diff --git a/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html b/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html index efd720db..3d127ab6 100644 --- a/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html +++ b/docs/acf-bukkit/src-html/co/aikar/commands/BukkitCommandManager.html @@ -291,7 +291,7 @@ 283 } 284 Object nmsPlayer = entityField.get(player); 285 if (nmsPlayer != null) { -286 Field localeField = nmsPlayer.getClass().getField("locale"); +286 Field localeField = nmsPlayer.getClass().getDeclaredField("locale"); 287 Object localeString = localeField.get(nmsPlayer); 288 if (localeString instanceof String) { 289 String[] split = ACFPatterns.UNDERSCORE.split((String) localeString); diff --git a/docs/acf-core/co/aikar/commands/BaseCommand.html b/docs/acf-core/co/aikar/commands/BaseCommand.html index d311bc91..dfc9e000 100644 --- a/docs/acf-core/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/co/aikar/commands/BaseCommand.html @@ -346,7 +346,7 @@ extends
  • BaseCommand

    -
    public BaseCommand()
    +
    public BaseCommand()
  • @@ -356,7 +356,7 @@ extends

    BaseCommand

    @Deprecated
    -public BaseCommand(@Nullable
    +public BaseCommand(@Nullable
                                    @Nullable String cmd)
    Deprecated. Please switch to CommandAlias for defining all root commands.
    Constructor based defining of commands will be removed in the next version bump.
    @@ -380,7 +380,7 @@ public 
  • getLastCommandOperationContext

    -
    public CommandOperationContext getLastCommandOperationContext()
    +
    public CommandOperationContext getLastCommandOperationContext()
    Returns a reference to the last used CommandOperationContext. This method is ThreadLocal, in that it can only be used on a thread that has executed a command
    @@ -394,7 +394,7 @@ public 
  • getExecCommandLabel

    -
    public String getExecCommandLabel()
    +
    public String getExecCommandLabel()
    Gets the root command name that the user actually typed
    Returns:
    @@ -408,7 +408,7 @@ public 
  • getExecSubcommand

    -
    public String getExecSubcommand()
    +
    public String getExecSubcommand()
    Gets the actual sub command name the user typed
    Returns:
    @@ -422,7 +422,7 @@ public 
  • getOrigArgs

    -
    public String[] getOrigArgs()
    +
    public String[] getOrigArgs()
    Gets the actual args in string form the user typed
    Returns:
    @@ -436,7 +436,7 @@ public 
  • execute

    -
    public void execute(CommandIssuer issuer,
    +
    public void execute(CommandIssuer issuer,
                         String commandLabel,
                         String[] args)
  • @@ -447,7 +447,7 @@ public 
  • getCurrentCommandIssuer

    -
    public CommandIssuer getCurrentCommandIssuer()
    +
    public CommandIssuer getCurrentCommandIssuer()
    Gets the current command issuer.
    Returns:
    @@ -461,7 +461,7 @@ public 
  • getCurrentCommandManager

    -
    public CommandManager getCurrentCommandManager()
    +
    public CommandManager getCurrentCommandManager()
    Gets the current command manager.
    Returns:
    @@ -476,7 +476,7 @@ public 

    canExecute

    @Deprecated
    -public boolean canExecute(CommandIssuer issuer,
    +public boolean canExecute(CommandIssuer issuer,
                                           RegisteredCommand<?> cmd)
    Deprecated. See CommandConditions
    Please use command conditions for restricting execution
    @@ -494,7 +494,7 @@ public boolean 
  • tabComplete

    -
    public List<StringtabComplete(CommandIssuer issuer,
    +
    public List<StringtabComplete(CommandIssuer issuer,
                                     String commandLabel,
                                     String[] args)
    Gets tab completed data from the given command from the user.
    @@ -514,7 +514,7 @@ public boolean 
  • tabComplete

    -
    public List<StringtabComplete(CommandIssuer issuer,
    +
    public List<StringtabComplete(CommandIssuer issuer,
                                     String commandLabel,
                                     String[] args,
                                     boolean isAsync)
    @@ -541,7 +541,7 @@ public boolean 
     

    getCommandHelp

    @Deprecated
    -public CommandHelp getCommandHelp()
    +public CommandHelp getCommandHelp()
    Deprecated. Unstable API
  • @@ -552,7 +552,7 @@ public 

    showCommandHelp

    @Deprecated
    -public void showCommandHelp()
    +public void showCommandHelp()
    Deprecated. Unstable API
  • @@ -562,7 +562,7 @@ public void 
  • help

    -
    public void help(Object issuer,
    +
    public void help(Object issuer,
                      String[] args)
  • @@ -572,7 +572,7 @@ public void 
  • help

    -
    public void help(CommandIssuer issuer,
    +
    public void help(CommandIssuer issuer,
                      String[] args)
  • @@ -582,7 +582,7 @@ public void 
  • doHelp

    -
    public void doHelp(Object issuer,
    +
    public void doHelp(Object issuer,
                        String... args)
  • @@ -592,7 +592,7 @@ public void 
  • doHelp

    -
    public void doHelp(CommandIssuer issuer,
    +
    public void doHelp(CommandIssuer issuer,
                        String... args)
  • @@ -602,7 +602,7 @@ public void 
  • showSyntax

    -
    public void showSyntax(CommandIssuer issuer,
    +
    public void showSyntax(CommandIssuer issuer,
                            RegisteredCommand<?> cmd)
  • @@ -612,7 +612,7 @@ public void 
  • hasPermission

    -
    public boolean hasPermission(Object issuer)
    +
    public boolean hasPermission(Object issuer)
  • @@ -621,7 +621,7 @@ public void 
  • hasPermission

    -
    public boolean hasPermission(CommandIssuer issuer)
    +
    public boolean hasPermission(CommandIssuer issuer)
  • @@ -630,7 +630,7 @@ public void 
  • getRequiredPermissions

    -
    public Set<StringgetRequiredPermissions()
    +
    public Set<StringgetRequiredPermissions()
  • @@ -639,7 +639,7 @@ public void 
  • requiresPermission

    -
    public boolean requiresPermission(String permission)
    +
    public boolean requiresPermission(String permission)
  • @@ -648,7 +648,7 @@ public void 
  • getName

    -
    public String getName()
    +
    public String getName()
  • @@ -657,7 +657,7 @@ public void 
  • getExceptionHandler

    -
    public ExceptionHandler getExceptionHandler()
    +
    public ExceptionHandler getExceptionHandler()
  • @@ -666,7 +666,7 @@ public void 
  • setExceptionHandler

    -
    public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler)
    +
    public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler)
  • @@ -675,7 +675,7 @@ public void 
  • getDefaultRegisteredCommand

    -
    public RegisteredCommand getDefaultRegisteredCommand()
    +
    public RegisteredCommand getDefaultRegisteredCommand()
  • @@ -684,7 +684,7 @@ public void 
  • setContextFlags

    -
    public String setContextFlags(Class<?> cls,
    +
    public String setContextFlags(Class<?> cls,
                                   String flags)
  • @@ -694,7 +694,7 @@ public void 
  • getContextFlags

    -
    public String getContextFlags(Class<?> cls)
    +
    public String getContextFlags(Class<?> cls)
  • @@ -703,7 +703,7 @@ public void 
  • getRegisteredCommands

    -
    public List<RegisteredCommandgetRegisteredCommands()
    +
    public List<RegisteredCommandgetRegisteredCommands()
  • diff --git a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html index d118104f..eb273ec4 100644 --- a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html @@ -168,836 +168,847 @@ 160 @Nullable 161 private String parentSubcommand; 162 -163 public BaseCommand() { -164 } -165 -166 /** -167 * Constructor based defining of commands will be removed in the next version bump. -168 * -169 * @param cmd -170 * @deprecated Please switch to {@link CommandAlias} for defining all root commands. -171 */ -172 @Deprecated -173 public BaseCommand(@Nullable String cmd) { -174 this.commandName = cmd; -175 } -176 -177 /** -178 * Returns a reference to the last used CommandOperationContext. -179 * This method is ThreadLocal, in that it can only be used on a thread that has executed a command -180 * -181 * @return -182 */ -183 public CommandOperationContext getLastCommandOperationContext() { -184 return lastCommandOperationContext.get(); -185 } -186 -187 /** -188 * Gets the root command name that the user actually typed -189 * -190 * @return Name -191 */ -192 public String getExecCommandLabel() { -193 return execLabel; -194 } -195 -196 /** -197 * Gets the actual sub command name the user typed -198 * -199 * @return Name -200 */ -201 public String getExecSubcommand() { -202 return execSubcommand; -203 } -204 -205 /** -206 * Gets the actual args in string form the user typed -207 * -208 * @return Args -209 */ -210 public String[] getOrigArgs() { -211 return origArgs; -212 } -213 -214 /** -215 * This should be called whenever the command gets registered. -216 * It sets all required fields correctly and injects dependencies. -217 * -218 * @param manager The manager to register as this command's owner and handler. -219 */ -220 void onRegister(CommandManager manager) { -221 onRegister(manager, this.commandName); -222 } -223 -224 /** -225 * This should be called whenever the command gets registered. -226 * It sets all required fields correctly and injects dependencies. -227 * -228 * @param manager The manager to register as this command's owner and handler. -229 * @param cmd The command name to use register with. -230 */ -231 private void onRegister(CommandManager manager, String cmd) { -232 manager.injectDependencies(this); -233 this.manager = manager; -234 -235 final Annotations annotations = manager.getAnnotations(); -236 final Class<? extends BaseCommand> self = this.getClass(); -237 -238 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); +163 /** +164 * The permissions of the command. +165 */ +166 private final Set<String> permissions = new HashSet<>(); +167 +168 public BaseCommand() { +169 } +170 +171 /** +172 * Constructor based defining of commands will be removed in the next version bump. +173 * +174 * @param cmd +175 * @deprecated Please switch to {@link CommandAlias} for defining all root commands. +176 */ +177 @Deprecated +178 public BaseCommand(@Nullable String cmd) { +179 this.commandName = cmd; +180 } +181 +182 /** +183 * Returns a reference to the last used CommandOperationContext. +184 * This method is ThreadLocal, in that it can only be used on a thread that has executed a command +185 * +186 * @return +187 */ +188 public CommandOperationContext getLastCommandOperationContext() { +189 return lastCommandOperationContext.get(); +190 } +191 +192 /** +193 * Gets the root command name that the user actually typed +194 * +195 * @return Name +196 */ +197 public String getExecCommandLabel() { +198 return execLabel; +199 } +200 +201 /** +202 * Gets the actual sub command name the user typed +203 * +204 * @return Name +205 */ +206 public String getExecSubcommand() { +207 return execSubcommand; +208 } +209 +210 /** +211 * Gets the actual args in string form the user typed +212 * +213 * @return Args +214 */ +215 public String[] getOrigArgs() { +216 return origArgs; +217 } +218 +219 /** +220 * This should be called whenever the command gets registered. +221 * It sets all required fields correctly and injects dependencies. +222 * +223 * @param manager The manager to register as this command's owner and handler. +224 */ +225 void onRegister(CommandManager manager) { +226 onRegister(manager, this.commandName); +227 } +228 +229 /** +230 * This should be called whenever the command gets registered. +231 * It sets all required fields correctly and injects dependencies. +232 * +233 * @param manager The manager to register as this command's owner and handler. +234 * @param cmd The command name to use register with. +235 */ +236 private void onRegister(CommandManager manager, String cmd) { +237 manager.injectDependencies(this); +238 this.manager = manager; 239 -240 if (cmd == null && cmdAliases != null) { -241 cmd = cmdAliases[0]; -242 } -243 -244 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); -245 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); -246 this.description = this.commandName + " commands"; -247 this.parentSubcommand = getParentSubcommand(self); -248 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -249 -250 registerSubcommands(); -251 registerSubclasses(cmd); -252 -253 if (cmdAliases != null) { -254 Set<String> cmdList = new HashSet<>(); -255 Collections.addAll(cmdList, cmdAliases); -256 cmdList.remove(cmd); -257 for (String cmdAlias : cmdList) { -258 register(cmdAlias, this); -259 } -260 } -261 -262 if (cmd != null) { -263 register(cmd, this); -264 } -265 } -266 -267 /** -268 * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. -269 * -270 * @param cmd The command name of this command. -271 */ -272 private void registerSubclasses(String cmd) { -273 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { -274 if (BaseCommand.class.isAssignableFrom(clazz)) { -275 try { -276 BaseCommand subCommand = null; -277 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); -278 for (Constructor<?> declaredConstructor : declaredConstructors) { -279 -280 declaredConstructor.setAccessible(true); -281 Parameter[] parameters = declaredConstructor.getParameters(); -282 if (parameters.length == 1) { -283 subCommand = (BaseCommand) declaredConstructor.newInstance(this); -284 } else { -285 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); -286 } -287 } -288 if (subCommand != null) { -289 subCommand.parentCommand = this; -290 subCommand.onRegister(manager, cmd); -291 this.subCommands.putAll(subCommand.subCommands); -292 this.registeredCommands.putAll(subCommand.registeredCommands); -293 } else { -294 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); -295 } -296 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { -297 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); -298 } -299 } -300 } -301 } -302 -303 /** -304 * This registers all subcommands of the command. -305 */ -306 private void registerSubcommands() { -307 final Annotations annotations = manager.getAnnotations(); -308 boolean foundDefault = false; -309 boolean foundCatchUnknown = false; -310 boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); -311 -312 for (Method method : this.getClass().getMethods()) { -313 method.setAccessible(true); -314 String sublist = null; -315 String sub = getSubcommandValue(method); -316 final boolean def = annotations.hasAnnotation(method, Default.class); -317 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); -318 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); -319 -320 if (!isParentEmpty && def) { -321 sub = parentSubcommand; -322 } -323 if (isParentEmpty && (def || (!foundDefault && helpCommand != null))) { -324 if (!foundDefault) { -325 if (def) { -326 this.subCommands.get(DEFAULT).clear(); -327 foundDefault = true; -328 } -329 registerSubcommand(method, DEFAULT); -330 } else { -331 ACFUtil.sneaky(new IllegalStateException("Multiple @Default/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -332 } -333 } -334 -335 if (sub != null) { -336 sublist = sub; -337 } else if (commandAliases != null) { -338 sublist = commandAliases; -339 } else if (helpCommand != null) { -340 sublist = helpCommand; -341 hasHelpCommand = true; -342 } -343 -344 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); -345 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || -346 annotations.hasAnnotation(method, CatchAll.class) || -347 annotations.hasAnnotation(method, UnknownHandler.class); -348 -349 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { -350 if (!foundCatchUnknown) { -351 if (hasCatchUnknown) { -352 this.subCommands.get(CATCHUNKNOWN).clear(); -353 foundCatchUnknown = true; -354 } -355 registerSubcommand(method, CATCHUNKNOWN); -356 } else { -357 ACFUtil.sneaky(new IllegalStateException("Multiple @UnknownHandler/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -358 } -359 } else if (preCommand) { -360 if (this.preCommandHandler == null) { -361 this.preCommandHandler = method; +240 final Annotations annotations = manager.getAnnotations(); +241 final Class<? extends BaseCommand> self = this.getClass(); +242 +243 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); +244 +245 if (cmd == null && cmdAliases != null) { +246 cmd = cmdAliases[0]; +247 } +248 +249 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); +250 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); +251 this.description = this.commandName + " commands"; +252 this.parentSubcommand = getParentSubcommand(self); +253 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +254 +255 registerSubcommands(); +256 registerPermissions(); +257 registerSubclasses(cmd); +258 +259 if (cmdAliases != null) { +260 Set<String> cmdList = new HashSet<>(); +261 Collections.addAll(cmdList, cmdAliases); +262 cmdList.remove(cmd); +263 for (String cmdAlias : cmdList) { +264 register(cmdAlias, this); +265 } +266 } +267 +268 if (cmd != null) { +269 register(cmd, this); +270 } +271 } +272 +273 /** +274 * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. +275 * +276 * @param cmd The command name of this command. +277 */ +278 private void registerSubclasses(String cmd) { +279 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { +280 if (BaseCommand.class.isAssignableFrom(clazz)) { +281 try { +282 BaseCommand subCommand = null; +283 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); +284 for (Constructor<?> declaredConstructor : declaredConstructors) { +285 +286 declaredConstructor.setAccessible(true); +287 Parameter[] parameters = declaredConstructor.getParameters(); +288 if (parameters.length == 1) { +289 subCommand = (BaseCommand) declaredConstructor.newInstance(this); +290 } else { +291 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); +292 } +293 } +294 if (subCommand != null) { +295 subCommand.parentCommand = this; +296 subCommand.onRegister(manager, cmd); +297 this.subCommands.putAll(subCommand.subCommands); +298 this.registeredCommands.putAll(subCommand.registeredCommands); +299 } else { +300 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); +301 } +302 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { +303 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); +304 } +305 } +306 } +307 } +308 +309 /** +310 * This registers all subcommands of the command. +311 */ +312 private void registerSubcommands() { +313 final Annotations annotations = manager.getAnnotations(); +314 boolean foundDefault = false; +315 boolean foundCatchUnknown = false; +316 boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); +317 +318 for (Method method : this.getClass().getMethods()) { +319 method.setAccessible(true); +320 String sublist = null; +321 String sub = getSubcommandValue(method); +322 final boolean def = annotations.hasAnnotation(method, Default.class); +323 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); +324 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); +325 +326 if (!isParentEmpty && def) { +327 sub = parentSubcommand; +328 } +329 if (isParentEmpty && (def || (!foundDefault && helpCommand != null))) { +330 if (!foundDefault) { +331 if (def) { +332 this.subCommands.get(DEFAULT).clear(); +333 foundDefault = true; +334 } +335 registerSubcommand(method, DEFAULT); +336 } else { +337 ACFUtil.sneaky(new IllegalStateException("Multiple @Default/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +338 } +339 } +340 +341 if (sub != null) { +342 sublist = sub; +343 } else if (commandAliases != null) { +344 sublist = commandAliases; +345 } else if (helpCommand != null) { +346 sublist = helpCommand; +347 hasHelpCommand = true; +348 } +349 +350 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); +351 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || +352 annotations.hasAnnotation(method, CatchAll.class) || +353 annotations.hasAnnotation(method, UnknownHandler.class); +354 +355 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { +356 if (!foundCatchUnknown) { +357 if (hasCatchUnknown) { +358 this.subCommands.get(CATCHUNKNOWN).clear(); +359 foundCatchUnknown = true; +360 } +361 registerSubcommand(method, CATCHUNKNOWN); 362 } else { -363 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +363 ACFUtil.sneaky(new IllegalStateException("Multiple @UnknownHandler/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); 364 } -365 } -366 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { -367 registerSubcommand(method, sublist); -368 } -369 } -370 } -371 -372 /** -373 * Gets the subcommand name of the method given. -374 * -375 * @param method The method to check. -376 * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. -377 */ -378 private String getSubcommandValue(Method method) { -379 final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); -380 if (sub == null) { -381 return null; -382 } -383 Class<?> clazz = method.getDeclaringClass(); -384 String parent = getParentSubcommand(clazz); -385 return parent == null || parent.isEmpty() ? sub : parent + " " + sub; -386 } -387 -388 private String getParentSubcommand(Class<?> clazz) { -389 List<String> subList = new ArrayList<>(); -390 while (clazz != null) { -391 String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); -392 if (sub != null) { -393 subList.add(sub); -394 } -395 clazz = clazz.getEnclosingClass(); -396 } -397 Collections.reverse(subList); -398 return ACFUtil.join(subList, " "); -399 } -400 -401 /** -402 * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. -403 * -404 * @param name Name of the parent to cmd. -405 * @param cmd The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. -406 */ -407 private void register(String name, BaseCommand cmd) { -408 String nameLower = name.toLowerCase(); -409 RootCommand rootCommand = manager.obtainRootCommand(nameLower); -410 rootCommand.addChild(cmd); -411 -412 this.registeredCommands.put(nameLower, rootCommand); -413 } -414 -415 /** -416 * Registers the given {@link Method} as a subcommand. -417 * -418 * @param method The method to register as a subcommand. -419 * @param subCommand The subcommand's name(s). -420 */ -421 private void registerSubcommand(Method method, String subCommand) { -422 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); -423 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); -424 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. -425 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); -426 -427 // Strip pipes off for auto complete addition -428 for (int i = 0; i < subCommandParts.length; i++) { -429 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); -430 if (split.length == 0 || split[0].isEmpty()) { -431 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); -432 } -433 subCommandParts[i] = split[0]; -434 } -435 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); -436 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); -437 -438 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; -439 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); -440 -441 for (String subcmd : cmdList) { -442 subCommands.put(subcmd, cmd); -443 } -444 cmd.addSubcommands(cmdList); +365 } else if (preCommand) { +366 if (this.preCommandHandler == null) { +367 this.preCommandHandler = method; +368 } else { +369 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +370 } +371 } +372 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { +373 registerSubcommand(method, sublist); +374 } +375 } +376 } +377 +378 /** +379 * This registers all the permissions required to execute this command. +380 */ +381 private void registerPermissions() { +382 this.permissions.clear(); +383 if (this.permission != null && !this.permission.isEmpty()) { +384 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); +385 } +386 if (this.parentCommand != null) { +387 this.permissions.addAll(this.parentCommand.getRequiredPermissions()); +388 } +389 } +390 +391 /** +392 * Gets the subcommand name of the method given. +393 * +394 * @param method The method to check. +395 * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. +396 */ +397 private String getSubcommandValue(Method method) { +398 final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); +399 if (sub == null) { +400 return null; +401 } +402 Class<?> clazz = method.getDeclaringClass(); +403 String parent = getParentSubcommand(clazz); +404 return parent == null || parent.isEmpty() ? sub : parent + " " + sub; +405 } +406 +407 private String getParentSubcommand(Class<?> clazz) { +408 List<String> subList = new ArrayList<>(); +409 while (clazz != null) { +410 String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); +411 if (sub != null) { +412 subList.add(sub); +413 } +414 clazz = clazz.getEnclosingClass(); +415 } +416 Collections.reverse(subList); +417 return ACFUtil.join(subList, " "); +418 } +419 +420 /** +421 * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. +422 * +423 * @param name Name of the parent to cmd. +424 * @param cmd The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. +425 */ +426 private void register(String name, BaseCommand cmd) { +427 String nameLower = name.toLowerCase(); +428 RootCommand rootCommand = manager.obtainRootCommand(nameLower); +429 rootCommand.addChild(cmd); +430 +431 this.registeredCommands.put(nameLower, rootCommand); +432 } +433 +434 /** +435 * Registers the given {@link Method} as a subcommand. +436 * +437 * @param method The method to register as a subcommand. +438 * @param subCommand The subcommand's name(s). +439 */ +440 private void registerSubcommand(Method method, String subCommand) { +441 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); +442 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); +443 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. +444 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); 445 -446 if (aliasNames != null) { -447 for (String name : aliasNames) { -448 register(name, new ForwardingCommand(this, cmd, subCommandParts)); -449 } -450 } -451 } -452 -453 /** -454 * Takes a string like "foo|bar baz|qux" and generates a list of -455 * - foo baz -456 * - foo qux -457 * - bar baz -458 * - bar qux -459 * <p> -460 * For every possible sub command combination -461 * -462 * @param subCommandParts -463 * @return List of all sub command possibilities -464 */ -465 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { -466 int i = 0; -467 Set<String> current = null; -468 while (true) { -469 Set<String> newList = new HashSet<>(); -470 -471 if (i < subCommandParts.length) { -472 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { -473 if (current != null) { -474 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); -475 } else { -476 newList.add(s1); -477 } -478 } -479 } -480 -481 if (i + 1 < subCommandParts.length) { -482 current = newList; -483 i = i + 1; -484 continue; -485 } -486 -487 return newList; -488 } -489 } -490 -491 public void execute(CommandIssuer issuer, String commandLabel, String[] args) { -492 commandLabel = commandLabel.toLowerCase(); -493 try { -494 CommandOperationContext commandContext = preCommandOperation(issuer, commandLabel, args, false); -495 -496 if (args.length > 0) { -497 CommandSearch cmd = findSubCommand(args); -498 if (cmd != null) { -499 execSubcommand = cmd.getCheckSub(); -500 final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length); -501 executeCommand(commandContext, issuer, execargs, cmd.cmd); -502 return; -503 } +446 // Strip pipes off for auto complete addition +447 for (int i = 0; i < subCommandParts.length; i++) { +448 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); +449 if (split.length == 0 || split[0].isEmpty()) { +450 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); +451 } +452 subCommandParts[i] = split[0]; +453 } +454 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); +455 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); +456 +457 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; +458 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); +459 +460 for (String subcmd : cmdList) { +461 subCommands.put(subcmd, cmd); +462 } +463 cmd.addSubcommands(cmdList); +464 +465 if (aliasNames != null) { +466 for (String name : aliasNames) { +467 register(name, new ForwardingCommand(this, cmd, subCommandParts)); +468 } +469 } +470 } +471 +472 /** +473 * Takes a string like "foo|bar baz|qux" and generates a list of +474 * - foo baz +475 * - foo qux +476 * - bar baz +477 * - bar qux +478 * <p> +479 * For every possible sub command combination +480 * +481 * @param subCommandParts +482 * @return List of all sub command possibilities +483 */ +484 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { +485 int i = 0; +486 Set<String> current = null; +487 while (true) { +488 Set<String> newList = new HashSet<>(); +489 +490 if (i < subCommandParts.length) { +491 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { +492 if (current != null) { +493 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); +494 } else { +495 newList.add(s1); +496 } +497 } +498 } +499 +500 if (i + 1 < subCommandParts.length) { +501 current = newList; +502 i = i + 1; +503 continue; 504 } 505 -506 if (subCommands.get(DEFAULT) != null && args.length == 0) { -507 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); -508 } else if (subCommands.get(CATCHUNKNOWN) != null) { -509 if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) { -510 help(issuer, args); -511 } -512 } else if (subCommands.get(DEFAULT) != null) { -513 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); -514 } -515 -516 } finally { -517 postCommandOperation(); -518 } -519 } -520 -521 /** -522 * Gets the registered command of the given arguments. -523 * -524 * @param args The arguments given by the user. -525 * @return The subcommand or null if none were found. -526 * @see #findSubCommand(String[]) -527 */ -528 RegisteredCommand<?> getRegisteredCommand(String[] args) { -529 final CommandSearch cmd = findSubCommand(args); -530 return cmd != null ? cmd.cmd : null; -531 } -532 -533 /** -534 * This is ran after any command operation has been performed. -535 */ -536 private void postCommandOperation() { -537 CommandManager.commandOperationContext.get().pop(); -538 execSubcommand = null; -539 execLabel = null; -540 origArgs = new String[]{}; -541 } -542 -543 /** -544 * This is ran before any command operation has been performed. -545 * -546 * @param issuer The user who executed the command. -547 * @param commandLabel The label the user used to execute the command. This is not the command name, but their input. -548 * When there is multiple aliases, this is which alias was used -549 * @param args The arguments passed to the command when executing it. -550 * @param isAsync Whether the command is executed off of the main thread. -551 * @return The context which is being registered to the {@link CommandManager}'s {@link -552 * CommandManager#commandOperationContext thread local stack}. -553 */ -554 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { -555 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); -556 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); -557 contexts.push(context); -558 lastCommandOperationContext.set(context); -559 execSubcommand = null; -560 execLabel = commandLabel; -561 origArgs = args; -562 return context; -563 } -564 -565 /** -566 * Gets the current command issuer. -567 * -568 * @return The current command issuer. -569 */ -570 public CommandIssuer getCurrentCommandIssuer() { -571 return CommandManager.getCurrentCommandIssuer(); -572 } -573 -574 /** -575 * Gets the current command manager. -576 * -577 * @return The current command manager. -578 */ -579 public CommandManager getCurrentCommandManager() { -580 return CommandManager.getCurrentCommandManager(); -581 } -582 -583 /** -584 * Finds a subcommand of the given arguments. -585 * -586 * @param args The arguments the user input. -587 * @return The identified subcommand. -588 * @see #findSubCommand(String[], boolean) -589 */ -590 private CommandSearch findSubCommand(String[] args) { -591 return findSubCommand(args, false); -592 } -593 -594 /** -595 * Finds a subcommand of the given arguments. -596 * -597 * @param args The arguments the user input. -598 * @param completion Whether or not completion of arguments should kick in. This may end up with worse than wanted results. -599 * @return The identified subcommand. -600 */ -601 private CommandSearch findSubCommand(String[] args, boolean completion) { -602 for (int i = args.length; i >= 0; i--) { -603 String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); -604 Set<RegisteredCommand> cmds = subCommands.get(checkSub); -605 -606 final int extraArgs = args.length - i; -607 if (!cmds.isEmpty()) { -608 RegisteredCommand cmd = null; -609 if (cmds.size() == 1) { -610 cmd = ACFUtil.getFirstElement(cmds); -611 } else { -612 Optional<RegisteredCommand> optCmd = cmds.stream().filter(c -> { -613 int required = c.requiredResolvers; -614 int optional = c.optionalResolvers; -615 return extraArgs <= required + optional && (completion || extraArgs >= required); -616 }).min((c1, c2) -> { -617 int a = c1.consumeInputResolvers; -618 int b = c2.consumeInputResolvers; -619 -620 if (a == b) { -621 return 0; -622 } -623 return a < b ? 1 : -1; -624 }); -625 if (optCmd.isPresent()) { -626 cmd = optCmd.get(); -627 } -628 } -629 if (cmd != null) { -630 return new CommandSearch(cmd, i, checkSub); -631 } -632 } -633 } -634 return null; -635 } -636 -637 private void executeCommand(CommandOperationContext commandOperationContext, -638 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { -639 if (cmd.hasPermission(issuer)) { -640 commandOperationContext.setRegisteredCommand(cmd); -641 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { -642 return; -643 } -644 List<String> sargs = Arrays.asList(args); -645 cmd.invoke(issuer, sargs, commandOperationContext); -646 } else { -647 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); -648 } -649 } -650 -651 /** -652 * Please use command conditions for restricting execution -653 * -654 * @param issuer -655 * @param cmd -656 * @return -657 * @deprecated See {@link CommandConditions} -658 */ -659 @SuppressWarnings("DeprecatedIsStillUsed") -660 @Deprecated -661 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { -662 return true; -663 } -664 -665 /** -666 * Gets tab completed data from the given command from the user. -667 * -668 * @param issuer The user who executed the tabcomplete. -669 * @param commandLabel The label which is being used by the user. -670 * @param args The arguments the user has typed so far. -671 * @return All possibilities in the tab complete. -672 */ -673 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { -674 return tabComplete(issuer, commandLabel, args, false); -675 } -676 -677 /** -678 * Gets the tab complete suggestions from a given command. This will automatically find anything -679 * which is valid for the specified command through the command's implementation. -680 * -681 * @param issuer The issuer of the command. -682 * @param commandLabel The command name as entered by the user instead of the ACF registered name. -683 * @param args All arguments entered by the user. -684 * @param isAsync Whether this is run off of the main thread. -685 * @return The possibilities to tab complete in no particular order. -686 */ -687 @SuppressWarnings("WeakerAccess") -688 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) -689 throws IllegalArgumentException { -690 -691 commandLabel = commandLabel.toLowerCase(); -692 if (args.length == 0) { -693 args = new String[]{""}; -694 } -695 try { -696 CommandOperationContext commandOperationContext = preCommandOperation(issuer, commandLabel, args, isAsync); -697 -698 final CommandSearch search = findSubCommand(args, true); -699 -700 -701 final List<String> cmds = new ArrayList<>(); -702 -703 if (search != null) { -704 cmds.addAll(completeCommand(issuer, search.cmd, Arrays.copyOfRange(args, search.argIndex, args.length), commandLabel, isAsync)); -705 } else if (subCommands.get(CATCHUNKNOWN).size() == 1) { -706 cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(CATCHUNKNOWN)), args, commandLabel, isAsync)); -707 } else if (subCommands.get(DEFAULT).size() == 1) { -708 cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(DEFAULT)), args, commandLabel, isAsync)); -709 } -710 -711 return filterTabComplete(args[args.length - 1], cmds); -712 } finally { -713 postCommandOperation(); -714 } -715 } +506 return newList; +507 } +508 } +509 +510 public void execute(CommandIssuer issuer, String commandLabel, String[] args) { +511 commandLabel = commandLabel.toLowerCase(); +512 try { +513 CommandOperationContext commandContext = preCommandOperation(issuer, commandLabel, args, false); +514 +515 if (args.length > 0) { +516 CommandSearch cmd = findSubCommand(args); +517 if (cmd != null) { +518 execSubcommand = cmd.getCheckSub(); +519 final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length); +520 executeCommand(commandContext, issuer, execargs, cmd.cmd); +521 return; +522 } +523 } +524 +525 if (subCommands.get(DEFAULT) != null && args.length == 0) { +526 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); +527 } else if (subCommands.get(CATCHUNKNOWN) != null) { +528 if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) { +529 help(issuer, args); +530 } +531 } else if (subCommands.get(DEFAULT) != null) { +532 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); +533 } +534 +535 } finally { +536 postCommandOperation(); +537 } +538 } +539 +540 /** +541 * Gets the registered command of the given arguments. +542 * +543 * @param args The arguments given by the user. +544 * @return The subcommand or null if none were found. +545 * @see #findSubCommand(String[]) +546 */ +547 RegisteredCommand<?> getRegisteredCommand(String[] args) { +548 final CommandSearch cmd = findSubCommand(args); +549 return cmd != null ? cmd.cmd : null; +550 } +551 +552 /** +553 * This is ran after any command operation has been performed. +554 */ +555 private void postCommandOperation() { +556 CommandManager.commandOperationContext.get().pop(); +557 execSubcommand = null; +558 execLabel = null; +559 origArgs = new String[]{}; +560 } +561 +562 /** +563 * This is ran before any command operation has been performed. +564 * +565 * @param issuer The user who executed the command. +566 * @param commandLabel The label the user used to execute the command. This is not the command name, but their input. +567 * When there is multiple aliases, this is which alias was used +568 * @param args The arguments passed to the command when executing it. +569 * @param isAsync Whether the command is executed off of the main thread. +570 * @return The context which is being registered to the {@link CommandManager}'s {@link +571 * CommandManager#commandOperationContext thread local stack}. +572 */ +573 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { +574 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); +575 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); +576 contexts.push(context); +577 lastCommandOperationContext.set(context); +578 execSubcommand = null; +579 execLabel = commandLabel; +580 origArgs = args; +581 return context; +582 } +583 +584 /** +585 * Gets the current command issuer. +586 * +587 * @return The current command issuer. +588 */ +589 public CommandIssuer getCurrentCommandIssuer() { +590 return CommandManager.getCurrentCommandIssuer(); +591 } +592 +593 /** +594 * Gets the current command manager. +595 * +596 * @return The current command manager. +597 */ +598 public CommandManager getCurrentCommandManager() { +599 return CommandManager.getCurrentCommandManager(); +600 } +601 +602 /** +603 * Finds a subcommand of the given arguments. +604 * +605 * @param args The arguments the user input. +606 * @return The identified subcommand. +607 * @see #findSubCommand(String[], boolean) +608 */ +609 private CommandSearch findSubCommand(String[] args) { +610 return findSubCommand(args, false); +611 } +612 +613 /** +614 * Finds a subcommand of the given arguments. +615 * +616 * @param args The arguments the user input. +617 * @param completion Whether or not completion of arguments should kick in. This may end up with worse than wanted results. +618 * @return The identified subcommand. +619 */ +620 private CommandSearch findSubCommand(String[] args, boolean completion) { +621 for (int i = args.length; i >= 0; i--) { +622 String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); +623 Set<RegisteredCommand> cmds = subCommands.get(checkSub); +624 +625 final int extraArgs = args.length - i; +626 if (!cmds.isEmpty()) { +627 RegisteredCommand cmd = null; +628 if (cmds.size() == 1) { +629 cmd = ACFUtil.getFirstElement(cmds); +630 } else { +631 Optional<RegisteredCommand> optCmd = cmds.stream().filter(c -> { +632 int required = c.requiredResolvers; +633 int optional = c.optionalResolvers; +634 return extraArgs <= required + optional && (completion || extraArgs >= required); +635 }).min((c1, c2) -> { +636 int a = c1.consumeInputResolvers; +637 int b = c2.consumeInputResolvers; +638 +639 if (a == b) { +640 return 0; +641 } +642 return a < b ? 1 : -1; +643 }); +644 if (optCmd.isPresent()) { +645 cmd = optCmd.get(); +646 } +647 } +648 if (cmd != null) { +649 return new CommandSearch(cmd, i, checkSub); +650 } +651 } +652 } +653 return null; +654 } +655 +656 private void executeCommand(CommandOperationContext commandOperationContext, +657 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { +658 if (cmd.hasPermission(issuer)) { +659 commandOperationContext.setRegisteredCommand(cmd); +660 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { +661 return; +662 } +663 List<String> sargs = Arrays.asList(args); +664 cmd.invoke(issuer, sargs, commandOperationContext); +665 } else { +666 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); +667 } +668 } +669 +670 /** +671 * Please use command conditions for restricting execution +672 * +673 * @param issuer +674 * @param cmd +675 * @return +676 * @deprecated See {@link CommandConditions} +677 */ +678 @SuppressWarnings("DeprecatedIsStillUsed") +679 @Deprecated +680 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { +681 return true; +682 } +683 +684 /** +685 * Gets tab completed data from the given command from the user. +686 * +687 * @param issuer The user who executed the tabcomplete. +688 * @param commandLabel The label which is being used by the user. +689 * @param args The arguments the user has typed so far. +690 * @return All possibilities in the tab complete. +691 */ +692 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { +693 return tabComplete(issuer, commandLabel, args, false); +694 } +695 +696 /** +697 * Gets the tab complete suggestions from a given command. This will automatically find anything +698 * which is valid for the specified command through the command's implementation. +699 * +700 * @param issuer The issuer of the command. +701 * @param commandLabel The command name as entered by the user instead of the ACF registered name. +702 * @param args All arguments entered by the user. +703 * @param isAsync Whether this is run off of the main thread. +704 * @return The possibilities to tab complete in no particular order. +705 */ +706 @SuppressWarnings("WeakerAccess") +707 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) +708 throws IllegalArgumentException { +709 +710 commandLabel = commandLabel.toLowerCase(); +711 if (args.length == 0) { +712 args = new String[]{""}; +713 } +714 try { +715 CommandOperationContext commandOperationContext = preCommandOperation(issuer, commandLabel, args, isAsync); 716 -717 /** -718 * Gets all subcommands which are possible to tabcomplete. -719 * -720 * @param issuer The command issuer. -721 * @param args -722 * @return -723 */ -724 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { -725 final Set<String> cmds = new HashSet<>(); -726 final int cmdIndex = Math.max(0, args.length - 1); -727 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); -728 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { -729 final String key = entry.getKey(); -730 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { -731 final RegisteredCommand value = entry.getValue(); -732 if (!value.hasPermission(issuer) || value.isPrivate) { -733 continue; -734 } +717 final CommandSearch search = findSubCommand(args, true); +718 +719 +720 final List<String> cmds = new ArrayList<>(); +721 +722 if (search != null) { +723 cmds.addAll(completeCommand(issuer, search.cmd, Arrays.copyOfRange(args, search.argIndex, args.length), commandLabel, isAsync)); +724 } else if (subCommands.get(CATCHUNKNOWN).size() == 1) { +725 cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(CATCHUNKNOWN)), args, commandLabel, isAsync)); +726 } else if (subCommands.get(DEFAULT).size() == 1) { +727 cmds.addAll(completeCommand(issuer, ACFUtil.getFirstElement(subCommands.get(DEFAULT)), args, commandLabel, isAsync)); +728 } +729 +730 return filterTabComplete(args[args.length - 1], cmds); +731 } finally { +732 postCommandOperation(); +733 } +734 } 735 -736 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); -737 cmds.add(split[cmdIndex]); -738 } -739 } -740 return new ArrayList<>(cmds); -741 } -742 -743 /** -744 * Complete a command properly per issuer and input. -745 * -746 * @param issuer The user who executed this. -747 * @param cmd The command to be completed. -748 * @param args All arguments given by the user. -749 * @param commandLabel The command name the user used. -750 * @param isAsync Whether the command was executed async. -751 * @return All results to complete the command. -752 */ -753 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { -754 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { -755 return Collections.emptyList(); -756 } -757 -758 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); -759 return filterTabComplete(args[args.length - 1], cmds); +736 /** +737 * Gets all subcommands which are possible to tabcomplete. +738 * +739 * @param issuer The command issuer. +740 * @param args +741 * @return +742 */ +743 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { +744 final Set<String> cmds = new HashSet<>(); +745 final int cmdIndex = Math.max(0, args.length - 1); +746 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); +747 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { +748 final String key = entry.getKey(); +749 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { +750 final RegisteredCommand value = entry.getValue(); +751 if (!value.hasPermission(issuer) || value.isPrivate) { +752 continue; +753 } +754 +755 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); +756 cmds.add(split[cmdIndex]); +757 } +758 } +759 return new ArrayList<>(cmds); 760 } 761 762 /** -763 * Gets the actual args in string form the user typed -764 * This returns a list of all tab complete options which are possible with the given argument and commands. -765 * -766 * @param arg Argument which was pressed tab on. -767 * @param cmds The possibilities to return. -768 * @return All possible options. This may be empty. -769 */ -770 private static List<String> filterTabComplete(String arg, List<String> cmds) { -771 return cmds.stream() -772 .distinct() -773 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) -774 .collect(Collectors.toList()); -775 } +763 * Complete a command properly per issuer and input. +764 * +765 * @param issuer The user who executed this. +766 * @param cmd The command to be completed. +767 * @param args All arguments given by the user. +768 * @param commandLabel The command name the user used. +769 * @param isAsync Whether the command was executed async. +770 * @return All results to complete the command. +771 */ +772 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { +773 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { +774 return Collections.emptyList(); +775 } 776 -777 /** -778 * Gets a registered command under the given subcommand name. -779 * -780 * @param subcommand The name of the subcommand requested. -781 * @return The subcommand found or null if none. -782 */ -783 private RegisteredCommand getCommandBySubcommand(String subcommand) { -784 return getCommandBySubcommand(subcommand, false); -785 } -786 -787 /** -788 * Gets a registered command under the given name. -789 * If requireOne is true, it won't accept more than a single matching subcommand. -790 * -791 * @param subcommand Name of the subcommand wanted. -792 * @param requireOne Whether to only accept 1 result. -793 * @return The subcommand found, or null if none/too many. -794 */ -795 private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) { -796 final Set<RegisteredCommand> commands = subCommands.get(subcommand); -797 if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) { -798 return commands.iterator().next(); -799 } -800 return null; -801 } -802 -803 /** -804 * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)} -805 * and gets through {@link #getCommandBySubcommand(String)}. -806 * -807 * @param commandContext The command context to use. -808 * @param subcommand The subcommand to find the executor of. -809 * @param issuer The issuer who executed the subcommand. -810 * @param args All arguments given by the issuer. -811 * @return Whether it found a command or not. -812 * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand) -813 * @see #getCommandBySubcommand(String) -814 * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext) -815 */ -816 private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { -817 final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand); -818 if (cmd != null) { -819 executeCommand(commandContext, issuer, args, cmd); -820 return true; -821 } -822 -823 return false; -824 } -825 -826 /** -827 * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. -828 * -829 * @param commandOperationContext The context to use. -830 * @param cmd The command executed. -831 * @param issuer The issuer who executed the command. -832 * @param args The arguments the issuer provided. -833 * @return Whether something went wrong. +777 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); +778 return filterTabComplete(args[args.length - 1], cmds); +779 } +780 +781 /** +782 * Gets the actual args in string form the user typed +783 * This returns a list of all tab complete options which are possible with the given argument and commands. +784 * +785 * @param arg Argument which was pressed tab on. +786 * @param cmds The possibilities to return. +787 * @return All possible options. This may be empty. +788 */ +789 private static List<String> filterTabComplete(String arg, List<String> cmds) { +790 return cmds.stream() +791 .distinct() +792 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) +793 .collect(Collectors.toList()); +794 } +795 +796 /** +797 * Gets a registered command under the given subcommand name. +798 * +799 * @param subcommand The name of the subcommand requested. +800 * @return The subcommand found or null if none. +801 */ +802 private RegisteredCommand getCommandBySubcommand(String subcommand) { +803 return getCommandBySubcommand(subcommand, false); +804 } +805 +806 /** +807 * Gets a registered command under the given name. +808 * If requireOne is true, it won't accept more than a single matching subcommand. +809 * +810 * @param subcommand Name of the subcommand wanted. +811 * @param requireOne Whether to only accept 1 result. +812 * @return The subcommand found, or null if none/too many. +813 */ +814 private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) { +815 final Set<RegisteredCommand> commands = subCommands.get(subcommand); +816 if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) { +817 return commands.iterator().next(); +818 } +819 return null; +820 } +821 +822 /** +823 * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)} +824 * and gets through {@link #getCommandBySubcommand(String)}. +825 * +826 * @param commandContext The command context to use. +827 * @param subcommand The subcommand to find the executor of. +828 * @param issuer The issuer who executed the subcommand. +829 * @param args All arguments given by the issuer. +830 * @return Whether it found a command or not. +831 * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand) +832 * @see #getCommandBySubcommand(String) +833 * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext) 834 */ -835 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { -836 Method pre = this.preCommandHandler; -837 if (pre != null) { -838 try { -839 Class<?>[] types = pre.getParameterTypes(); -840 Object[] parameters = new Object[pre.getParameterCount()]; -841 for (int i = 0; i < parameters.length; i++) { -842 Class<?> type = types[i]; -843 Object issuerObject = issuer.getIssuer(); -844 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { -845 parameters[i] = issuerObject; -846 } else if (CommandIssuer.class.isAssignableFrom(type)) { -847 parameters[i] = issuer; -848 } else if (RegisteredCommand.class.isAssignableFrom(type)) { -849 parameters[i] = cmd; -850 } else if (String[].class.isAssignableFrom((type))) { -851 parameters[i] = args; -852 } else { -853 parameters[i] = null; -854 } -855 } -856 -857 return (boolean) pre.invoke(this, parameters); -858 } catch (IllegalAccessException | InvocationTargetException e) { -859 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); -860 } -861 } -862 return false; -863 } -864 -865 /** -866 * @deprecated Unstable API -867 */ -868 @Deprecated -869 @UnstableAPI -870 public CommandHelp getCommandHelp() { -871 return manager.generateCommandHelp(); -872 } -873 -874 /** -875 * @deprecated Unstable API -876 */ -877 @Deprecated -878 @UnstableAPI -879 public void showCommandHelp() { -880 getCommandHelp().showHelp(); -881 } -882 -883 public void help(Object issuer, String[] args) { -884 help(manager.getCommandIssuer(issuer), args); -885 } -886 -887 public void help(CommandIssuer issuer, String[] args) { -888 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); -889 } -890 -891 public void doHelp(Object issuer, String... args) { -892 doHelp(manager.getCommandIssuer(issuer), args); -893 } -894 -895 public void doHelp(CommandIssuer issuer, String... args) { -896 help(issuer, args); -897 } -898 -899 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { -900 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, -901 "{command}", manager.getCommandPrefix(issuer) + cmd.command, -902 "{syntax}", cmd.syntaxText -903 ); +835 private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { +836 final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand); +837 if (cmd != null) { +838 executeCommand(commandContext, issuer, args, cmd); +839 return true; +840 } +841 +842 return false; +843 } +844 +845 /** +846 * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. +847 * +848 * @param commandOperationContext The context to use. +849 * @param cmd The command executed. +850 * @param issuer The issuer who executed the command. +851 * @param args The arguments the issuer provided. +852 * @return Whether something went wrong. +853 */ +854 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { +855 Method pre = this.preCommandHandler; +856 if (pre != null) { +857 try { +858 Class<?>[] types = pre.getParameterTypes(); +859 Object[] parameters = new Object[pre.getParameterCount()]; +860 for (int i = 0; i < parameters.length; i++) { +861 Class<?> type = types[i]; +862 Object issuerObject = issuer.getIssuer(); +863 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { +864 parameters[i] = issuerObject; +865 } else if (CommandIssuer.class.isAssignableFrom(type)) { +866 parameters[i] = issuer; +867 } else if (RegisteredCommand.class.isAssignableFrom(type)) { +868 parameters[i] = cmd; +869 } else if (String[].class.isAssignableFrom((type))) { +870 parameters[i] = args; +871 } else { +872 parameters[i] = null; +873 } +874 } +875 +876 return (boolean) pre.invoke(this, parameters); +877 } catch (IllegalAccessException | InvocationTargetException e) { +878 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); +879 } +880 } +881 return false; +882 } +883 +884 /** +885 * @deprecated Unstable API +886 */ +887 @Deprecated +888 @UnstableAPI +889 public CommandHelp getCommandHelp() { +890 return manager.generateCommandHelp(); +891 } +892 +893 /** +894 * @deprecated Unstable API +895 */ +896 @Deprecated +897 @UnstableAPI +898 public void showCommandHelp() { +899 getCommandHelp().showHelp(); +900 } +901 +902 public void help(Object issuer, String[] args) { +903 help(manager.getCommandIssuer(issuer), args); 904 } 905 -906 public boolean hasPermission(Object issuer) { -907 return hasPermission(manager.getCommandIssuer(issuer)); +906 public void help(CommandIssuer issuer, String[] args) { +907 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); 908 } 909 -910 public boolean hasPermission(CommandIssuer issuer) { -911 return permission == null || permission.isEmpty() || (manager.hasPermission(issuer, permission) && (parentCommand == null || parentCommand.hasPermission(issuer))); +910 public void doHelp(Object issuer, String... args) { +911 doHelp(manager.getCommandIssuer(issuer), args); 912 } 913 -914 public Set<String> getRequiredPermissions() { -915 Set<String> permissions = new HashSet<>(); -916 if (this.permission != null && !this.permission.isEmpty()) { -917 permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission))); -918 } -919 if (parentCommand != null) { -920 permissions.addAll(parentCommand.getRequiredPermissions()); -921 } -922 -923 return permissions; -924 } -925 -926 public boolean requiresPermission(String permission) { -927 return getRequiredPermissions().contains(permission); -928 } -929 -930 public String getName() { -931 return commandName; -932 } -933 -934 public ExceptionHandler getExceptionHandler() { -935 return exceptionHandler; -936 } -937 -938 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { -939 this.exceptionHandler = exceptionHandler; -940 return this; -941 } -942 -943 public RegisteredCommand getDefaultRegisteredCommand() { -944 return this.getCommandBySubcommand(DEFAULT); -945 } -946 -947 public String setContextFlags(Class<?> cls, String flags) { -948 return this.contextFlags.put(cls, flags); -949 } -950 -951 public String getContextFlags(Class<?> cls) { -952 return this.contextFlags.get(cls); -953 } -954 -955 public List<RegisteredCommand> getRegisteredCommands() { -956 List<RegisteredCommand> registeredCommands = new ArrayList<>(); -957 registeredCommands.addAll(this.subCommands.values()); -958 return registeredCommands; -959 +914 public void doHelp(CommandIssuer issuer, String... args) { +915 help(issuer, args); +916 } +917 +918 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { +919 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, +920 "{command}", manager.getCommandPrefix(issuer) + cmd.command, +921 "{syntax}", cmd.syntaxText +922 ); +923 } +924 +925 public boolean hasPermission(Object issuer) { +926 return hasPermission(manager.getCommandIssuer(issuer)); +927 } +928 +929 public boolean hasPermission(CommandIssuer issuer) { +930 return getRequiredPermissions().isEmpty() || getRequiredPermissions().stream().allMatch(permission -> manager.hasPermission(issuer, permission)); +931 } +932 +933 public Set<String> getRequiredPermissions() { +934 return this.permissions; +935 } +936 +937 public boolean requiresPermission(String permission) { +938 return getRequiredPermissions().contains(permission); +939 } +940 +941 public String getName() { +942 return commandName; +943 } +944 +945 public ExceptionHandler getExceptionHandler() { +946 return exceptionHandler; +947 } +948 +949 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { +950 this.exceptionHandler = exceptionHandler; +951 return this; +952 } +953 +954 public RegisteredCommand getDefaultRegisteredCommand() { +955 return this.getCommandBySubcommand(DEFAULT); +956 } +957 +958 public String setContextFlags(Class<?> cls, String flags) { +959 return this.contextFlags.put(cls, flags); 960 } 961 -962 private static class CommandSearch { -963 RegisteredCommand cmd; -964 int argIndex; -965 String checkSub; -966 -967 CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) { -968 this.cmd = cmd; -969 this.argIndex = argIndex; -970 this.checkSub = checkSub; -971 } +962 public String getContextFlags(Class<?> cls) { +963 return this.contextFlags.get(cls); +964 } +965 +966 public List<RegisteredCommand> getRegisteredCommands() { +967 List<RegisteredCommand> registeredCommands = new ArrayList<>(); +968 registeredCommands.addAll(this.subCommands.values()); +969 return registeredCommands; +970 +971 } 972 -973 String getCheckSub() { -974 return this.checkSub; -975 } -976 -977 @Override -978 public boolean equals(Object o) { -979 if (this == o) return true; -980 if (o == null || getClass() != o.getClass()) return false; -981 CommandSearch that = (CommandSearch) o; -982 return argIndex == that.argIndex && -983 Objects.equals(cmd, that.cmd) && -984 Objects.equals(checkSub, that.checkSub); -985 } -986 -987 @Override -988 public int hashCode() { -989 return Objects.hash(cmd, argIndex, checkSub); -990 } -991 } -992} +973 private static class CommandSearch { +974 RegisteredCommand cmd; +975 int argIndex; +976 String checkSub; +977 +978 CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) { +979 this.cmd = cmd; +980 this.argIndex = argIndex; +981 this.checkSub = checkSub; +982 } +983 +984 String getCheckSub() { +985 return this.checkSub; +986 } +987 +988 @Override +989 public boolean equals(Object o) { +990 if (this == o) return true; +991 if (o == null || getClass() != o.getClass()) return false; +992 CommandSearch that = (CommandSearch) o; +993 return argIndex == that.argIndex && +994 Objects.equals(cmd, that.cmd) && +995 Objects.equals(checkSub, that.checkSub); +996 } +997 +998 @Override +999 public int hashCode() { +1000 return Objects.hash(cmd, argIndex, checkSub); +1001 } +1002 } +1003}