Current work on command searching for help, see image

http://i.imgur.com/HQ6nmvF.png

@Default
@Subcommand("help")
@UnknownHandler
public void doHelp(CommandSender sender, CommandHelp help) {
     help.showHelp();
}
This commit is contained in:
Aikar
2017-08-23 23:54:59 -04:00
parent 0746f97ee1
commit ab192c9e34
9 changed files with 131 additions and 22 deletions
@@ -255,6 +255,7 @@ public abstract class BaseCommand {
for (String subcmd : cmdList) {
subCommands.put(subcmd, cmd);
}
cmd.addSubcommands(cmdList);
if (aliasNames != null) {
for (String name : aliasNames) {
@@ -148,15 +148,22 @@ public class CommandContexts <R extends CommandExecutionContext<?, ? extends Com
});
registerOptionalContext(CommandHelp.class, (c) -> {
String first = c.getFirstArg();
String last = c.getLastArg();
int page = 1;
List<String> search = null;
if (first != null && ACFUtil.isInteger(first)) {
if (last != null && ACFUtil.isInteger(last)) {
c.popLastArg();
page = ACFUtil.parseInt(last);
if (!c.getArgs().isEmpty()) {
search = c.getArgs();
}
} else if (first != null && ACFUtil.isInteger(first)) {
c.popFirstArg();
page = ACFUtil.parseInt(first);
if (!c.getArgs().isEmpty()) {
search = c.getArgs();
}
} else if (first != null && !c.getArgs().isEmpty()) {
} else if (!c.getArgs().isEmpty()) {
search = c.getArgs();
}
CommandHelp commandHelp = manager.generateCommandHelp();
@@ -70,10 +70,18 @@ public class CommandExecutionContext <T extends CommandExecutionContext, I exten
return !args.isEmpty() ? args.remove(0) : null;
}
public String popLastArg() {
return !args.isEmpty() ? args.remove(args.size() - 1) : null;
}
public String getFirstArg() {
return !args.isEmpty() ? args.get(0) : null;
}
public String getLastArg() {
return !args.isEmpty() ? args.get(args.size() - 1) : null;
}
public boolean isLastArg() {
return cmd.parameters.length -1 == index;
}
@@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@SuppressWarnings("WeakerAccess")
public class CommandHelp {
@@ -58,21 +59,38 @@ public class CommandHelp {
});
}
private boolean matchesSearch(HelpEntry help) {
if (this.search == null) {
return true;
@UnstableAPI // Not sure on this one yet even when API becomes unstable
protected void updateSearchScore(HelpEntry help) {
if (this.search == null || this.search.isEmpty()) {
help.setSearchScore(1);
return;
}
final RegisteredCommand cmd = help.getRegisteredCommand();
final RegisteredCommand<?> cmd = help.getRegisteredCommand();
int searchScore = 0;
for (String word : this.search) {
Pattern pattern = Pattern.compile(Pattern.quote(word));
if (pattern.matcher(cmd.command).matches()) {
return true;
} else if (pattern.matcher(help.getDescription()).matches()) {
return true;
Pattern pattern = Pattern.compile(".*" + Pattern.quote(word) + ".*", Pattern.CASE_INSENSITIVE);
for (String subCmd : cmd.registeredSubcommands) {
Pattern subCmdPattern = Pattern.compile(".*" + Pattern.quote(subCmd) + ".*", Pattern.CASE_INSENSITIVE);
if (pattern.matcher(subCmd).matches()) {
searchScore += 3;
} else if (subCmdPattern.matcher(word).matches()) {
searchScore++;
}
}
if (pattern.matcher(help.getDescription()).matches()) {
searchScore += 2;
}
if (pattern.matcher(help.getParameterSyntax()).matches()) {
searchScore++;
}
if (help.getSearchTags() != null && pattern.matcher(help.getSearchTags()).matches()) {
searchScore += 2;
}
}
return false;
help.setSearchScore(searchScore);
}
public CommandManager getManager() {
@@ -88,15 +106,21 @@ public class CommandHelp {
}
public void showHelp(CommandIssuer issuer, MessageKeyProvider format) {
getHelpEntries().forEach(e -> {
if (!matchesSearch(e)) {
return;
}
Iterator<HelpEntry> results = getHelpEntries().stream()
.filter(HelpEntry::shouldShow)
.sorted(Comparator.comparingInt(helpEntry -> helpEntry.getSearchScore() * -1)).iterator();
if (!results.hasNext()) {
issuer.sendMessage(MessageType.ERROR, MessageKeys.NO_COMMAND_MATCHED_SEARCH, "{search}", ACFUtil.join(this.search, " "));
results = getHelpEntries().iterator();
}
while (results.hasNext()) {
HelpEntry e = results.next();
String formatted = this.manager.formatMessage(issuer, MessageType.HELP, format, getFormatReplacements(e));
for (String msg : ACFPatterns.NEWLINE.split(formatted)) {
issuer.sendMessageInternal(ACFUtil.rtrim(msg));
}
});
}
}
/**
@@ -125,5 +149,6 @@ public class CommandHelp {
public void setSearch(List<String> search) {
this.search = search;
getHelpEntries().forEach(this::updateSearchScore);
}
}
@@ -23,12 +23,18 @@
package co.aikar.commands;
import co.aikar.commands.annotation.HelpSearchTags;
public class HelpEntry {
private final RegisteredCommand command;
private final String searchTags;
private int searchScore = 1;
HelpEntry(RegisteredCommand command) {
this.command = command;
HelpSearchTags tagsAnno = command.method.getAnnotation(HelpSearchTags.class);
this.searchTags = tagsAnno != null ? tagsAnno.value() : null;
}
RegisteredCommand getRegisteredCommand() {
@@ -47,4 +53,20 @@ public class HelpEntry {
public String getDescription(){
return this.command.helpText;
}
public void setSearchScore(int searchScore) {
this.searchScore = searchScore;
}
public boolean shouldShow() {
return this.searchScore > 0;
}
public int getSearchScore() {
return searchScore;
}
public String getSearchTags() {
return searchTags;
}
}
@@ -44,7 +44,8 @@ public enum MessageKeys implements MessageKeyProvider {
MUST_BE_MAX_LENGTH,
NOT_ALLOWED_ON_CONSOLE,
COULD_NOT_FIND_PLAYER,
HELP_FORMAT;
HELP_FORMAT,
NO_COMMAND_MATCHED_SEARCH;
private final MessageKey key = MessageKey.of("acf-core." + this.name().toLowerCase());
public MessageKey getMessageKey() {
@@ -27,6 +27,7 @@ import co.aikar.commands.annotation.*;
import co.aikar.commands.contexts.ContextResolver;
import co.aikar.commands.contexts.IssuerAwareContextResolver;
import co.aikar.commands.contexts.IssuerOnlyContextResolver;
import co.aikar.commands.contexts.OptionalContextResolver;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -35,6 +36,8 @@ import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -54,6 +57,7 @@ public class RegisteredCommand <R extends CommandExecutionContext<? extends Comm
final String complete;
final int requiredResolvers;
final int optionalResolvers;
final List<String> registeredSubcommands = new ArrayList<>();
RegisteredCommand(BaseCommand scope, String command, Method method, String prefSubCommand) {
this.scope = scope;
@@ -116,13 +120,14 @@ public class RegisteredCommand <R extends CommandExecutionContext<? extends Comm
}
private boolean isOptionalResolver(ContextResolver<?, R> resolver, Parameter parameter) {
return resolver instanceof IssuerAwareContextResolver || resolver instanceof IssuerOnlyContextResolver
return isOptionalResolver(resolver)
|| parameter.getAnnotation(Optional.class) != null
|| parameter.getAnnotation(Default.class) != null;
}
private boolean isSenderAwareResolver(ContextResolver<?, R> resolver) {
return resolver instanceof IssuerAwareContextResolver || resolver instanceof IssuerOnlyContextResolver;
private boolean isOptionalResolver(ContextResolver<?, R> resolver) {
return resolver instanceof IssuerAwareContextResolver || resolver instanceof IssuerOnlyContextResolver
|| resolver instanceof OptionalContextResolver;
}
void invoke(CommandIssuer sender, List<String> args) {
@@ -195,7 +200,7 @@ public class RegisteredCommand <R extends CommandExecutionContext<? extends Comm
if (allowOptional && def != null) {
args.add(scope.manager.getCommandReplacements().replace(def.value()));
} else if (allowOptional && opt != null) {
passedArgs.put(parameterName, isSenderAwareResolver(resolver) ? resolver.getContext(context) : null);
passedArgs.put(parameterName, isOptionalResolver(resolver) ? resolver.getContext(context) : null);
//noinspection UnnecessaryContinue
continue;
} else if (!isOptionalResolver) {
@@ -247,4 +252,11 @@ public class RegisteredCommand <R extends CommandExecutionContext<? extends Comm
public String getCommand() {
return command;
}
public void addSubcommand(String cmd) {
this.registeredSubcommands.add(cmd);
}
public void addSubcommands(Collection<String> cmd) {
this.registeredSubcommands.addAll(cmd);
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package co.aikar.commands.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface HelpSearchTags {
String value();
}
+1
View File
@@ -34,3 +34,4 @@ acf-core.must_be_max_length = Error: Must be less than {max} characters long.
acf-core.not_allowed_on_console = Error: Console may not execute this command.
acf-core.could_not_find_player = Error: Could not find a player by the name: <c2>{search}</c2>
acf-core.help_format = <c1>{command}</c1> <c2>{parameters}</c2> <c3>{seperator} {description}</c3>
acf-core.no_command_matched_search = No command matched <c2>{search}</c2>.