diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 163a1c5d..b70af4c1 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -1,6 +1,9 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java b/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java
index 98f195ac..8c0ce9d5 100644
--- a/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java
+++ b/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java
@@ -52,8 +52,9 @@ public class BukkitRootCommand extends Command implements RootCommand {
}
@Override
- public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
- return getTabCompletions(manager.getCommandIssuer(sender), alias, args);
+ public List tabComplete(CommandSender sender, String commandLabel, String[] args) throws IllegalArgumentException {
+ if (commandLabel.contains(":")) commandLabel = ACFPatterns.COLON.split(commandLabel, 2)[1];
+ return getTabCompletions(manager.getCommandIssuer(sender), commandLabel, args);
}
@Override
@@ -71,8 +72,6 @@ public class BukkitRootCommand extends Command implements RootCommand {
public void addChild(BaseCommand command) {
if (this.defCommand == null || !command.subCommands.get(BaseCommand.DEFAULT).isEmpty()) {
this.defCommand = command;
- //this.setDescription(command.getDescription());
- //this.setUsage(command.getUsage());
}
addChildShared(this.children, this.subCommands, command);
setPermission(getUniquePermission());
diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java
index 71b8b5aa..16572049 100644
--- a/core/src/main/java/co/aikar/commands/BaseCommand.java
+++ b/core/src/main/java/co/aikar/commands/BaseCommand.java
@@ -23,6 +23,7 @@
package co.aikar.commands;
+import co.aikar.commands.CommandRouter.RouteSearch;
import co.aikar.commands.annotation.CatchAll;
import co.aikar.commands.annotation.CatchUnknown;
import co.aikar.commands.annotation.CommandAlias;
@@ -50,7 +51,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;
@@ -67,7 +67,6 @@ import java.util.stream.Stream;
* then each actionable command is a sub command
*/
-@SuppressWarnings("unused")
public abstract class BaseCommand {
/**
@@ -310,7 +309,6 @@ public abstract class BaseCommand {
*/
private void registerSubcommands() {
final Annotations annotations = manager.getAnnotations();
- boolean foundDefault = false;
boolean foundCatchUnknown = false;
boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty();
@@ -318,22 +316,14 @@ public abstract class BaseCommand {
method.setAccessible(true);
String sublist = null;
String sub = getSubcommandValue(method);
- final boolean def = annotations.hasAnnotation(method, Default.class);
final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING);
final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING);
- if (!isParentEmpty && def) {
- sub = parentSubcommand;
- }
- if (isParentEmpty && (def || (!foundDefault && helpCommand != null))) {
- if (!foundDefault) {
- if (def) {
- this.subCommands.get(DEFAULT).clear();
- foundDefault = true;
- }
- registerSubcommand(method, DEFAULT);
+ if (annotations.hasAnnotation(method, Default.class)) {
+ if (!isParentEmpty) {
+ sub = parentSubcommand;
} else {
- ACFUtil.sneaky(new IllegalStateException("Multiple @Default/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName()));
+ registerSubcommand(method, DEFAULT);
}
}
@@ -359,7 +349,7 @@ public abstract class BaseCommand {
}
registerSubcommand(method, CATCHUNKNOWN);
} else {
- ACFUtil.sneaky(new IllegalStateException("Multiple @UnknownHandler/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName()));
+ ACFUtil.sneaky(new IllegalStateException("Multiple @CatchUnknown/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName()));
}
} else if (preCommand) {
if (this.preCommandHandler == null) {
@@ -506,48 +496,16 @@ public abstract class BaseCommand {
}
}
- public void execute(CommandIssuer issuer, String commandLabel, String[] args) {
- commandLabel = commandLabel.toLowerCase();
+ void execute(CommandIssuer issuer, CommandRouter.CommandRouteResult command) {
try {
- CommandOperationContext commandContext = preCommandOperation(issuer, commandLabel, args, false);
-
- if (args.length > 0) {
- CommandSearch cmd = findSubCommand(args);
- if (cmd != null) {
- execSubcommand = cmd.getCheckSub();
- final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length);
- executeCommand(commandContext, issuer, execargs, cmd.cmd);
- return;
- }
- }
-
- Set defaultCommands = subCommands.get(DEFAULT);
- RegisteredCommand defCommand = ACFUtil.getFirstElement(defaultCommands);
- if (defCommand != null && (args.length == 0 || defCommand.consumeInputResolvers > 0)) {
- findAndExecuteCommand(commandContext, DEFAULT, issuer, args);
- } else if (subCommands.get(CATCHUNKNOWN) != null) {
- if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) {
- help(issuer, args);
- }
- }
-
+ CommandOperationContext commandContext = preCommandOperation(issuer, command.commandLabel, command.args, false);
+ execSubcommand = command.subcommand;
+ executeCommand(commandContext, issuer, command.args, command.cmd);
} finally {
postCommandOperation();
}
}
- /**
- * Gets the registered command of the given arguments.
- *
- * @param args The arguments given by the user.
- * @return The subcommand or null if none were found.
- * @see #findSubCommand(String[])
- */
- RegisteredCommand> getRegisteredCommand(String[] args) {
- final CommandSearch cmd = findSubCommand(args);
- return cmd != null ? cmd.cmd : null;
- }
-
/**
* This is ran after any command operation has been performed.
*/
@@ -598,60 +556,6 @@ public abstract class BaseCommand {
return CommandManager.getCurrentCommandManager();
}
- /**
- * Finds a subcommand of the given arguments.
- *
- * @param args The arguments the user input.
- * @return The identified subcommand.
- * @see #findSubCommand(String[], boolean)
- */
- private CommandSearch findSubCommand(String[] args) {
- return findSubCommand(args, false);
- }
-
- /**
- * Finds a subcommand of the given arguments.
- *
- * @param args The arguments the user input.
- * @param completion Whether or not completion of arguments should kick in. This may end up with worse than wanted results.
- * @return The identified subcommand.
- */
- private CommandSearch findSubCommand(String[] args, boolean completion) {
- for (int i = args.length; i >= 0; i--) {
- String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase();
- Set cmds = subCommands.get(checkSub);
-
- final int extraArgs = args.length - i;
- if (!cmds.isEmpty()) {
- RegisteredCommand cmd = null;
- if (cmds.size() == 1) {
- cmd = ACFUtil.getFirstElement(cmds);
- } else {
- Optional optCmd = cmds.stream().filter(c -> {
- int required = c.requiredResolvers;
- int optional = c.optionalResolvers;
- return extraArgs <= required + optional && (completion || extraArgs >= required);
- }).min((c1, c2) -> {
- int a = c1.consumeInputResolvers;
- int b = c2.consumeInputResolvers;
-
- if (a == b) {
- return 0;
- }
- return a < b ? 1 : -1;
- });
- if (optCmd.isPresent()) {
- cmd = optCmd.get();
- }
- }
- if (cmd != null) {
- return new CommandSearch(cmd, i, checkSub);
- }
- }
- }
- return null;
- }
-
private void executeCommand(CommandOperationContext commandOperationContext,
CommandIssuer issuer, String[] args, RegisteredCommand cmd) {
if (cmd.hasPermission(issuer)) {
@@ -711,19 +615,17 @@ public abstract class BaseCommand {
args = new String[]{""};
}
try {
- CommandOperationContext commandOperationContext = preCommandOperation(issuer, commandLabel, args, isAsync);
-
- final CommandSearch search = findSubCommand(args, true);
+ CommandRouter router = manager.getRouter();
+ preCommandOperation(issuer, commandLabel, args, isAsync);
+ final RouteSearch search = router.routeCommand(commandLabel, args, true);
final List cmds = new ArrayList<>();
-
if (search != null) {
- cmds.addAll(completeCommand(issuer, search.cmd, Arrays.copyOfRange(args, search.argIndex, args.length), commandLabel, isAsync));
- } else if (subCommands.get(CATCHUNKNOWN).size() == 1) {
- cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(CATCHUNKNOWN)), args, commandLabel, isAsync));
- } else if (subCommands.get(DEFAULT).size() == 1) {
- cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(DEFAULT)), args, commandLabel, isAsync));
+ CommandRouter.CommandRouteResult result = router.matchCommand(search, true);
+ if (result != null) {
+ cmds.addAll(completeCommand(issuer, result.cmd, result.args, commandLabel, isAsync));
+ }
}
return filterTabComplete(args[args.length - 1], cmds);
@@ -792,55 +694,6 @@ public abstract class BaseCommand {
.collect(Collectors.toList());
}
- /**
- * Gets a registered command under the given subcommand name.
- *
- * @param subcommand The name of the subcommand requested.
- * @return The subcommand found or null if none.
- */
- private RegisteredCommand getCommandBySubcommand(String subcommand) {
- return getCommandBySubcommand(subcommand, false);
- }
-
- /**
- * Gets a registered command under the given name.
- * If requireOne is true, it won't accept more than a single matching subcommand.
- *
- * @param subcommand Name of the subcommand wanted.
- * @param requireOne Whether to only accept 1 result.
- * @return The subcommand found, or null if none/too many.
- */
- private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) {
- final Set commands = subCommands.get(subcommand);
- if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) {
- return commands.iterator().next();
- }
- return null;
- }
-
- /**
- * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)}
- * and gets through {@link #getCommandBySubcommand(String)}.
- *
- * @param commandContext The command context to use.
- * @param subcommand The subcommand to find the executor of.
- * @param issuer The issuer who executed the subcommand.
- * @param args All arguments given by the issuer.
- * @return Whether it found a command or not.
- * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)
- * @see #getCommandBySubcommand(String)
- * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext)
- */
- private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) {
- final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand);
- if (cmd != null) {
- executeCommand(commandContext, issuer, args, cmd);
- return true;
- }
-
- return false;
- }
-
/**
* Executes the precommand and sees whether something is wrong. Ideally, you get false from this.
*
@@ -951,7 +804,7 @@ public abstract class BaseCommand {
}
public RegisteredCommand getDefaultRegisteredCommand() {
- return this.getCommandBySubcommand(DEFAULT);
+ return ACFUtil.getFirstElement(this.subCommands.get(DEFAULT));
}
public String setContextFlags(Class> cls, String flags) {
@@ -967,35 +820,4 @@ public abstract class BaseCommand {
registeredCommands.addAll(this.subCommands.values());
return registeredCommands;
}
-
- private static class CommandSearch {
- RegisteredCommand cmd;
- int argIndex;
- String checkSub;
-
- CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) {
- this.cmd = cmd;
- this.argIndex = argIndex;
- this.checkSub = checkSub;
- }
-
- String getCheckSub() {
- return this.checkSub;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- CommandSearch that = (CommandSearch) o;
- return argIndex == that.argIndex &&
- Objects.equals(cmd, that.cmd) &&
- Objects.equals(checkSub, that.checkSub);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(cmd, argIndex, checkSub);
- }
- }
}
diff --git a/core/src/main/java/co/aikar/commands/CommandContexts.java b/core/src/main/java/co/aikar/commands/CommandContexts.java
index 48ac63f9..895f15e1 100644
--- a/core/src/main/java/co/aikar/commands/CommandContexts.java
+++ b/core/src/main/java/co/aikar/commands/CommandContexts.java
@@ -177,8 +177,6 @@ public class CommandContexts {
String val;
- // Go home IDEA, you're drunk
- //noinspection unchecked
List args = c.getArgs();
if (c.isLastArg() && !c.hasAnnotation(Single.class)) {
val = ACFUtil.join(args);
@@ -195,7 +193,7 @@ public class CommandContexts {
private final RegisteredCommand cmd;
private final CommandParameter param;
diff --git a/core/src/main/java/co/aikar/commands/CommandHelp.java b/core/src/main/java/co/aikar/commands/CommandHelp.java
index 693c12e8..8cd85328 100644
--- a/core/src/main/java/co/aikar/commands/CommandHelp.java
+++ b/core/src/main/java/co/aikar/commands/CommandHelp.java
@@ -43,7 +43,7 @@ public class CommandHelp {
private int page;
private int perPage;
List search;
- private HelpEntry selectedEntry;
+ private Set selectedEntry = new HashSet<>();
private int totalResults;
private int totalPages;
private boolean lastPage;
@@ -117,14 +117,14 @@ public class CommandHelp {
return manager;
}
- public boolean isExactMatch(String command) {
+ public boolean testExactMatch(String command) {
+ selectedEntry.clear();
for (HelpEntry helpEntry : helpEntries) {
if (helpEntry.getCommand().endsWith(" " + command)) {
- selectedEntry = helpEntry;
- return true;
+ selectedEntry.add(helpEntry);
}
}
- return false;
+ return !selectedEntry.isEmpty();
}
public void showHelp() {
@@ -133,8 +133,15 @@ public class CommandHelp {
public void showHelp(CommandIssuer issuer) {
CommandHelpFormatter formatter = manager.getHelpFormatter();
- if (selectedEntry != null) {
- formatter.showDetailedHelp(this, selectedEntry);
+ if (!selectedEntry.isEmpty()) {
+ HelpEntry first = ACFUtil.getFirstElement(selectedEntry);
+ formatter.printDetailedHelpHeader(this, issuer, first);
+
+ for (HelpEntry helpEntry : selectedEntry) {
+ formatter.showDetailedHelp(this, helpEntry);
+ }
+
+ formatter.printDetailedHelpFooter(this, issuer, first);
return;
}
@@ -224,7 +231,7 @@ public class CommandHelp {
return search;
}
- public HelpEntry getSelectedEntry() {
+ public Set getSelectedEntry() {
return selectedEntry;
}
diff --git a/core/src/main/java/co/aikar/commands/CommandHelpFormatter.java b/core/src/main/java/co/aikar/commands/CommandHelpFormatter.java
index 49906f6a..4ac1f883 100644
--- a/core/src/main/java/co/aikar/commands/CommandHelpFormatter.java
+++ b/core/src/main/java/co/aikar/commands/CommandHelpFormatter.java
@@ -56,8 +56,6 @@ public class CommandHelpFormatter {
public void showDetailedHelp(CommandHelp commandHelp, HelpEntry entry) {
CommandIssuer issuer = commandHelp.getIssuer();
- // header
- printDetailedHelpHeader(commandHelp, issuer, entry);
// normal help line
printDetailedHelpCommand(commandHelp, issuer, entry);
@@ -69,9 +67,6 @@ public class CommandHelpFormatter {
printDetailedParameter(commandHelp, issuer, entry, param);
}
}
-
- // footer
- printDetailedHelpFooter(commandHelp, issuer, entry);
}
// ########
diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java
index 6386b499..f82b0cb8 100644
--- a/core/src/main/java/co/aikar/commands/CommandManager.java
+++ b/core/src/main/java/co/aikar/commands/CommandManager.java
@@ -86,6 +86,7 @@ public abstract class CommandManager <
private Set unstableAPIs = new HashSet<>();
private Annotations annotations = new Annotations<>(this);
+ private CommandRouter router = new CommandRouter(this);
public static CommandOperationContext getCurrentCommandOperationContext() {
return commandOperationContext.get().peek();
@@ -199,6 +200,10 @@ public abstract class CommandManager <
return helpFormatter;
}
+ CommandRouter getRouter() {
+ return router;
+ }
+
/**
* Registers a command with ACF
*
@@ -270,14 +275,6 @@ public abstract class CommandManager <
return true;
}
- BaseCommand getBaseCommand(String commandLabel, @NotNull String[] args) {
- RootCommand rootCommand = obtainRootCommand(commandLabel);
- if (rootCommand == null) {
- return null;
- }
- return rootCommand.getBaseCommand(args);
- }
-
public synchronized RootCommand getRootCommand(@NotNull String cmd) {
return rootCommands.get(ACFPatterns.SPACE.split(cmd.toLowerCase(), 2)[0]);
}
diff --git a/core/src/main/java/co/aikar/commands/CommandParameter.java b/core/src/main/java/co/aikar/commands/CommandParameter.java
index 029ff776..f13bcb51 100644
--- a/core/src/main/java/co/aikar/commands/CommandParameter.java
+++ b/core/src/main/java/co/aikar/commands/CommandParameter.java
@@ -28,6 +28,7 @@ import co.aikar.commands.annotation.Default;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Flags;
import co.aikar.commands.annotation.Optional;
+import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Syntax;
import co.aikar.commands.annotation.Values;
import co.aikar.commands.contexts.ContextResolver;
@@ -58,12 +59,12 @@ public class CommandParameter flags;
private boolean canConsumeInput;
private boolean optionalResolver;
+ boolean consumesRest;
- public CommandParameter(RegisteredCommand command, Parameter param, int paramIndex) {
+ public CommandParameter(RegisteredCommand command, Parameter param, int paramIndex, boolean isLast) {
this.parameter = param;
this.type = param.getType();
this.name = param.getName(); // do we care for an annotation to supply name?
- //noinspection unchecked
this.manager = command.manager;
this.paramIndex = paramIndex;
Annotations annotations = manager.getAnnotations();
@@ -80,12 +81,13 @@ public class CommandParameter cmds = search.commands;
+ String[] args = search.args;
+ if (!cmds.isEmpty()) {
+ if (cmds.size() == 1) {
+ return new CommandRouteResult(ACFUtil.getFirstElement(cmds), search);
+ } else {
+ Optional optCmd = cmds.stream()
+ .filter(c -> isProbableMatch(c, args, completion))
+ .min((c1, c2) -> {
+ int a = c1.consumeInputResolvers;
+ int b = c2.consumeInputResolvers;
+
+ if (a == b) {
+ return 0;
+ }
+ return a < b ? 1 : -1;
+ });
+ if (optCmd.isPresent()) {
+ return new CommandRouteResult(optCmd.get(), search);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param c
+ * @param args
+ * @param completion
+ * @return
+ * @TODO: Improve this to be more accurate like @Default handling.
+ */
+ private boolean isProbableMatch(RegisteredCommand c, String[] args, boolean completion) {
+ int required = c.requiredResolvers;
+ int optional = c.optionalResolvers;
+ return args.length <= required + optional && (completion || args.length >= required);
+ }
+
+ RouteSearch routeCommand(RootCommand command, String commandLabel, String[] args, boolean completion) {
+ SetMultimap subCommands = command.getSubCommands();
+ int argLength = args.length;
+ for (int i = argLength; i >= 0; i--) {
+ String subcommand = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase();
+ Set cmds = subCommands.get(subcommand);
+
+ if (!cmds.isEmpty()) {
+ return new RouteSearch(cmds, Arrays.copyOfRange(args, i, argLength), commandLabel, subcommand, completion);
+ }
+ }
+
+ Set defaultCommands = subCommands.get(DEFAULT);
+ Set unknownCommands = subCommands.get(CATCHUNKNOWN);
+ if (!defaultCommands.isEmpty()) {
+ Set matchedDefault = new HashSet<>();
+ for (RegisteredCommand c : defaultCommands) {
+ int required = c.requiredResolvers;
+ int optional = c.optionalResolvers;
+ CommandParameter lastParam = c.parameters.length > 0 ? c.parameters[c.parameters.length - 1] : null;
+ if (argLength <= required + optional || (
+ lastParam != null && (
+ lastParam.getType() == String[].class
+ ||
+ (argLength >= required && lastParam.consumesRest)
+ )
+ )) {
+ matchedDefault.add(c);
+ }
+ }
+ if (!matchedDefault.isEmpty()) {
+ return new RouteSearch(matchedDefault, args, commandLabel, null, completion);
+ }
+ }
+
+ if (!unknownCommands.isEmpty()) {
+ return new RouteSearch(unknownCommands, args, commandLabel, null, completion);
+ }
+
+ return null;
+ }
+
+ RouteSearch routeCommand(String commandLabel, String[] args, boolean completion) {
+ return routeCommand(manager.getRootCommand(commandLabel), commandLabel, args, completion);
+ }
+
+
+ static class CommandRouteResult {
+ final RegisteredCommand cmd;
+ final String[] args;
+ final String commandLabel;
+ final String subcommand;
+
+ CommandRouteResult(RegisteredCommand cmd, RouteSearch search) {
+ this(cmd, search.args, search.subcommand, search.commandLabel);
+ }
+
+ CommandRouteResult(CommandRouteResult result, String[] args) {
+ this(result.cmd, args, result.subcommand, result.commandLabel);
+ }
+
+ CommandRouteResult(RegisteredCommand cmd, String[] args, String subcommand, String commandLabel) {
+ this.cmd = cmd;
+ this.args = args;
+ this.commandLabel = commandLabel;
+ this.subcommand = subcommand;
+ }
+
+ }
+
+ static class RouteSearch {
+ final String[] args;
+ final Set commands;
+ final String commandLabel;
+ final String subcommand;
+
+ RouteSearch(Set commands, String[] args, String commandLabel, String subcommand, boolean completion) {
+ this.commands = commands;
+ this.args = args;
+ this.commandLabel = commandLabel.toLowerCase();
+ this.subcommand = subcommand;
+ }
+ }
+
+}
diff --git a/core/src/main/java/co/aikar/commands/ForwardingCommand.java b/core/src/main/java/co/aikar/commands/ForwardingCommand.java
index 3045c4eb..6274c791 100644
--- a/core/src/main/java/co/aikar/commands/ForwardingCommand.java
+++ b/core/src/main/java/co/aikar/commands/ForwardingCommand.java
@@ -78,8 +78,9 @@ public class ForwardingCommand extends BaseCommand {
}
@Override
- public void execute(CommandIssuer issuer, String commandLabel, String[] args) {
- command.execute(issuer, commandLabel, ApacheCommonsLangUtil.addAll(baseArgs, args));
+ public void execute(CommandIssuer issuer, CommandRouter.CommandRouteResult result) {
+ result = new CommandRouter.CommandRouteResult(result, ApacheCommonsLangUtil.addAll(baseArgs, result.args));
+ command.execute(issuer, result);
}
BaseCommand getCommand() {
diff --git a/core/src/main/java/co/aikar/commands/RegisteredCommand.java b/core/src/main/java/co/aikar/commands/RegisteredCommand.java
index 0030402d..9c519f51 100644
--- a/core/src/main/java/co/aikar/commands/RegisteredCommand.java
+++ b/core/src/main/java/co/aikar/commands/RegisteredCommand.java
@@ -106,7 +106,7 @@ public class RegisteredCommand parameter = this.parameters[i] = new CommandParameter<>(this, parameters[i], i);
+ CommandParameter parameter = this.parameters[i] = new CommandParameter<>(this, parameters[i], i, i == parameters.length - 1);
if (!parameter.isCommandIssuer()) {
if (!parameter.requiresInput()) {
optionalResolvers++;
diff --git a/core/src/main/java/co/aikar/commands/RootCommand.java b/core/src/main/java/co/aikar/commands/RootCommand.java
index 39234124..962738ce 100644
--- a/core/src/main/java/co/aikar/commands/RootCommand.java
+++ b/core/src/main/java/co/aikar/commands/RootCommand.java
@@ -23,7 +23,8 @@
package co.aikar.commands;
-import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;
+import co.aikar.commands.CommandRouter.CommandRouteResult;
+import co.aikar.commands.CommandRouter.RouteSearch;
import com.google.common.collect.SetMultimap;
import java.util.ArrayList;
@@ -31,9 +32,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import static co.aikar.commands.BaseCommand.CATCHUNKNOWN;
-import static co.aikar.commands.BaseCommand.DEFAULT;
-
public interface RootCommand {
void addChild(BaseCommand command);
@@ -47,21 +45,7 @@ public interface RootCommand {
default void addChildShared(List children, SetMultimap subCommands, BaseCommand command) {
command.subCommands.entries().forEach(e -> {
- String key = e.getKey();
- RegisteredCommand registeredCommand = e.getValue();
- if (key.equals(DEFAULT) || key.equals(BaseCommand.CATCHUNKNOWN)) {
- return;
- }
- Set registered = subCommands.get(key);
- if (!registered.isEmpty()) {
- BaseCommand prevBase = registered.iterator().next().scope;
- if (prevBase != registeredCommand.scope) {
- this.getManager().log(LogLevel.ERROR, "ACF Error: " + command.getName() + " registered subcommand " + key + " for root command " + getCommandName() + " - but it is already defined in " + prevBase.getName());
- this.getManager().log(LogLevel.ERROR, "2 subcommands of the same prefix may not be spread over 2 different classes. Ignoring this.");
- return;
- }
- }
- subCommands.put(key, registeredCommand);
+ subCommands.put(e.getKey(), e.getValue());
});
children.add(command);
@@ -105,35 +89,25 @@ public interface RootCommand {
}
default BaseCommand execute(CommandIssuer sender, String commandLabel, String[] args) {
- BaseCommand command = getBaseCommand(args);
+ CommandRouter router = getManager().getRouter();
+ RouteSearch search = router.routeCommand(this, commandLabel, args, false);
+ BaseCommand defCommand = getDefCommand();
+ if (search != null) {
+ CommandRouteResult result = router.matchCommand(search, false);
+ if (result != null) {
+ BaseCommand scope = result.cmd.scope;
+ scope.execute(sender, result);
+ return scope;
+ }
- command.execute(sender, commandLabel, args);
- return command;
- }
-
- default BaseCommand getBaseCommand(String[] args) {
- SetMultimap subCommands = getSubCommands();
- RegisteredCommand command;
- for (int i = args.length; i >= 0; i--) {
- String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase();
- command = ACFUtil.getFirstElement(subCommands.get(checkSub));
- if (command != null) {
- return command.scope;
+ RegisteredCommand firstElement = ACFUtil.getFirstElement(search.commands);
+ if (firstElement != null) {
+ defCommand = firstElement.scope;
}
}
- command = ACFUtil.getFirstElement(subCommands.get(DEFAULT));
- if (command != null) {
- if (args.length == 0 || command.consumeInputResolvers > 0) {
- return command.scope;
- }
- }
-
- command = ACFUtil.getFirstElement(subCommands.get(CATCHUNKNOWN));
- if (command != null) {
- return command.scope;
- }
- return getDefCommand();
+ defCommand.help(sender, args);
+ return defCommand;
}
default List getTabCompletions(CommandIssuer sender, String alias, String[] args) {
diff --git a/example/src/main/java/co/aikar/acfexample/SomeOtherCommand.java b/example/src/main/java/co/aikar/acfexample/SomeOtherCommand.java
index 56d93bdb..86f386a6 100644
--- a/example/src/main/java/co/aikar/acfexample/SomeOtherCommand.java
+++ b/example/src/main/java/co/aikar/acfexample/SomeOtherCommand.java
@@ -1,9 +1,11 @@
package co.aikar.acfexample;
import co.aikar.commands.BaseCommand;
+import co.aikar.commands.CommandHelp;
import co.aikar.commands.annotation.CatchUnknown;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.Default;
+import co.aikar.commands.annotation.HelpCommand;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import org.bukkit.command.CommandSender;
@@ -31,4 +33,9 @@ public class SomeOtherCommand extends BaseCommand {
public void test(Player player, String string, @Default("1") int integer) {
player.sendMessage("Hi " + string + " - " + integer);
}
+
+ @HelpCommand
+ public void onHelp(CommandSender sender, CommandHelp help) {
+ help.showHelp();
+ }
}