From f7c1cc7102ee155fd18d331b008ad3ca3ea921d2 Mon Sep 17 00:00:00 2001 From: Aikar Date: Mon, 11 Feb 2019 20:39:34 -0500 Subject: [PATCH] (DEPLOYED ACF) Updated JavaDocs --- .../co/aikar/commands/BaseCommand.html | 104 +- .../co/aikar/commands/ForwardingCommand.html | 47 +- .../class-use/CommandOperationContext.html | 10 + docs/acf-core/index-all.html | 6 + .../co/aikar/commands/BaseCommand.html | 1568 +++++++++-------- .../co/aikar/commands/ForwardingCommand.html | 37 +- .../aikar/commands/SpongeCommandContexts.html | 4 +- .../co/aikar/commands/SpongeRootCommand.html | 10 +- .../aikar/commands/SpongeCommandContexts.html | 273 +-- .../co/aikar/commands/SpongeRootCommand.html | 61 +- 10 files changed, 1110 insertions(+), 1010 deletions(-) diff --git a/docs/acf-core/co/aikar/commands/BaseCommand.html b/docs/acf-core/co/aikar/commands/BaseCommand.html index 33226bc8..d311bc91 100644 --- a/docs/acf-core/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/co/aikar/commands/BaseCommand.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":42,"i1":10,"i2":10,"i3":10,"i4":42,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":42,"i24":10,"i25":10,"i26":10}; +var methods = {"i0":42,"i1":10,"i2":10,"i3":10,"i4":42,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":42,"i25":10,"i26":10,"i27":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -234,55 +234,61 @@ extends +CommandOperationContext +getLastCommandOperationContext() +
Returns a reference to the last used CommandOperationContext.
+ + + String getName()  - + String[] getOrigArgs()
Gets the actual args in string form the user typed
- + List<RegisteredCommand> getRegisteredCommands()  - + Set<String> getRequiredPermissions()  - + boolean hasPermission(CommandIssuer issuer)  - + boolean hasPermission(Object issuer)  - + void help(CommandIssuer issuer, String[] args)  - + void help(Object issuer, String[] args)  - + boolean requiresPermission(String permission)  - + String setContextFlags(Class<?> cls, String flags)  - + BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler)  - + void showCommandHelp()
Deprecated.  @@ -290,12 +296,12 @@ extends + void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd)  - + List<String> tabComplete(CommandIssuer issuer, String commandLabel, @@ -303,7 +309,7 @@ extends Gets tab completed data from the given command from the user.
- + List<String> tabComplete(CommandIssuer issuer, String commandLabel, @@ -368,13 +374,27 @@ public  + + +
    +
  • +

    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
    +
    +
    Returns:
    +
    +
  • +
@@ -532,7 +552,7 @@ public 

showCommandHelp

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    -
    public List<RegisteredCommandgetRegisteredCommands()
    +
    public List<RegisteredCommandgetRegisteredCommands()
  • diff --git a/docs/acf-core/co/aikar/commands/ForwardingCommand.html b/docs/acf-core/co/aikar/commands/ForwardingCommand.html index 03a6ff1b..b4efb85d 100644 --- a/docs/acf-core/co/aikar/commands/ForwardingCommand.html +++ b/docs/acf-core/co/aikar/commands/ForwardingCommand.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10}; +var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -140,26 +140,32 @@ extends String[] args)
      +CommandOperationContext +getLastCommandOperationContext() +
    Returns a reference to the last used CommandOperationContext.
    + + + List<RegisteredCommand> getRegisteredCommands()  - + Set<String> getRequiredPermissions()  - + boolean hasPermission(CommandIssuer sender)  - + boolean hasPermission(Object issuer)  - + boolean requiresPermission(String permission)  - + List<String> tabComplete(CommandIssuer issuer, String alias, @@ -210,13 +216,30 @@ extends + + +
    • getRequiredPermissions

      -
      public Set<StringgetRequiredPermissions()
      +
      public Set<StringgetRequiredPermissions()
      Overrides:
      getRequiredPermissions in class BaseCommand
      @@ -229,7 +252,7 @@ extends
    • hasPermission

      -
      public boolean hasPermission(Object issuer)
      +
      public boolean hasPermission(Object issuer)
      Overrides:
      hasPermission in class BaseCommand
      @@ -242,7 +265,7 @@ extends
    • requiresPermission

      -
      public boolean requiresPermission(String permission)
      +
      public boolean requiresPermission(String permission)
      Overrides:
      requiresPermission in class BaseCommand
      @@ -255,7 +278,7 @@ extends
    • hasPermission

      -
      public boolean hasPermission(CommandIssuer sender)
      +
      public boolean hasPermission(CommandIssuer sender)
      Overrides:
      hasPermission in class BaseCommand
      @@ -268,7 +291,7 @@ extends
    • tabComplete

      -
      public List<StringtabComplete(CommandIssuer issuer,
      +
      public List<StringtabComplete(CommandIssuer issuer,
                                       String alias,
                                       String[] args,
                                       boolean isAsync)
      @@ -297,7 +320,7 @@ extends 
       
    • execute

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


    • -
      public class SpongeCommandContexts
      +
      public class SpongeCommandContexts
       extends co.aikar.commands.CommandContexts<SpongeCommandExecutionContext>
    • @@ -187,7 +187,7 @@ extends co.aikar.commands.CommandContexts<
    • SpongeCommandContexts

      -
      public SpongeCommandContexts(SpongeCommandManager manager)
      +
      public SpongeCommandContexts(SpongeCommandManager manager)
    • diff --git a/docs/acf-sponge/co/aikar/commands/SpongeRootCommand.html b/docs/acf-sponge/co/aikar/commands/SpongeRootCommand.html index f2e0dc6b..4855aaf9 100644 --- a/docs/acf-sponge/co/aikar/commands/SpongeRootCommand.html +++ b/docs/acf-sponge/co/aikar/commands/SpongeRootCommand.html @@ -328,7 +328,7 @@ implements org.spongepowered.api.command.CommandCallable, co.aikar.commands.Root
      • addChild

        -
        public void addChild(co.aikar.commands.BaseCommand command)
        +
        public void addChild(co.aikar.commands.BaseCommand command)
        Specified by:
        addChild in interface co.aikar.commands.RootCommand
        @@ -341,7 +341,7 @@ implements org.spongepowered.api.command.CommandCallable, co.aikar.commands.Root
        • getDefCommand

          -
          public co.aikar.commands.BaseCommand getDefCommand()
          +
          public co.aikar.commands.BaseCommand getDefCommand()
          Specified by:
          getDefCommand in interface co.aikar.commands.RootCommand
          @@ -354,7 +354,7 @@ implements org.spongepowered.api.command.CommandCallable, co.aikar.commands.Root
          • getManager

            -
            public co.aikar.commands.CommandManager getManager()
            +
            public co.aikar.commands.CommandManager getManager()
            Specified by:
            getManager in interface co.aikar.commands.RootCommand
            @@ -367,7 +367,7 @@ implements org.spongepowered.api.command.CommandCallable, co.aikar.commands.Root
            • getSubCommands

              -
              public com.google.common.collect.SetMultimap<String,co.aikar.commands.RegisteredCommand> getSubCommands()
              +
              public com.google.common.collect.SetMultimap<String,co.aikar.commands.RegisteredCommand> getSubCommands()
              Specified by:
              getSubCommands in interface co.aikar.commands.RootCommand
              @@ -380,7 +380,7 @@ implements org.spongepowered.api.command.CommandCallable, co.aikar.commands.Root
              • getChildren

                -
                public List<co.aikar.commands.BaseCommand> getChildren()
                +
                public List<co.aikar.commands.BaseCommand> getChildren()
                Specified by:
                getChildren in interface co.aikar.commands.RootCommand
                diff --git a/docs/acf-sponge/src-html/co/aikar/commands/SpongeCommandContexts.html b/docs/acf-sponge/src-html/co/aikar/commands/SpongeCommandContexts.html index 1688aff0..1e135196 100644 --- a/docs/acf-sponge/src-html/co/aikar/commands/SpongeCommandContexts.html +++ b/docs/acf-sponge/src-html/co/aikar/commands/SpongeCommandContexts.html @@ -31,131 +31,156 @@ 023 024package co.aikar.commands; 025 -026import co.aikar.commands.annotation.Optional; -027import co.aikar.commands.contexts.CommandResultSupplier; -028import co.aikar.commands.contexts.OnlinePlayer; -029import org.jetbrains.annotations.Nullable; -030import org.spongepowered.api.Sponge; -031import org.spongepowered.api.command.CommandSource; -032import org.spongepowered.api.entity.living.player.Player; -033import org.spongepowered.api.text.format.TextColor; -034import org.spongepowered.api.text.format.TextStyle; -035import org.spongepowered.api.world.World; -036 -037import java.util.HashSet; -038import java.util.Set; -039import java.util.regex.Pattern; -040import java.util.stream.Collectors; -041import java.util.stream.Stream; -042 -043@SuppressWarnings("WeakerAccess") -044public class SpongeCommandContexts extends CommandContexts<SpongeCommandExecutionContext> { -045 -046 public SpongeCommandContexts(final SpongeCommandManager manager) { -047 super(manager); -048 -049 registerIssuerOnlyContext(CommandResultSupplier.class, c -> new CommandResultSupplier()); -050 registerContext(OnlinePlayer.class, c -> getOnlinePlayer(c.getIssuer(), c.popFirstArg(), c.hasAnnotation(Optional.class))); -051 registerContext(TextColor.class, c -> { -052 String first = c.popFirstArg(); -053 Stream<TextColor> colours = Sponge.getRegistry().getAllOf(TextColor.class).stream(); -054 String filter = c.getFlagValue("filter", (String)null); -055 if(filter != null) { -056 filter = ACFUtil.simplifyString(filter); -057 String finalFilter = filter; -058 colours = colours.filter(colour -> finalFilter.equals(ACFUtil.simplifyString(colour.getName()))); +026import co.aikar.commands.contexts.CommandResultSupplier; +027import co.aikar.commands.contexts.OnlinePlayer; +028import org.jetbrains.annotations.Nullable; +029import org.spongepowered.api.Sponge; +030import org.spongepowered.api.command.CommandSource; +031import org.spongepowered.api.entity.living.player.Player; +032import org.spongepowered.api.entity.living.player.User; +033import org.spongepowered.api.service.user.UserStorageService; +034import org.spongepowered.api.text.format.TextColor; +035import org.spongepowered.api.text.format.TextStyle; +036import org.spongepowered.api.world.World; +037 +038import java.util.HashSet; +039import java.util.Optional; +040import java.util.Set; +041import java.util.regex.Pattern; +042import java.util.stream.Collectors; +043import java.util.stream.Stream; +044 +045@SuppressWarnings("WeakerAccess") +046public class SpongeCommandContexts extends CommandContexts<SpongeCommandExecutionContext> { +047 +048 public SpongeCommandContexts(final SpongeCommandManager manager) { +049 super(manager); +050 +051 registerIssuerOnlyContext(CommandResultSupplier.class, c -> new CommandResultSupplier()); +052 registerContext(OnlinePlayer.class, c -> getOnlinePlayer(c.getIssuer(), c.popFirstArg(), c.isOptional())); +053 registerContext(User.class, c -> { +054 String name = c.popFirstArg(); +055 // try online players first +056 Optional<Player> targetPlayer = Sponge.getGame().getServer().getPlayer(name); +057 if (targetPlayer.isPresent()) { +058 return targetPlayer.get(); 059 } -060 Stream<TextColor> finalColours = colours; -061 return Sponge.getRegistry().getType(TextColor.class, ACFUtil.simplifyString(first)).orElseThrow(() -> { -062 String valid = finalColours -063 .map(colour -> "<c2>" + ACFUtil.simplifyString(colour.getName()) + "</c2>") -064 .collect(Collectors.joining("<c1>,</c1> ")); -065 return new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid); -066 }); -067 }); -068 registerContext(TextStyle.Base.class, c -> { -069 String first = c.popFirstArg(); -070 Stream<TextStyle.Base> styles = Sponge.getRegistry().getAllOf(TextStyle.Base.class).stream(); -071 String filter = c.getFlagValue("filter", (String)null); -072 if(filter != null) { -073 filter = ACFUtil.simplifyString(filter); -074 String finalFilter = filter; -075 styles = styles.filter(style -> finalFilter.equals(ACFUtil.simplifyString(style.getName()))); -076 } -077 Stream<TextStyle.Base> finalStyles = styles; -078 return Sponge.getRegistry().getType(TextStyle.Base.class, ACFUtil.simplifyString(first)).orElseThrow(() -> { -079 String valid = finalStyles -080 .map(style -> "<c2>" + ACFUtil.simplifyString(style.getName()) + "</c2>") -081 .collect(Collectors.joining("<c1>,</c1> ")); -082 return new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid); -083 }); -084 }); -085 -086 registerIssuerAwareContext(CommandSource.class, SpongeCommandExecutionContext::getSource); -087 registerIssuerAwareContext(Player.class, (c) -> { -088 Player player = c.getSource() instanceof Player ? (Player) c.getSource() : null; -089 if (player == null && !c.hasAnnotation(Optional.class)) { -090 throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false); -091 } -092 /*PlayerInventory inventory = player != null ? player.getInventory() : null; -093 if (inventory != null && c.hasFlag("itemheld") && !ACFBukkitUtil.isValidItem(inventory.getItem(inventory.getHeldItemSlot()))) { -094 throw new InvalidCommandArgument(MinecraftMessageKeys.YOU_MUST_BE_HOLDING_ITEM, false); -095 }*/ -096 return player; -097 }); -098 registerContext(OnlinePlayer[].class, (c) -> { -099 SpongeCommandIssuer issuer = c.getIssuer(); -100 final String search = c.popFirstArg(); -101 boolean allowMissing = c.hasFlag("allowmissing"); -102 Set<OnlinePlayer> players = new HashSet<>(); -103 Pattern split = ACFPatterns.COMMA; -104 String splitter = c.getFlagValue("splitter", (String) null); -105 if (splitter != null) { -106 split = Pattern.compile(Pattern.quote(splitter)); -107 } -108 for (String lookup : split.split(search)) { -109 OnlinePlayer player = getOnlinePlayer(issuer, lookup, allowMissing); -110 if (player != null) { -111 players.add(player); -112 } -113 } -114 if (players.isEmpty() && !c.hasFlag("allowempty")) { -115 issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, -116 "{search}", search); -117 -118 throw new InvalidCommandArgument(false); -119 } -120 return players.toArray(new OnlinePlayer[players.size()]); -121 }); -122 registerIssuerAwareContext(World.class, (c) -> { -123 String firstArg = c.getFirstArg(); -124 java.util.Optional<World> world = firstArg != null ? Sponge.getServer().getWorld(firstArg) : java.util.Optional.empty(); -125 if (world.isPresent()) { -126 c.popFirstArg(); -127 } -128 if (!world.isPresent() && c.getSource() instanceof Player) { -129 world = java.util.Optional.of(((Player) c.getSource()).getWorld()); -130 } -131 if (!world.isPresent()) { -132 throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD); -133 } -134 return world.get(); -135 }); -136 } -137 -138 @Nullable -139 OnlinePlayer getOnlinePlayer(SpongeCommandIssuer issuer, String lookup, boolean allowMissing) throws InvalidCommandArgument { -140 Player player = ACFSpongeUtil.findPlayerSmart(issuer, lookup); -141 //noinspection Duplicates -142 if (player == null) { -143 if (allowMissing) { -144 return null; -145 } -146 throw new InvalidCommandArgument(false); -147 } -148 return new OnlinePlayer(player); -149 } -150} +060 +061 Optional<UserStorageService> service = Sponge.getGame().getServiceManager().provide(UserStorageService.class); +062 if (!service.isPresent()) { +063 manager.log(LogLevel.ERROR, "No UserStorageService is available", new Error()); +064 throw new InvalidCommandArgument(MessageKeys.ERROR_GENERIC_LOGGED, false); +065 } +066 Optional<User> user = service.get().get(name); +067 if (user.isPresent()) { +068 return user.get(); +069 } +070 if (!c.isOptional()) { +071 throw new InvalidCommandArgument(MinecraftMessageKeys.NO_PLAYER_FOUND, false); +072 } +073 +074 return null; +075 }); +076 registerContext(TextColor.class, c -> { +077 String first = c.popFirstArg(); +078 Stream<TextColor> colours = Sponge.getRegistry().getAllOf(TextColor.class).stream(); +079 String filter = c.getFlagValue("filter", (String) null); +080 if (filter != null) { +081 filter = ACFUtil.simplifyString(filter); +082 String finalFilter = filter; +083 colours = colours.filter(colour -> finalFilter.equals(ACFUtil.simplifyString(colour.getName()))); +084 } +085 Stream<TextColor> finalColours = colours; +086 return Sponge.getRegistry().getType(TextColor.class, ACFUtil.simplifyString(first)).orElseThrow(() -> { +087 String valid = finalColours +088 .map(colour -> "<c2>" + ACFUtil.simplifyString(colour.getName()) + "</c2>") +089 .collect(Collectors.joining("<c1>,</c1> ")); +090 return new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid); +091 }); +092 }); +093 registerContext(TextStyle.Base.class, c -> { +094 String first = c.popFirstArg(); +095 Stream<TextStyle.Base> styles = Sponge.getRegistry().getAllOf(TextStyle.Base.class).stream(); +096 String filter = c.getFlagValue("filter", (String) null); +097 if (filter != null) { +098 filter = ACFUtil.simplifyString(filter); +099 String finalFilter = filter; +100 styles = styles.filter(style -> finalFilter.equals(ACFUtil.simplifyString(style.getName()))); +101 } +102 Stream<TextStyle.Base> finalStyles = styles; +103 return Sponge.getRegistry().getType(TextStyle.Base.class, ACFUtil.simplifyString(first)).orElseThrow(() -> { +104 String valid = finalStyles +105 .map(style -> "<c2>" + ACFUtil.simplifyString(style.getName()) + "</c2>") +106 .collect(Collectors.joining("<c1>,</c1> ")); +107 return new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF, "{valid}", valid); +108 }); +109 }); +110 +111 registerIssuerAwareContext(CommandSource.class, SpongeCommandExecutionContext::getSource); +112 registerIssuerAwareContext(Player.class, (c) -> { +113 Player player = c.getSource() instanceof Player ? (Player) c.getSource() : null; +114 if (player == null && !c.isOptional()) { +115 throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, false); +116 } +117 /*PlayerInventory inventory = player != null ? player.getInventory() : null; +118 if (inventory != null && c.hasFlag("itemheld") && !ACFBukkitUtil.isValidItem(inventory.getItem(inventory.getHeldItemSlot()))) { +119 throw new InvalidCommandArgument(MinecraftMessageKeys.YOU_MUST_BE_HOLDING_ITEM, false); +120 }*/ +121 return player; +122 }); +123 registerContext(OnlinePlayer[].class, (c) -> { +124 SpongeCommandIssuer issuer = c.getIssuer(); +125 final String search = c.popFirstArg(); +126 boolean allowMissing = c.hasFlag("allowmissing"); +127 Set<OnlinePlayer> players = new HashSet<>(); +128 Pattern split = ACFPatterns.COMMA; +129 String splitter = c.getFlagValue("splitter", (String) null); +130 if (splitter != null) { +131 split = Pattern.compile(Pattern.quote(splitter)); +132 } +133 for (String lookup : split.split(search)) { +134 OnlinePlayer player = getOnlinePlayer(issuer, lookup, allowMissing); +135 if (player != null) { +136 players.add(player); +137 } +138 } +139 if (players.isEmpty() && !c.hasFlag("allowempty")) { +140 issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, +141 "{search}", search); +142 +143 throw new InvalidCommandArgument(false); +144 } +145 return players.toArray(new OnlinePlayer[players.size()]); +146 }); +147 registerIssuerAwareContext(World.class, (c) -> { +148 String firstArg = c.getFirstArg(); +149 java.util.Optional<World> world = firstArg != null ? Sponge.getServer().getWorld(firstArg) : java.util.Optional.empty(); +150 if (world.isPresent()) { +151 c.popFirstArg(); +152 } +153 if (!world.isPresent() && c.getSource() instanceof Player) { +154 world = java.util.Optional.of(((Player) c.getSource()).getWorld()); +155 } +156 if (!world.isPresent()) { +157 throw new InvalidCommandArgument(MinecraftMessageKeys.INVALID_WORLD); +158 } +159 return world.get(); +160 }); +161 } +162 +163 @Nullable +164 OnlinePlayer getOnlinePlayer(SpongeCommandIssuer issuer, String lookup, boolean allowMissing) throws InvalidCommandArgument { +165 Player player = ACFSpongeUtil.findPlayerSmart(issuer, lookup); +166 //noinspection Duplicates +167 if (player == null) { +168 if (allowMissing) { +169 return null; +170 } +171 throw new InvalidCommandArgument(false); +172 } +173 return new OnlinePlayer(player); +174 } +175} diff --git a/docs/acf-sponge/src-html/co/aikar/commands/SpongeRootCommand.html b/docs/acf-sponge/src-html/co/aikar/commands/SpongeRootCommand.html index a49d160c..f7413612 100644 --- a/docs/acf-sponge/src-html/co/aikar/commands/SpongeRootCommand.html +++ b/docs/acf-sponge/src-html/co/aikar/commands/SpongeRootCommand.html @@ -102,36 +102,37 @@ 094 095 private CommandResult executeSponge(CommandIssuer sender, String commandLabel, String[] args) { 096 BaseCommand cmd = execute(sender, commandLabel, args); -097 return ((SpongeCommandOperationContext) cmd.lastCommandOperationContext).getResult(); -098 } -099 -100 public void addChild(BaseCommand command) { -101 if (this.defCommand == null || !command.subCommands.get(BaseCommand.DEFAULT).isEmpty()) { -102 this.defCommand = command; -103 } -104 addChildShared(this.children, this.subCommands, command); -105 } -106 -107 @Override -108 public BaseCommand getDefCommand() { -109 return defCommand; -110 } -111 -112 @Override -113 public CommandManager getManager() { -114 return manager; -115 } -116 -117 @Override -118 public SetMultimap<String, RegisteredCommand> getSubCommands() { -119 return subCommands; -120 } -121 -122 @Override -123 public List<BaseCommand> getChildren() { -124 return children; -125 } -126} +097 SpongeCommandOperationContext lastContext = (SpongeCommandOperationContext) cmd.getLastCommandOperationContext(); +098 return lastContext != null ? lastContext.getResult() : CommandResult.success(); +099 } +100 +101 public void addChild(BaseCommand command) { +102 if (this.defCommand == null || !command.subCommands.get(BaseCommand.DEFAULT).isEmpty()) { +103 this.defCommand = command; +104 } +105 addChildShared(this.children, this.subCommands, command); +106 } +107 +108 @Override +109 public BaseCommand getDefCommand() { +110 return defCommand; +111 } +112 +113 @Override +114 public CommandManager getManager() { +115 return manager; +116 } +117 +118 @Override +119 public SetMultimap<String, RegisteredCommand> getSubCommands() { +120 return subCommands; +121 } +122 +123 @Override +124 public List<BaseCommand> getChildren() { +125 return children; +126 } +127}