From 54d64e69a271ec1d93ba4c47da829953b59ca442 Mon Sep 17 00:00:00 2001 From: Aikar Date: Tue, 12 Jun 2018 22:24:09 -0400 Subject: [PATCH] (DEPLOYED ACF) Updated JavaDocs --- .../commands/BukkitCommandCompletions.html | 2 +- .../commands/BungeeCommandCompletions.html | 2 +- .../co/aikar/commands/BaseCommand.html | 208 ++- ...letions.AsyncCommandCompletionHandler.html | 2 +- ...dCompletions.CommandCompletionHandler.html | 4 +- ...andCompletions.SyncCompletionRequired.html | 4 +- .../co/aikar/commands/CommandCompletions.html | 142 +- .../co/aikar/commands/ForwardingCommand.html | 31 +- .../commands/annotation/CatchUnknown.html | 9 +- .../commands/annotation/CommandAlias.html | 10 +- .../annotation/CommandCompletion.html | 14 +- .../annotation/CommandPermission.html | 7 +- .../aikar/commands/annotation/Conditions.html | 12 +- .../co/aikar/commands/annotation/Default.html | 6 +- .../aikar/commands/annotation/Dependency.html | 6 +- .../commands/annotation/Description.html | 6 +- .../co/aikar/commands/annotation/Flags.html | 9 +- .../commands/annotation/HelpCommand.html | 16 +- .../commands/annotation/HelpSearchTags.html | 8 +- .../aikar/commands/annotation/Optional.html | 7 +- .../aikar/commands/annotation/PreCommand.html | 3 +- .../co/aikar/commands/annotation/Single.html | 4 +- .../co/aikar/commands/annotation/Split.html | 6 +- .../aikar/commands/annotation/Subcommand.html | 9 +- .../co/aikar/commands/annotation/Syntax.html | 11 +- .../co/aikar/commands/annotation/Values.html | 7 +- .../commands/annotation/package-summary.html | 72 +- ...letions.AsyncCommandCompletionHandler.html | 4 +- ...dCompletions.CommandCompletionHandler.html | 40 +- .../class-use/CommandExecutionContext.html | 6 +- .../commands/class-use/CommandIssuer.html | 24 +- .../commands/class-use/CommandManager.html | 4 +- .../class-use/InvalidCommandArgument.html | 4 +- .../commands/class-use/RegisteredCommand.html | 6 +- .../commands/contexts/ContextResolver.html | 21 +- .../contexts/OptionalContextResolver.html | 11 +- .../contexts/class-use/ContextResolver.html | 2 +- .../commands/contexts/package-summary.html | 6 +- .../aikar/commands/contexts/package-use.html | 10 +- .../co/aikar/commands/package-summary.html | 4 +- .../co/aikar/commands/package-use.html | 4 +- docs/acf-core/constant-values.html | 28 - docs/acf-core/deprecated-list.html | 60 +- docs/acf-core/index-all.html | 142 +- .../co/aikar/commands/BaseCommand.html | 1594 ++++++++++------- ...letions.AsyncCommandCompletionHandler.html | 329 ++-- ...dCompletions.CommandCompletionHandler.html | 329 ++-- ...andCompletions.SyncCompletionRequired.html | 329 ++-- .../co/aikar/commands/CommandCompletions.html | 329 ++-- .../commands/annotation/CatchUnknown.html | 17 +- .../commands/annotation/CommandAlias.html | 18 +- .../annotation/CommandCompletion.html | 20 +- .../annotation/CommandPermission.html | 15 +- .../aikar/commands/annotation/Conditions.html | 18 +- .../co/aikar/commands/annotation/Default.html | 14 +- .../aikar/commands/annotation/Dependency.html | 22 +- .../commands/annotation/Description.html | 14 +- .../co/aikar/commands/annotation/Flags.html | 17 +- .../commands/annotation/HelpCommand.html | 20 +- .../commands/annotation/HelpSearchTags.html | 16 +- .../aikar/commands/annotation/Optional.html | 15 +- .../aikar/commands/annotation/PreCommand.html | 9 +- .../co/aikar/commands/annotation/Single.html | 9 +- .../co/aikar/commands/annotation/Split.html | 14 +- .../aikar/commands/annotation/Subcommand.html | 17 +- .../co/aikar/commands/annotation/Syntax.html | 21 +- .../co/aikar/commands/annotation/Values.html | 15 +- .../commands/contexts/ContextResolver.html | 27 +- .../contexts/OptionalContextResolver.html | 11 +- .../aikar/commands/JDACommandCompletions.html | 7 + .../commands/PaperCommandCompletions.html | 2 +- .../commands/SpongeCommandCompletions.html | 2 +- 72 files changed, 2694 insertions(+), 1549 deletions(-) diff --git a/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html b/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html index 69163652..b138fc01 100644 --- a/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html +++ b/docs/acf-bukkit/co/aikar/commands/BukkitCommandCompletions.html @@ -158,7 +158,7 @@ extends co.aikar.commands.CommandCompletions<
  • diff --git a/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html b/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html index cdaecb66..0bb441a3 100644 --- a/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html +++ b/docs/acf-bungee/co/aikar/commands/BungeeCommandCompletions.html @@ -158,7 +158,7 @@ extends co.aikar.commands.CommandCompletions<
  • diff --git a/docs/acf-core/co/aikar/commands/BaseCommand.html b/docs/acf-core/co/aikar/commands/BaseCommand.html index df13417f..5b30480e 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":10,"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":42,"i23":10,"i24":10,"i25":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":42,"i23":10,"i24":10,"i25":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"; @@ -74,13 +74,13 @@ var activeTableTab = "activeTableTab"; @@ -112,37 +112,22 @@ var activeTableTab = "activeTableTab";

    -
    public abstract class BaseCommand
    +
    public abstract class BaseCommand
     extends Object
    +
    A Base command is defined as a command group of related commands. + A BaseCommand does not imply nor enforce that they use the same root command. + + It is up to the end user how to organize their command. you could use 1 base command per + command in your application. + + Optionally (and encouraged), you can use the base command to represent a root command, and + then each actionable command is a sub command
  • @@ -476,9 +470,18 @@ extends
  • 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.
    +
    +
    Parameters:
    +
    issuer - The user who executed the tabcomplete.
    +
    commandLabel - The label which is being used by the user.
    +
    args - The arguments the user has typed so far.
    +
    Returns:
    +
    All possibilities in the tab complete.
    +
  • @@ -487,12 +490,21 @@ extends
  • tabComplete

    -
    public List<StringtabComplete(CommandIssuer issuer,
    +
    public List<StringtabComplete(CommandIssuer issuer,
                                     String commandLabel,
                                     String[] args,
                                     boolean isAsync)
                              throws IllegalArgumentException
    +
    Gets the tab complete suggestions from a given command. This will automatically find anything + which is valid for the specified command through the command's implementation.
    +
    Parameters:
    +
    issuer - The issuer of the command.
    +
    commandLabel - The command name as entered by the user instead of the ACF registered name.
    +
    args - All arguments entered by the user.
    +
    isAsync - Whether this is run off of the main thread.
    +
    Returns:
    +
    The possibilities to tab complete in no particular order.
    Throws:
    IllegalArgumentException
    @@ -505,7 +517,7 @@ extends

    getCommandHelp

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

    showCommandHelp

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    -
    public String getContextFlags(Class<?> cls)
    +
    public String getContextFlags(Class<?> cls)
  • @@ -714,13 +726,13 @@ public void 
  • Summary: 
  • Nested | 
  • -
  • Field | 
  • +
  • Field | 
  • Constr | 
  • Method
  • diff --git a/docs/acf-core/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html b/docs/acf-core/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html index 4a710f36..a81df28f 100644 --- a/docs/acf-core/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html +++ b/docs/acf-core/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html @@ -102,7 +102,7 @@

    -
    public static interface CommandCompletions.AsyncCommandCompletionHandler<C extends CommandCompletionContext>
    +
    public static interface CommandCompletions.AsyncCommandCompletionHandler<C extends CommandCompletionContext>
     extends CommandCompletions.CommandCompletionHandler<C>
    diff --git a/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html b/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html index 58bd6044..a6259302 100644 --- a/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html +++ b/docs/acf-core/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";

    -
    public static interface CommandCompletions.CommandCompletionHandler<C extends CommandCompletionContext>
    +
    public static interface CommandCompletions.CommandCompletionHandler<C extends CommandCompletionContext>
    @@ -154,7 +154,7 @@ var activeTableTab = "activeTableTab"; diff --git a/docs/acf-core/co/aikar/commands/CommandCompletions.html b/docs/acf-core/co/aikar/commands/CommandCompletions.html index 36f63c01..254def86 100644 --- a/docs/acf-core/co/aikar/commands/CommandCompletions.html +++ b/docs/acf-core/co/aikar/commands/CommandCompletions.html @@ -18,7 +18,7 @@ catch(err) { } //--> -var methods = {"i0":10,"i1":10}; +var methods = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10}; var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]}; var altColor = "altColor"; var rowColor = "rowColor"; @@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";


  • -
    public class CommandCompletions<C extends CommandCompletionContext>
    +
    public class CommandCompletions<C extends CommandCompletionContext>
     extends Object
  • @@ -175,12 +175,44 @@ extends CommandCompletions.CommandCompletionHandler registerAsyncCompletion(String id, - CommandCompletions.AsyncCommandCompletionHandler<C> handler)  + CommandCompletions.AsyncCommandCompletionHandler<C> handler) +
    Registr a completion handler to provide command completions based on the user input.
    + CommandCompletions.CommandCompletionHandler registerCompletion(String id, - CommandCompletions.CommandCompletionHandler<C> handler)  + CommandCompletions.CommandCompletionHandler<C> handler) +
    Registr a completion handler to provide command completions based on the user input.
    + + + +CommandCompletions.CommandCompletionHandler +registerStaticCompletion(String id, + List<String> completions) +
    Register a static list of command completions that will never change
    + + + +CommandCompletions.CommandCompletionHandler +registerStaticCompletion(String id, + String list) +
    Register a static list of command completions that will never change.
    + + + +CommandCompletions.CommandCompletionHandler +registerStaticCompletion(String id, + String[] completions) +
    Register a static list of command completions that will never change
    + + + +CommandCompletions.CommandCompletionHandler +registerStaticCompletion(String id, + Supplier<List<String>> supplier) +
    Register a static list of command completions that will never change.
    + @@ -227,18 +259,112 @@ extends
  • registerCompletion

    -
    public CommandCompletions.CommandCompletionHandler registerCompletion(String id,
    +
    public CommandCompletions.CommandCompletionHandler registerCompletion(String id,
                                                                           CommandCompletions.CommandCompletionHandler<C> handler)
    +
    Registr a completion handler to provide command completions based on the user input.
    +
    +
    Parameters:
    +
    id -
    +
    handler -
    +
    Returns:
    +
  • - diff --git a/docs/acf-core/co/aikar/commands/annotation/CommandCompletion.html b/docs/acf-core/co/aikar/commands/annotation/CommandCompletion.html index 5e03aadd..621e8f7e 100644 --- a/docs/acf-core/co/aikar/commands/annotation/CommandCompletion.html +++ b/docs/acf-core/co/aikar/commands/annotation/CommandCompletion.html @@ -94,7 +94,17 @@
    @Retention(value=RUNTIME)
      @Target(value=METHOD)
    -public @interface CommandCompletion
    +public @interface CommandCompletion +
    Many implementation platforms have a concept of "Tab Completions", + where pressing tab will give suggestions on what you can input. + + This annotation specifies either static completion values, + or special @codes that let you define Completion Handlers to dynamically + populate completion values.
    +
    +
    See Also:
    +
    co.aikar.commands.CommandCompletions}
    +
    @@ -138,7 +148,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html b/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html index 35d9c4ca..15238881 100644 --- a/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html +++ b/docs/acf-core/co/aikar/commands/annotation/CommandPermission.html @@ -94,7 +94,10 @@
    @Retention(value=RUNTIME)
      @Target(value={METHOD,TYPE})
    -public @interface CommandPermission
    +public @interface CommandPermission +
    Sets the permission required to perform this command. + + Permission format will vary based on implementation platform
    @@ -138,7 +141,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/Conditions.html b/docs/acf-core/co/aikar/commands/annotation/Conditions.html index 1d0d6a5f..965c510d 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Conditions.html +++ b/docs/acf-core/co/aikar/commands/annotation/Conditions.html @@ -94,7 +94,15 @@
    @Retention(value=RUNTIME)
      @Target(value={METHOD,PARAMETER,TYPE})
    -public @interface Conditions
    +public @interface Conditions +
    Specifies conditions that must be met in order to execute this command. + + If used on a method or a class, will be checked before parameter context is resolved + If used on a parameter, will be checked after the context is resolved
    +
    +
    See Also:
    +
    co.aikar.commands.CommandConditions}
    +
    @@ -138,7 +146,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/Default.html b/docs/acf-core/co/aikar/commands/annotation/Default.html index cf7aa809..314477e0 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Default.html +++ b/docs/acf-core/co/aikar/commands/annotation/Default.html @@ -94,7 +94,9 @@
    @Retention(value=RUNTIME)
      @Target(value={METHOD,PARAMETER})
    -public @interface Default
    +public @interface Default +
    If used on a method, sets default command handler for the root command of this group + If used on a parameter, sets the value to be used for context resolution
    @@ -138,7 +140,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
    Default:
    ""
    diff --git a/docs/acf-core/co/aikar/commands/annotation/Dependency.html b/docs/acf-core/co/aikar/commands/annotation/Dependency.html index 5454b377..bff4eecf 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Dependency.html +++ b/docs/acf-core/co/aikar/commands/annotation/Dependency.html @@ -94,7 +94,9 @@
    @Retention(value=RUNTIME)
      @Target(value=FIELD)
    -public @interface Dependency
    +public @interface Dependency +
    Injects a dependency into the field this is attached to. + Any time a new dependency is registered, this will be overwritten.
  • @@ -140,7 +142,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
    The key that should be used to lookup the instances, defaults to \"\"
    Returns:
    diff --git a/docs/acf-core/co/aikar/commands/annotation/Description.html b/docs/acf-core/co/aikar/commands/annotation/Description.html index 79bc495d..dd5a173e 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Description.html +++ b/docs/acf-core/co/aikar/commands/annotation/Description.html @@ -94,7 +94,9 @@
    @Retention(value=RUNTIME)
      @Target(value={METHOD,PARAMETER})
    -public @interface Description
    +public @interface Description +
    Sets a description to the parameter or method this is attached to. + This is used in the help menus.
  • @@ -138,7 +140,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/Flags.html b/docs/acf-core/co/aikar/commands/annotation/Flags.html index 9ca76635..d8787373 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Flags.html +++ b/docs/acf-core/co/aikar/commands/annotation/Flags.html @@ -94,7 +94,12 @@
    @Retention(value=RUNTIME)
      @Target(value=PARAMETER)
    -public @interface Flags
    +public @interface Flags +
    Provides configuration options for ContextResolver's to change how they resolve context. + + Example: Searching for a player, you might use @Flags("loose") to indicate a fuzzy match instead of an exact match. + + If you want to restrict if an issuer can use the command, please use CommandConditions.Condition instead.
    @@ -138,7 +143,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/HelpCommand.html b/docs/acf-core/co/aikar/commands/annotation/HelpCommand.html index 5aa4e920..edadc3e6 100644 --- a/docs/acf-core/co/aikar/commands/annotation/HelpCommand.html +++ b/docs/acf-core/co/aikar/commands/annotation/HelpCommand.html @@ -94,7 +94,11 @@
    @Retention(value=RUNTIME)
      @Target(value=METHOD)
    -public @interface HelpCommand
    +public @interface HelpCommand +
    A Shortcut for specifying CatchUnknown, Default and Subcommand on a method. + Subcommand carries the same value as this annotations value to define the list of subcommands to register for. + + a method marked with this annotation should also use a CommandHelp context parameter to show help.
    @@ -115,7 +119,9 @@ public @interface String -value  +value +
    The value to forward to the @Subcommand annotation.
    + @@ -138,7 +144,11 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
    +
    The value to forward to the @Subcommand annotation. Lists which subcommands to register to trigger help
    +
    +
    Returns:
    +
    Default:
    "help|?|-help|-h|-?"
    diff --git a/docs/acf-core/co/aikar/commands/annotation/HelpSearchTags.html b/docs/acf-core/co/aikar/commands/annotation/HelpSearchTags.html index c76fa70a..b760f92e 100644 --- a/docs/acf-core/co/aikar/commands/annotation/HelpSearchTags.html +++ b/docs/acf-core/co/aikar/commands/annotation/HelpSearchTags.html @@ -94,7 +94,11 @@
    @Retention(value=RUNTIME)
      @Target(value=METHOD)
    -public @interface HelpSearchTags
    +public @interface HelpSearchTags +
    Defines additional keywords to feed into the search help system. + + For example, if a specific word doesn't make sense to use in the command name or description, but should + be used for help in discovering the correct command, then you can add it as a tag.
  • @@ -138,7 +142,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/Optional.html b/docs/acf-core/co/aikar/commands/annotation/Optional.html index 7fd9d3e3..cb693b74 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Optional.html +++ b/docs/acf-core/co/aikar/commands/annotation/Optional.html @@ -94,7 +94,12 @@
    @Retention(value=RUNTIME)
      @Target(value=PARAMETER)
    -public @interface Optional
    +public @interface Optional +
    Marks the parameter this is attached to as optional. + This will set the parameter as null if it was not provided. +

    + In the case the language used is Kotlin, Ceylon or any other null-enforcing JVM language, + you will need to allow for a nullable value.

    diff --git a/docs/acf-core/co/aikar/commands/annotation/PreCommand.html b/docs/acf-core/co/aikar/commands/annotation/PreCommand.html index dd9d1fd0..1b98a167 100644 --- a/docs/acf-core/co/aikar/commands/annotation/PreCommand.html +++ b/docs/acf-core/co/aikar/commands/annotation/PreCommand.html @@ -94,7 +94,8 @@
    @Retention(value=RUNTIME)
      @Target(value=METHOD)
    -public @interface PreCommand
    +public @interface PreCommand +
    This runs before any other command method each time it is invoked.
    diff --git a/docs/acf-core/co/aikar/commands/annotation/Single.html b/docs/acf-core/co/aikar/commands/annotation/Single.html index baa6e5e2..1cc4b6f6 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Single.html +++ b/docs/acf-core/co/aikar/commands/annotation/Single.html @@ -94,8 +94,8 @@
    @Retention(value=RUNTIME)
      @Target(value=PARAMETER)
    -public @interface Single
    -
    Don't join remaining arguments
    +public @interface Single +
    Don't join remaining arguments. Used on String parameters, which normally would combine the remaining arguments
    diff --git a/docs/acf-core/co/aikar/commands/annotation/Split.html b/docs/acf-core/co/aikar/commands/annotation/Split.html index 38af2114..3c043c0f 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Split.html +++ b/docs/acf-core/co/aikar/commands/annotation/Split.html @@ -94,7 +94,9 @@
    @Retention(value=RUNTIME)
      @Target(value=PARAMETER)
    -public @interface Split
    +public @interface Split +
    Joins arguments into a single piece of text with the specified separator. + For array based parameters, defines the regex pattern to split on
    @@ -138,7 +140,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
    Default:
    ","
    diff --git a/docs/acf-core/co/aikar/commands/annotation/Subcommand.html b/docs/acf-core/co/aikar/commands/annotation/Subcommand.html index 87691509..254c5d05 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Subcommand.html +++ b/docs/acf-core/co/aikar/commands/annotation/Subcommand.html @@ -94,7 +94,12 @@
    @Retention(value=RUNTIME)
      @Target(value={METHOD,TYPE})
    -public @interface Subcommand
    +public @interface Subcommand +
    Defines the subcommand that can be used to execute this command. + This is appended onto the root command for the command group, + as well as any parent command groups subcommand base. + + Defines the part after root command like so: "/rootcommand value()".
  • @@ -138,7 +143,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/Syntax.html b/docs/acf-core/co/aikar/commands/annotation/Syntax.html index 676dd84d..c64504c9 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Syntax.html +++ b/docs/acf-core/co/aikar/commands/annotation/Syntax.html @@ -94,7 +94,14 @@
    @Retention(value=RUNTIME)
      @Target(value={METHOD,PARAMETER})
    -public @interface Syntax
    +public @interface Syntax +
    Specifies the syntax to be used when executing this command. + It should not include any descriptions of the arguments nor when some are allowed and when they are not. + + Use of this annotation is not necessary. Syntax will be automatically generated for you. + Use this annotation to override automatic syntax + + Use Description together with the help menu for that purpose.
    @@ -138,7 +145,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/Values.html b/docs/acf-core/co/aikar/commands/annotation/Values.html index a8e7670d..804ad081 100644 --- a/docs/acf-core/co/aikar/commands/annotation/Values.html +++ b/docs/acf-core/co/aikar/commands/annotation/Values.html @@ -94,7 +94,10 @@
    @Retention(value=RUNTIME)
      @Target(value=PARAMETER)
    -public @interface Values
    +public @interface Values +
    Specifies a list of values that the command input should be validated against, or else show an error. + + You may also use CommandCompletion handler codes here to feed dynamic values and avoid repetition.
    @@ -138,7 +141,7 @@ public @interface
  • value

    -
    public abstract String value
    +
    public abstract String value
  • diff --git a/docs/acf-core/co/aikar/commands/annotation/package-summary.html b/docs/acf-core/co/aikar/commands/annotation/package-summary.html index 63a185bf..a6e8a2c8 100644 --- a/docs/acf-core/co/aikar/commands/annotation/package-summary.html +++ b/docs/acf-core/co/aikar/commands/annotation/package-summary.html @@ -89,55 +89,83 @@ CatchUnknown -  + +
    Defines a method that should receive any unknown command for the related root command.
    + CommandAlias -  + +
    Allows to add a single or several command alias(es).
    + CommandCompletion -  + +
    Many implementation platforms have a concept of "Tab Completions", + where pressing tab will give suggestions on what you can input.
    + CommandPermission -  + +
    Sets the permission required to perform this command.
    + Conditions -  + +
    Specifies conditions that must be met in order to execute this command.
    + Default -  + +
    If used on a method, sets default command handler for the root command of this group + If used on a parameter, sets the value to be used for context resolution
    + Dependency -  + +
    Injects a dependency into the field this is attached to.
    + Description -  + +
    Sets a description to the parameter or method this is attached to.
    + Flags -  + +
    Provides configuration options for ContextResolver's to change how they resolve context.
    + HelpCommand -  + +
    A Shortcut for specifying CatchUnknown, Default and Subcommand on a method.
    + HelpSearchTags -  + +
    Defines additional keywords to feed into the search help system.
    + Optional -  + +
    Marks the parameter this is attached to as optional.
    + PreCommand -  + +
    This runs before any other command method each time it is invoked.
    + Private @@ -148,20 +176,26 @@ Single -
    Don't join remaining arguments
    +
    Don't join remaining arguments.
    Split -  + +
    Joins arguments into a single piece of text with the specified separator.
    + Subcommand -  + +
    Defines the subcommand that can be used to execute this command.
    + Syntax -  + +
    Specifies the syntax to be used when executing this command.
    + UnknownHandler @@ -171,7 +205,9 @@ Values -  + +
    Specifies a list of values that the command input should be validated against, or else show an error.
    + diff --git a/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.AsyncCommandCompletionHandler.html b/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.AsyncCommandCompletionHandler.html index 469995ad..d3792e5a 100644 --- a/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.AsyncCommandCompletionHandler.html +++ b/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.AsyncCommandCompletionHandler.html @@ -104,7 +104,9 @@ CommandCompletions.CommandCompletionHandler CommandCompletions.registerAsyncCompletion(String id, - CommandCompletions.AsyncCommandCompletionHandler<C> handler)  + CommandCompletions.AsyncCommandCompletionHandler<C> handler) +
    Registr a completion handler to provide command completions based on the user input.
    + diff --git a/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.CommandCompletionHandler.html b/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.CommandCompletionHandler.html index 45c2d09b..085c3daa 100644 --- a/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.CommandCompletionHandler.html +++ b/docs/acf-core/co/aikar/commands/class-use/CommandCompletions.CommandCompletionHandler.html @@ -117,12 +117,44 @@ CommandCompletions.CommandCompletionHandler CommandCompletions.registerAsyncCompletion(String id, - CommandCompletions.AsyncCommandCompletionHandler<C> handler)  + CommandCompletions.AsyncCommandCompletionHandler<C> handler) +
    Registr a completion handler to provide command completions based on the user input.
    + CommandCompletions.CommandCompletionHandler CommandCompletions.registerCompletion(String id, - CommandCompletions.CommandCompletionHandler<C> handler)  + CommandCompletions.CommandCompletionHandler<C> handler) +
    Registr a completion handler to provide command completions based on the user input.
    + + + +CommandCompletions.CommandCompletionHandler +CommandCompletions.registerStaticCompletion(String id, + List<String> completions) +
    Register a static list of command completions that will never change
    + + + +CommandCompletions.CommandCompletionHandler +CommandCompletions.registerStaticCompletion(String id, + String list) +
    Register a static list of command completions that will never change.
    + + + +CommandCompletions.CommandCompletionHandler +CommandCompletions.registerStaticCompletion(String id, + String[] completions) +
    Register a static list of command completions that will never change
    + + + +CommandCompletions.CommandCompletionHandler +CommandCompletions.registerStaticCompletion(String id, + Supplier<List<String>> supplier) +
    Register a static list of command completions that will never change.
    + @@ -136,7 +168,9 @@ CommandCompletions.CommandCompletionHandler CommandCompletions.registerCompletion(String id, - CommandCompletions.CommandCompletionHandler<C> handler)  + CommandCompletions.CommandCompletionHandler<C> handler) +
    Registr a completion handler to provide command completions based on the user input.
    + diff --git a/docs/acf-core/co/aikar/commands/class-use/CommandExecutionContext.html b/docs/acf-core/co/aikar/commands/class-use/CommandExecutionContext.html index bb695cc9..e3cfdbe1 100644 --- a/docs/acf-core/co/aikar/commands/class-use/CommandExecutionContext.html +++ b/docs/acf-core/co/aikar/commands/class-use/CommandExecutionContext.html @@ -193,7 +193,9 @@ interface  -ContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>>  +ContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> +
    This defines a context resolver, which parses T from C.
    + interface  @@ -208,7 +210,7 @@ interface  OptionalContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> -
    Context Resolver that can accept null input
    +
    The same as ContextResolver, however it can accept a null context.
    diff --git a/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html b/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html index 8a90ba9b..499beed6 100644 --- a/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html +++ b/docs/acf-core/co/aikar/commands/class-use/CommandIssuer.html @@ -183,7 +183,9 @@ CommandIssuer -BaseCommand.getCurrentCommandIssuer()  +BaseCommand.getCurrentCommandIssuer() +
    Gets the current command issuer.
    + static CommandIssuer @@ -209,7 +211,11 @@ boolean BaseCommand.canExecute(CommandIssuer issuer, - RegisteredCommand<?> cmd)  + RegisteredCommand<?> cmd) +
    Deprecated.  + +
    + abstract CommandExecutionContext @@ -403,7 +409,9 @@ List<String> BaseCommand.tabComplete(CommandIssuer issuer, String commandLabel, - String[] args)  + String[] args) +
    Gets tab completed data from the given command from the user.
    + List<String> @@ -416,7 +424,9 @@ BaseCommand.tabComplete(CommandIssuer issuer, String commandLabel, String[] args, - boolean isAsync)  + boolean isAsync) +
    Gets the tab complete suggestions from a given command.
    + @@ -447,7 +457,9 @@ interface  -ContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>>  +ContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> +
    This defines a context resolver, which parses T from C.
    + interface  @@ -462,7 +474,7 @@ interface  OptionalContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> -
    Context Resolver that can accept null input
    +
    The same as ContextResolver, however it can accept a null context.
    diff --git a/docs/acf-core/co/aikar/commands/class-use/CommandManager.html b/docs/acf-core/co/aikar/commands/class-use/CommandManager.html index 8ed9a26b..aab73e9f 100644 --- a/docs/acf-core/co/aikar/commands/class-use/CommandManager.html +++ b/docs/acf-core/co/aikar/commands/class-use/CommandManager.html @@ -120,7 +120,9 @@ CommandManager -BaseCommand.getCurrentCommandManager()  +BaseCommand.getCurrentCommandManager() +
    Gets the current command manager.
    + static CommandManager diff --git a/docs/acf-core/co/aikar/commands/class-use/InvalidCommandArgument.html b/docs/acf-core/co/aikar/commands/class-use/InvalidCommandArgument.html index 46c7849d..a8e6f83a 100644 --- a/docs/acf-core/co/aikar/commands/class-use/InvalidCommandArgument.html +++ b/docs/acf-core/co/aikar/commands/class-use/InvalidCommandArgument.html @@ -161,7 +161,9 @@ T -ContextResolver.getContext(C c)  +ContextResolver.getContext(C c) +
    Parses the context of type C into T, or throws an exception.
    + diff --git a/docs/acf-core/co/aikar/commands/class-use/RegisteredCommand.html b/docs/acf-core/co/aikar/commands/class-use/RegisteredCommand.html index d7684d14..c99b3f2a 100644 --- a/docs/acf-core/co/aikar/commands/class-use/RegisteredCommand.html +++ b/docs/acf-core/co/aikar/commands/class-use/RegisteredCommand.html @@ -132,7 +132,11 @@ boolean BaseCommand.canExecute(CommandIssuer issuer, - RegisteredCommand<?> cmd)  + RegisteredCommand<?> cmd) +
    Deprecated.  + +
    + abstract CommandExecutionContext diff --git a/docs/acf-core/co/aikar/commands/contexts/ContextResolver.html b/docs/acf-core/co/aikar/commands/contexts/ContextResolver.html index d25e115c..c9d7bd87 100644 --- a/docs/acf-core/co/aikar/commands/contexts/ContextResolver.html +++ b/docs/acf-core/co/aikar/commands/contexts/ContextResolver.html @@ -99,6 +99,11 @@ var activeTableTab = "activeTableTab"; @@ -130,7 +136,9 @@ public interface T -getContext(C c)  +getContext(C c) +
    Parses the context of type C into T, or throws an exception.
    + @@ -155,11 +163,16 @@ public interface
  • getContext

    -
    T getContext(C c)
    +
    T getContext(C c)
           throws InvalidCommandArgument
    +
    Parses the context of type C into T, or throws an exception.
    +
    Parameters:
    +
    c - The context to parse from.
    +
    Returns:
    +
    The parsed instance of the wanted type.
    Throws:
    -
    InvalidCommandArgument
    +
    InvalidCommandArgument - In case the context contains any discrepancies, it will throw this exception.
  • diff --git a/docs/acf-core/co/aikar/commands/contexts/OptionalContextResolver.html b/docs/acf-core/co/aikar/commands/contexts/OptionalContextResolver.html index d5fcfd88..cf3611ab 100644 --- a/docs/acf-core/co/aikar/commands/contexts/OptionalContextResolver.html +++ b/docs/acf-core/co/aikar/commands/contexts/OptionalContextResolver.html @@ -93,14 +93,21 @@ diff --git a/docs/acf-core/co/aikar/commands/contexts/class-use/ContextResolver.html b/docs/acf-core/co/aikar/commands/contexts/class-use/ContextResolver.html index 5c3b41d8..5a5c5344 100644 --- a/docs/acf-core/co/aikar/commands/contexts/class-use/ContextResolver.html +++ b/docs/acf-core/co/aikar/commands/contexts/class-use/ContextResolver.html @@ -173,7 +173,7 @@ interface  OptionalContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> -
    Context Resolver that can accept null input
    +
    The same as ContextResolver, however it can accept a null context.
    diff --git a/docs/acf-core/co/aikar/commands/contexts/package-summary.html b/docs/acf-core/co/aikar/commands/contexts/package-summary.html index 0d5bf672..4dd8996c 100644 --- a/docs/acf-core/co/aikar/commands/contexts/package-summary.html +++ b/docs/acf-core/co/aikar/commands/contexts/package-summary.html @@ -83,7 +83,9 @@ ContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> -  + +
    This defines a context resolver, which parses T from C.
    + IssuerAwareContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> @@ -98,7 +100,7 @@ OptionalContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> -
    Context Resolver that can accept null input
    +
    The same as ContextResolver, however it can accept a null context.
    diff --git a/docs/acf-core/co/aikar/commands/contexts/package-use.html b/docs/acf-core/co/aikar/commands/contexts/package-use.html index db01ec0b..9889a3dd 100644 --- a/docs/acf-core/co/aikar/commands/contexts/package-use.html +++ b/docs/acf-core/co/aikar/commands/contexts/package-use.html @@ -102,7 +102,9 @@ -ContextResolver  +ContextResolver +
    This defines a context resolver, which parses T from C.
    + IssuerAwareContextResolver  @@ -114,7 +116,7 @@ OptionalContextResolver -
    Context Resolver that can accept null input
    +
    The same as ContextResolver, however it can accept a null context.
    @@ -130,7 +132,9 @@ -ContextResolver  +ContextResolver +
    This defines a context resolver, which parses T from C.
    + IssuerAwareContextResolver  diff --git a/docs/acf-core/co/aikar/commands/package-summary.html b/docs/acf-core/co/aikar/commands/package-summary.html index b2d0cb31..3047b26e 100644 --- a/docs/acf-core/co/aikar/commands/package-summary.html +++ b/docs/acf-core/co/aikar/commands/package-summary.html @@ -132,7 +132,9 @@ BaseCommand -  + +
    A Base command is defined as a command group of related commands.
    + CommandCompletionContext<I extends CommandIssuer> diff --git a/docs/acf-core/co/aikar/commands/package-use.html b/docs/acf-core/co/aikar/commands/package-use.html index 57eae770..4f3ea1b8 100644 --- a/docs/acf-core/co/aikar/commands/package-use.html +++ b/docs/acf-core/co/aikar/commands/package-use.html @@ -106,7 +106,9 @@ -BaseCommand  +BaseCommand +
    A Base command is defined as a command group of related commands.
    + CommandCompletionContext  diff --git a/docs/acf-core/constant-values.html b/docs/acf-core/constant-values.html index 3e65ee8f..93621473 100644 --- a/docs/acf-core/constant-values.html +++ b/docs/acf-core/constant-values.html @@ -82,34 +82,6 @@ - + + + +
    diff --git a/docs/acf-core/index-all.html b/docs/acf-core/index-all.html index 04ea61e3..77e33250 100644 --- a/docs/acf-core/index-all.html +++ b/docs/acf-core/index-all.html @@ -153,11 +153,17 @@

    B

    BaseCommand - Class in co.aikar.commands
    -
     
    +
    +
    A Base command is defined as a command group of related commands.
    +
    BaseCommand() - Constructor for class co.aikar.commands.BaseCommand
     
    BaseCommand(String) - Constructor for class co.aikar.commands.BaseCommand
    -
     
    +
    +
    Deprecated. +
    Please switch to CommandAlias for defining all root commands.
    +
    +
    BULGARIAN - Static variable in class co.aikar.commands.Locales
     
    @@ -169,7 +175,11 @@
    canConsumeInput() - Method in class co.aikar.commands.CommandParameter
     
    canExecute(CommandIssuer, RegisteredCommand<?>) - Method in class co.aikar.commands.BaseCommand
    -
     
    +
    +
    Deprecated. + +
    +
    canOverridePlayerContext() - Method in class co.aikar.commands.CommandExecutionContext
     
    capitalize(String, char[]) - Static method in class co.aikar.commands.ACFUtil
    @@ -205,9 +215,9 @@
    CatchUnknown - Annotation Type in co.aikar.commands.annotation
    -
     
    -
    CATCHUNKNOWN - Static variable in class co.aikar.commands.BaseCommand
    -
     
    +
    +
    Defines a method that should receive any unknown command for the related root command.
    +
    CHINESE - Static variable in class co.aikar.commands.Locales
     
    clone(T[]) - Static method in class co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil
    @@ -230,9 +240,14 @@
    combine(String[], int) - Static method in class co.aikar.commands.ACFUtil
     
    CommandAlias - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Allows to add a single or several command alias(es).
    +
    CommandCompletion - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Many implementation platforms have a concept of "Tab Completions", + where pressing tab will give suggestions on what you can input.
    +
    CommandCompletionContext<I extends CommandIssuer> - Class in co.aikar.commands
     
    CommandCompletions<C extends CommandCompletionContext> - Class in co.aikar.commands
    @@ -278,7 +293,9 @@
    CommandParameter(RegisteredCommand<CEC>, Parameter, int) - Constructor for class co.aikar.commands.CommandParameter
     
    CommandPermission - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Sets the permission required to perform this command.
    +
    CommandReplacements - Class in co.aikar.commands
    Manages replacement template strings
    @@ -296,7 +313,9 @@
    ConditionFailedException(String) - Constructor for exception co.aikar.commands.ConditionFailedException
     
    Conditions - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Specifies conditions that must be met in order to execute this command.
    +
    conditions - Variable in class co.aikar.commands.CommandManager
     
    ConditionsProcessor - Class in co.aikar.commands.processors
    @@ -310,7 +329,9 @@
    contextMap - Variable in class co.aikar.commands.CommandContexts
     
    ContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> - Interface in co.aikar.commands.contexts
    -
     
    +
    +
    This defines a context resolver, which parses T from C.
    +
    createCommandContext(RegisteredCommand, CommandParameter, CommandIssuer, List<String>, int, Map<String, Object>) - Method in class co.aikar.commands.CommandManager
     
    createCompletionContext(RegisteredCommand, CommandIssuer, String, String, String[]) - Method in class co.aikar.commands.CommandManager
    @@ -332,9 +353,10 @@
    DANISH - Static variable in class co.aikar.commands.Locales
     
    Default - Annotation Type in co.aikar.commands.annotation
    -
     
    -
    DEFAULT - Static variable in class co.aikar.commands.BaseCommand
    -
     
    +
    +
    If used on a method, sets default command handler for the root command of this group + If used on a parameter, sets the value to be used for context resolution
    +
    defaultExceptionHandler - Variable in class co.aikar.commands.CommandManager
     
    defaultFormatter - Variable in class co.aikar.commands.CommandManager
    @@ -344,9 +366,13 @@
    dependencies - Variable in class co.aikar.commands.CommandManager
     
    Dependency - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Injects a dependency into the field this is attached to.
    +
    Description - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Sets a description to the parameter or method this is attached to.
    +
    doHelp(Object, String...) - Method in class co.aikar.commands.BaseCommand
     
    doHelp(CommandIssuer, String...) - Method in class co.aikar.commands.BaseCommand
    @@ -403,7 +429,9 @@
    FINNISH - Static variable in class co.aikar.commands.Locales
     
    Flags - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Provides configuration options for ContextResolver's to change how they resolve context.
    +
    format(int, String) - Method in class co.aikar.commands.MessageFormatter
     
    format(String) - Method in class co.aikar.commands.MessageFormatter
    @@ -561,7 +589,9 @@
    getConfigValue(String, Integer) - Method in class co.aikar.commands.ConditionContext
     
    getContext(C) - Method in interface co.aikar.commands.contexts.ContextResolver
    -
     
    +
    +
    Parses the context of type C into T, or throws an exception.
    +
    getContextFlags(Class<?>) - Method in class co.aikar.commands.BaseCommand
     
    getContextValue(Class<? extends T>) - Method in class co.aikar.commands.CommandCompletionContext
    @@ -569,11 +599,15 @@
    getContextValue(Class<? extends T>, Integer) - Method in class co.aikar.commands.CommandCompletionContext
     
    getCurrentCommandIssuer() - Method in class co.aikar.commands.BaseCommand
    -
     
    +
    +
    Gets the current command issuer.
    +
    getCurrentCommandIssuer() - Static method in class co.aikar.commands.CommandManager
     
    getCurrentCommandManager() - Method in class co.aikar.commands.BaseCommand
    -
     
    +
    +
    Gets the current command manager.
    +
    getCurrentCommandManager() - Static method in class co.aikar.commands.CommandManager
     
    getCurrentCommandOperationContext() - Static method in class co.aikar.commands.CommandManager
    @@ -883,13 +917,17 @@
    HELP - Static variable in class co.aikar.commands.MessageType
     
    HelpCommand - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    A Shortcut for specifying CatchUnknown, Default and Subcommand on a method.
    +
    HelpEntry - Class in co.aikar.commands
     
    helpFormatter - Variable in class co.aikar.commands.CommandManager
     
    HelpSearchTags - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Defines additional keywords to feed into the search help system.
    +
    helpSearchTags - Variable in class co.aikar.commands.RegisteredCommand
     
    HINDI - Static variable in class co.aikar.commands.Locales
    @@ -1310,10 +1348,12 @@
    Deprecated.
     
    Optional - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Marks the parameter this is attached to as optional.
    +
    OptionalContextResolver<T,C extends CommandExecutionContext<?,? extends CommandIssuer>> - Interface in co.aikar.commands.contexts
    -
    Context Resolver that can accept null input
    +
    The same as ContextResolver, however it can accept a null context.
    @@ -1358,7 +1398,9 @@
    precision(double, int) - Static method in class co.aikar.commands.ACFUtil
     
    PreCommand - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    This runs before any other command method each time it is invoked.
    +
    preCommand() - Method in class co.aikar.commands.RegisteredCommand
     
    printDetailedHelpCommand(CommandHelp, CommandIssuer, HelpEntry) - Method in class co.aikar.commands.CommandHelpFormatter
    @@ -1428,13 +1470,17 @@
    Deprecated.
    registerAsyncCompletion(String, CommandCompletions.AsyncCommandCompletionHandler<C>) - Method in class co.aikar.commands.CommandCompletions
    -
     
    +
    +
    Registr a completion handler to provide command completions based on the user input.
    +
    registerCommand(BaseCommand) - Method in class co.aikar.commands.CommandManager
    Registers a command with ACF
    registerCompletion(String, CommandCompletions.CommandCompletionHandler<C>) - Method in class co.aikar.commands.CommandCompletions
    -
     
    +
    +
    Registr a completion handler to provide command completions based on the user input.
    +
    registerContext(Class<T>, ContextResolver<T, R>) - Method in class co.aikar.commands.CommandContexts
    Registers a context that requires input from the command issuer to resolve.
    @@ -1473,6 +1519,22 @@ as the core wants to use the platform agnostic term of "Issuer" instead of Sender
    +
    registerStaticCompletion(String, String) - Method in class co.aikar.commands.CommandCompletions
    +
    +
    Register a static list of command completions that will never change.
    +
    +
    registerStaticCompletion(String, String[]) - Method in class co.aikar.commands.CommandCompletions
    +
    +
    Register a static list of command completions that will never change
    +
    +
    registerStaticCompletion(String, Supplier<List<String>>) - Method in class co.aikar.commands.CommandCompletions
    +
    +
    Register a static list of command completions that will never change.
    +
    +
    registerStaticCompletion(String, List<String>) - Method in class co.aikar.commands.CommandCompletions
    +
    +
    Register a static list of command completions that will never change
    +
    removeCauseMethodName(String) - Static method in class co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil
    Removes from the list of method names used in the search for Throwable @@ -1681,14 +1743,16 @@
     
    Single - Annotation Type in co.aikar.commands.annotation
    -
    Don't join remaining arguments
    +
    Don't join remaining arguments.
    sneaky(Throwable) - Static method in class co.aikar.commands.ACFUtil
     
    SPANISH - Static variable in class co.aikar.commands.Locales
     
    Split - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Joins arguments into a single piece of text with the specified separator.
    +
    startsWith(CharSequence, CharSequence) - Static method in class co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil
    Check if a CharSequence starts with a specified prefix.
    @@ -1698,7 +1762,9 @@
    Case insensitive check if a CharSequence starts with a specified prefix.
    Subcommand - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Defines the subcommand that can be used to execute this command.
    +
    supportedLanguages - Variable in class co.aikar.commands.CommandManager
     
    SWEDISH - Static variable in class co.aikar.commands.Locales
    @@ -1706,7 +1772,9 @@
    SyncCompletionRequired() - Constructor for exception co.aikar.commands.CommandCompletions.SyncCompletionRequired
     
    Syntax - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Specifies the syntax to be used when executing this command.
    +
    SYNTAX - Static variable in class co.aikar.commands.MessageType
     
    @@ -1716,9 +1784,13 @@

    T

    tabComplete(CommandIssuer, String, String[]) - Method in class co.aikar.commands.BaseCommand
    -
     
    +
    +
    Gets tab completed data from the given command from the user.
    +
    tabComplete(CommandIssuer, String, String[], boolean) - Method in class co.aikar.commands.BaseCommand
    -
     
    +
    +
    Gets the tab complete suggestions from a given command.
    +
    tabComplete(CommandIssuer, String, String[]) - Method in class co.aikar.commands.ForwardingCommand
     
    THAI - Static variable in class co.aikar.commands.Locales
    @@ -1775,7 +1847,9 @@
    Returns the enum constant of this type with the specified name.
    Values - Annotation Type in co.aikar.commands.annotation
    -
     
    +
    +
    Specifies a list of values that the command input should be validated against, or else show an error.
    +
    values() - Static method in enum co.aikar.commands.MessageKeys
    Returns an array containing the constants of this enum type, in 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 79192c88..8b4254ff 100644 --- a/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/BaseCommand.html @@ -50,660 +50,970 @@ 042import com.google.common.collect.Maps; 043import com.google.common.collect.SetMultimap; 044import com.google.common.collect.Sets; -045 -046import java.lang.reflect.Constructor; -047import java.lang.reflect.InvocationTargetException; -048import java.lang.reflect.Method; -049import java.lang.reflect.Parameter; -050import java.util.ArrayList; -051import java.util.Arrays; -052import java.util.Collections; -053import java.util.HashMap; -054import java.util.HashSet; -055import java.util.List; -056import java.util.Map; -057import java.util.Objects; -058import java.util.Optional; -059import java.util.Set; -060import java.util.Stack; -061import java.util.stream.Collectors; -062import java.util.stream.Stream; -063 -064@SuppressWarnings("unused") -065public abstract class BaseCommand { -066 -067 public static final String CATCHUNKNOWN = "__catchunknown"; -068 public static final String DEFAULT = "__default"; -069 final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create(); -070 final Map<Class<?>, String> contextFlags = Maps.newHashMap(); -071 private Method preCommandHandler; -072 -073 @SuppressWarnings("WeakerAccess") -074 private String execLabel; -075 @SuppressWarnings("WeakerAccess") -076 private String execSubcommand; -077 @SuppressWarnings("WeakerAccess") -078 private String[] origArgs; -079 CommandManager<?, ?, ?, ?, ?, ?> manager = null; -080 BaseCommand parentCommand; -081 Map<String, RootCommand> registeredCommands = new HashMap<>(); -082 String description; -083 String commandName; -084 String permission; -085 String conditions; -086 -087 private ExceptionHandler exceptionHandler = null; -088 CommandOperationContext lastCommandOperationContext; -089 private String parentSubcommand; -090 -091 public BaseCommand() {} -092 public BaseCommand(String cmd) { -093 this.commandName = cmd; -094 } -095 -096 /** -097 * Gets the root command name that the user actually typed -098 * @return Name -099 */ -100 public String getExecCommandLabel() { -101 return execLabel; -102 } -103 -104 /** -105 * Gets the actual sub command name the user typed -106 * @return Name +045import org.jetbrains.annotations.Nullable; +046 +047import java.lang.reflect.Constructor; +048import java.lang.reflect.InvocationTargetException; +049import java.lang.reflect.Method; +050import java.lang.reflect.Parameter; +051import java.util.ArrayList; +052import java.util.Arrays; +053import java.util.Collections; +054import java.util.HashMap; +055import java.util.HashSet; +056import java.util.List; +057import java.util.Map; +058import java.util.Objects; +059import java.util.Optional; +060import java.util.Set; +061import java.util.Stack; +062import java.util.stream.Collectors; +063import java.util.stream.Stream; +064 +065/** +066 * A Base command is defined as a command group of related commands. +067 * A BaseCommand does not imply nor enforce that they use the same root command. +068 * +069 * It is up to the end user how to organize their command. you could use 1 base command per +070 * command in your application. +071 * +072 * Optionally (and encouraged), you can use the base command to represent a root command, and +073 * then each actionable command is a sub command +074 */ +075 +076@SuppressWarnings("unused") +077public abstract class BaseCommand { +078 +079 /** +080 * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown +081 * argument to command states. +082 */ +083 static final String CATCHUNKNOWN = "__catchunknown"; +084 /** +085 * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the +086 * entire base command. +087 */ +088 static final String DEFAULT = "__default"; +089 +090 /** +091 * A map of all the registered commands for this base command, keyed to each potential subcommand to access it. +092 */ +093 final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create(); +094 +095 /** +096 * A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each. +097 */ +098 final Map<Class<?>, String> contextFlags = Maps.newHashMap(); +099 +100 /** +101 * What method was annoated with {@link PreCommand} to execute before commands. +102 */ +103 @Nullable private Method preCommandHandler; +104 +105 /** +106 * What root command the user actually entered to access the currently executing command 107 */ -108 public String getExecSubcommand() { -109 return execSubcommand; -110 } -111 -112 /** -113 * Gets the actual args in string form the user typed -114 * @return Args -115 */ -116 public String[] getOrigArgs() { -117 return origArgs; -118 } -119 -120 void setParentCommand(BaseCommand command) { -121 this.parentCommand = command; -122 } -123 void onRegister(CommandManager manager) { -124 onRegister(manager, this.commandName); -125 } -126 void onRegister(CommandManager manager, String cmd) { -127 manager.injectDependencies(this); -128 this.manager = manager; -129 -130 final Annotations annotations = manager.getAnnotations(); -131 final Class<? extends BaseCommand> self = this.getClass(); -132 -133 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); -134 -135 if (cmd == null && cmdAliases != null) { -136 cmd = cmdAliases[0]; -137 } -138 -139 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); -140 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); -141 this.description = this.commandName + " commands"; -142 this.parentSubcommand = getParentSubcommand(self); -143 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); -144 -145 registerSubcommands(); -146 -147 if (cmdAliases != null) { -148 Set<String> cmdList = new HashSet<>(); -149 Collections.addAll(cmdList, cmdAliases); -150 cmdList.remove(cmd); -151 for (String cmdAlias : cmdList) { -152 register(cmdAlias, this); -153 } -154 } -155 -156 if (cmd != null) { -157 register(cmd, this); -158 } -159 registerSubclasses(cmd); -160 -161 } -162 -163 private void registerSubclasses(String cmd) { -164 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { -165 if (BaseCommand.class.isAssignableFrom(clazz)) { -166 try { -167 BaseCommand subCommand = null; -168 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); -169 for (Constructor<?> declaredConstructor : declaredConstructors) { -170 -171 declaredConstructor.setAccessible(true); -172 Parameter[] parameters = declaredConstructor.getParameters(); -173 if (parameters.length == 1) { -174 subCommand = (BaseCommand) declaredConstructor.newInstance(this); -175 } else { -176 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); -177 } -178 } -179 if (subCommand != null) { -180 subCommand.setParentCommand(this); -181 subCommand.onRegister(manager, cmd); -182 this.subCommands.putAll(subCommand.subCommands); -183 this.registeredCommands.putAll(subCommand.registeredCommands); -184 } else { -185 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); -186 } -187 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { -188 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); -189 } -190 } -191 } -192 } -193 -194 private void registerSubcommands() { -195 final Annotations annotations = manager.getAnnotations(); -196 boolean foundDefault = false; -197 boolean foundCatchUnknown = false; -198 boolean isParentEmpty = parentSubcommand.isEmpty(); -199 -200 for (Method method : this.getClass().getMethods()) { -201 method.setAccessible(true); -202 String sublist = null; -203 String sub = getSubcommandValue(method); -204 final boolean def = annotations.hasAnnotation(method, Default.class); -205 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); -206 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); -207 -208 if (!isParentEmpty && def) { -209 sub = parentSubcommand; -210 } -211 if (isParentEmpty && (def || (!foundDefault && helpCommand != null))) { -212 if (!foundDefault) { -213 if (def) { -214 this.subCommands.get(DEFAULT).clear(); -215 foundDefault = true; -216 } -217 registerSubcommand(method, DEFAULT); -218 } else { -219 ACFUtil.sneaky(new IllegalStateException("Multiple @Default/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -220 } -221 } -222 -223 if (sub != null) { -224 sublist = sub; -225 } else if (commandAliases != null) { -226 sublist = commandAliases; -227 } else if (helpCommand != null) { -228 sublist = helpCommand; -229 } +108 @SuppressWarnings("WeakerAccess") +109 private String execLabel; +110 /** +111 * What subcommand the user actually entered to access the currently executing command +112 */ +113 @SuppressWarnings("WeakerAccess") +114 private String execSubcommand; +115 /** +116 * What arguments the user actually entered after the root command to access the currently executing command +117 */ +118 @SuppressWarnings("WeakerAccess") +119 private String[] origArgs; +120 +121 /** +122 * The manager this is registered to +123 */ +124 CommandManager<?, ?, ?, ?, ?, ?> manager = null; +125 +126 /** +127 * The command which owns this. This may be null if there are no owners. +128 */ +129 BaseCommand parentCommand; +130 Map<String, RootCommand> registeredCommands = new HashMap<>(); +131 /** +132 * The description of the command. This may be null if no description has been provided. +133 * Used for help documentation +134 */ +135 @Nullable String description; +136 /** +137 * The name of the command. This may be null if no name has been provided. +138 */ +139 @Nullable String commandName; +140 /** +141 * The permission of the command. This may be null if no permission has been provided. +142 */ +143 @Nullable String permission; +144 /** +145 * The conditions of the command. This may be null if no conditions has been provided. +146 */ +147 @Nullable String conditions; +148 +149 /** +150 * The handler of all uncaught exceptions thrown by the user's command implementation. +151 */ +152 private ExceptionHandler exceptionHandler = null; +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; +157 /** +158 * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this +159 */ +160 @Nullable private String parentSubcommand; +161 +162 public BaseCommand() {} +163 +164 /** +165 * Constructor based defining of commands will be removed in the next version bump. +166 * @deprecated Please switch to {@link CommandAlias} for defining all root commands. +167 * @param cmd +168 */ +169 @Deprecated +170 public BaseCommand(@Nullable String cmd) { +171 this.commandName = cmd; +172 } +173 +174 /** +175 * Gets the root command name that the user actually typed +176 * @return Name +177 */ +178 public String getExecCommandLabel() { +179 return execLabel; +180 } +181 +182 /** +183 * Gets the actual sub command name the user typed +184 * @return Name +185 */ +186 public String getExecSubcommand() { +187 return execSubcommand; +188 } +189 +190 /** +191 * Gets the actual args in string form the user typed +192 * @return Args +193 */ +194 public String[] getOrigArgs() { +195 return origArgs; +196 } +197 +198 /** +199 * This should be called whenever the command gets registered. +200 * It sets all required fields correctly and injects dependencies. +201 * +202 * @param manager +203 * The manager to register as this command's owner and handler. +204 */ +205 void onRegister(CommandManager manager) { +206 onRegister(manager, this.commandName); +207 } +208 +209 /** +210 * This should be called whenever the command gets registered. +211 * It sets all required fields correctly and injects dependencies. +212 * +213 * @param manager +214 * The manager to register as this command's owner and handler. +215 * @param cmd +216 * The command name to use register with. +217 */ +218 private void onRegister(CommandManager manager, String cmd) { +219 manager.injectDependencies(this); +220 this.manager = manager; +221 +222 final Annotations annotations = manager.getAnnotations(); +223 final Class<? extends BaseCommand> self = this.getClass(); +224 +225 String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY); +226 +227 if (cmd == null && cmdAliases != null) { +228 cmd = cmdAliases[0]; +229 } 230 -231 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); -232 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || -233 annotations.hasAnnotation(method, CatchAll.class) || -234 annotations.hasAnnotation(method, UnknownHandler.class); -235 -236 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { -237 if (!foundCatchUnknown) { -238 if (hasCatchUnknown) { -239 this.subCommands.get(CATCHUNKNOWN).clear(); -240 foundCatchUnknown = true; -241 } -242 registerSubcommand(method, CATCHUNKNOWN); -243 } else { -244 ACFUtil.sneaky(new IllegalStateException("Multiple @UnknownHandler/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -245 } -246 } else if (preCommand) { -247 if (this.preCommandHandler == null) { -248 this.preCommandHandler = method; -249 } else { -250 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); -251 } -252 } -253 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { -254 registerSubcommand(method, sublist); -255 } -256 } -257 } -258 -259 private String getSubcommandValue(Method method) { -260 final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); -261 if (sub == null) { -262 return null; -263 } -264 Class<?> clazz = method.getDeclaringClass(); -265 String parent = getParentSubcommand(clazz); -266 return parent == null || parent.isEmpty() ? sub : parent + " " + sub; -267 } +231 this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(); +232 this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS); +233 this.description = this.commandName + " commands"; +234 this.parentSubcommand = getParentSubcommand(self); +235 this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY); +236 +237 registerSubcommands(); +238 +239 if (cmdAliases != null) { +240 Set<String> cmdList = new HashSet<>(); +241 Collections.addAll(cmdList, cmdAliases); +242 cmdList.remove(cmd); +243 for (String cmdAlias : cmdList) { +244 register(cmdAlias, this); +245 } +246 } +247 +248 if (cmd != null) { +249 register(cmd, this); +250 } +251 registerSubclasses(cmd); +252 +253 } +254 +255 /** +256 * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. +257 * +258 * @param cmd +259 * The command name of this command. +260 */ +261 private void registerSubclasses(String cmd) { +262 for (Class<?> clazz : this.getClass().getDeclaredClasses()) { +263 if (BaseCommand.class.isAssignableFrom(clazz)) { +264 try { +265 BaseCommand subCommand = null; +266 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); +267 for (Constructor<?> declaredConstructor : declaredConstructors) { 268 -269 private String getParentSubcommand(Class<?> clazz) { -270 List<String> subList = new ArrayList<>(); -271 while (clazz != null) { -272 String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING); -273 if (sub != null) { -274 subList.add(sub); -275 } -276 clazz = clazz.getEnclosingClass(); -277 } -278 Collections.reverse(subList); -279 return ACFUtil.join(subList, " "); -280 } -281 -282 private void register(String name, BaseCommand cmd) { -283 String nameLower = name.toLowerCase(); -284 RootCommand rootCommand = manager.obtainRootCommand(nameLower); -285 rootCommand.addChild(cmd); -286 -287 this.registeredCommands.put(nameLower, rootCommand); -288 } -289 -290 private void registerSubcommand(Method method, String subCommand) { -291 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); -292 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); -293 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. -294 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); -295 -296 // Strip pipes off for auto complete addition -297 for (int i = 0; i < subCommandParts.length; i++) { -298 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); -299 if (split.length == 0 || split[0].isEmpty()) { -300 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); -301 } -302 subCommandParts[i] = split[0]; -303 } -304 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); -305 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); -306 -307 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; -308 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); -309 -310 for (String subcmd : cmdList) { -311 subCommands.put(subcmd, cmd); -312 } -313 cmd.addSubcommands(cmdList); -314 -315 if (aliasNames != null) { -316 for (String name : aliasNames) { -317 register(name, new ForwardingCommand(this, subCommandParts)); -318 } -319 } -320 } -321 -322 /** -323 * Takes a string like "foo|bar baz|qux" and generates a list of -324 * - foo baz -325 * - foo qux -326 * - bar baz -327 * - bar qux -328 * -329 * For every possible sub command combination -330 * -331 * @param subCommandParts -332 * @return List of all sub command possibilities -333 */ -334 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { -335 int i = 0; -336 Set<String> current = null; -337 while (true) { -338 Set<String> newList = new HashSet<>(); -339 -340 if (i < subCommandParts.length) { -341 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { -342 if (current != null) { -343 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); -344 } else { -345 newList.add(s1); -346 } -347 } -348 } -349 -350 if (i + 1 < subCommandParts.length) { -351 current = newList; -352 i = i + 1; -353 continue; -354 } -355 -356 return newList; +269 declaredConstructor.setAccessible(true); +270 Parameter[] parameters = declaredConstructor.getParameters(); +271 if (parameters.length == 1) { +272 subCommand = (BaseCommand) declaredConstructor.newInstance(this); +273 } else { +274 manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")"); +275 } +276 } +277 if (subCommand != null) { +278 subCommand.parentCommand = this; +279 subCommand.onRegister(manager, cmd); +280 this.subCommands.putAll(subCommand.subCommands); +281 this.registeredCommands.putAll(subCommand.registeredCommands); +282 } else { +283 this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName()); +284 } +285 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { +286 this.manager.log(LogLevel.ERROR, "Error registering subclass", e); +287 } +288 } +289 } +290 } +291 +292 /** +293 * This registers all subcommands of the command. +294 */ +295 private void registerSubcommands() { +296 final Annotations annotations = manager.getAnnotations(); +297 boolean foundDefault = false; +298 boolean foundCatchUnknown = false; +299 boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty(); +300 +301 for (Method method : this.getClass().getMethods()) { +302 method.setAccessible(true); +303 String sublist = null; +304 String sub = getSubcommandValue(method); +305 final boolean def = annotations.hasAnnotation(method, Default.class); +306 final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING); +307 final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING); +308 +309 if (!isParentEmpty && def) { +310 sub = parentSubcommand; +311 } +312 if (isParentEmpty && (def || (!foundDefault && helpCommand != null))) { +313 if (!foundDefault) { +314 if (def) { +315 this.subCommands.get(DEFAULT).clear(); +316 foundDefault = true; +317 } +318 registerSubcommand(method, DEFAULT); +319 } else { +320 ACFUtil.sneaky(new IllegalStateException("Multiple @Default/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +321 } +322 } +323 +324 if (sub != null) { +325 sublist = sub; +326 } else if (commandAliases != null) { +327 sublist = commandAliases; +328 } else if (helpCommand != null) { +329 sublist = helpCommand; +330 } +331 +332 boolean preCommand = annotations.hasAnnotation(method, PreCommand.class); +333 boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) || +334 annotations.hasAnnotation(method, CatchAll.class) || +335 annotations.hasAnnotation(method, UnknownHandler.class); +336 +337 if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) { +338 if (!foundCatchUnknown) { +339 if (hasCatchUnknown) { +340 this.subCommands.get(CATCHUNKNOWN).clear(); +341 foundCatchUnknown = true; +342 } +343 registerSubcommand(method, CATCHUNKNOWN); +344 } else { +345 ACFUtil.sneaky(new IllegalStateException("Multiple @UnknownHandler/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +346 } +347 } else if (preCommand) { +348 if (this.preCommandHandler == null) { +349 this.preCommandHandler = method; +350 } else { +351 ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName())); +352 } +353 } +354 if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) { +355 registerSubcommand(method, sublist); +356 } 357 } 358 } 359 -360 public void execute(CommandIssuer issuer, String commandLabel, String[] args) { -361 commandLabel = commandLabel.toLowerCase(); -362 try { -363 CommandOperationContext commandContext = preCommandOperation(issuer, commandLabel, args, false); -364 -365 if (args.length > 0) { -366 CommandSearch cmd = findSubCommand(args); -367 if (cmd != null) { -368 execSubcommand = cmd.getCheckSub(); -369 final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length); -370 executeCommand(commandContext, issuer, execargs, cmd.cmd); -371 return; -372 } -373 } -374 -375 if (subCommands.get(DEFAULT) != null && args.length == 0) { -376 executeSubcommand(commandContext, DEFAULT, issuer, args); -377 } else if (subCommands.get(CATCHUNKNOWN) != null) { -378 if (!executeSubcommand(commandContext, CATCHUNKNOWN, issuer, args)) { -379 help(issuer, args); -380 } -381 } else if (subCommands.get(DEFAULT) != null) { -382 executeSubcommand(commandContext, DEFAULT, issuer, args); -383 } -384 -385 } finally { -386 postCommandOperation(); -387 } -388 } -389 -390 RegisteredCommand<?> getRegisteredCommand(String[] args) { -391 final CommandSearch cmd = findSubCommand(args); -392 return cmd != null ? cmd.cmd : null; -393 } -394 -395 private void postCommandOperation() { -396 CommandManager.commandOperationContext.get().pop(); -397 execSubcommand = null; -398 execLabel = null; -399 origArgs = new String[]{}; -400 } -401 -402 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { -403 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); -404 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); -405 contexts.push(context); -406 lastCommandOperationContext = context; -407 execSubcommand = null; -408 execLabel = commandLabel; -409 origArgs = args; -410 return context; -411 } -412 -413 public CommandIssuer getCurrentCommandIssuer() { -414 return CommandManager.getCurrentCommandIssuer(); -415 } -416 public CommandManager getCurrentCommandManager() { -417 return CommandManager.getCurrentCommandManager(); -418 } -419 -420 private CommandSearch findSubCommand(String[] args) { -421 return findSubCommand(args, false); -422 } -423 private CommandSearch findSubCommand(String[] args, boolean completion) { -424 for (int i = args.length; i >= 0; i--) { -425 String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); -426 Set<RegisteredCommand> cmds = subCommands.get(checkSub); -427 -428 final int extraArgs = args.length - i; -429 if (!cmds.isEmpty()) { -430 RegisteredCommand cmd = null; -431 if (cmds.size() == 1) { -432 cmd = Iterables.getOnlyElement(cmds); -433 } else { -434 Optional<RegisteredCommand> optCmd = cmds.stream().filter(c -> { -435 int required = c.requiredResolvers; -436 int optional = c.optionalResolvers; -437 return extraArgs <= required + optional && (completion || extraArgs >= required); -438 }).sorted((c1, c2) -> { -439 int a = c1.consumeInputResolvers; -440 int b = c2.consumeInputResolvers; -441 -442 if (a == b) { -443 return 0; -444 } -445 return a < b ? 1 : -1; -446 }).findFirst(); -447 if (optCmd.isPresent()) { -448 cmd = optCmd.get(); -449 } -450 } -451 if (cmd != null) { -452 return new CommandSearch(cmd, i, checkSub); -453 } -454 } -455 } -456 return null; -457 } -458 -459 private void executeCommand(CommandOperationContext commandOperationContext, -460 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { -461 if (cmd.hasPermission(issuer)) { -462 commandOperationContext.setRegisteredCommand(cmd); -463 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { -464 return; -465 } -466 List<String> sargs = Lists.newArrayList(args); -467 cmd.invoke(issuer, sargs, commandOperationContext); -468 } else { -469 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); -470 } -471 } -472 -473 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { -474 return true; -475 } -476 -477 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { -478 return tabComplete(issuer, commandLabel, args, false); -479 } -480 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) -481 throws IllegalArgumentException { -482 -483 commandLabel = commandLabel.toLowerCase(); -484 if (args.length == 0) { -485 args = new String[]{""}; -486 } +360 /** +361 * Gets the subcommand name of the method given. +362 * +363 * @param method +364 * The method to check. +365 * +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 +395 * Name of the parent to cmd. +396 * @param cmd +397 * The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. +398 */ +399 private void register(String name, BaseCommand cmd) { +400 String nameLower = name.toLowerCase(); +401 RootCommand rootCommand = manager.obtainRootCommand(nameLower); +402 rootCommand.addChild(cmd); +403 +404 this.registeredCommands.put(nameLower, rootCommand); +405 } +406 +407 /** +408 * Registers the given {@link Method} as a subcommand. +409 * +410 * @param method +411 * The method to register as a subcommand. +412 * @param subCommand +413 * The subcommand's name(s). +414 */ +415 private void registerSubcommand(Method method, String subCommand) { +416 subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); +417 final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); +418 // Must run getSubcommandPossibility BEFORE we rewrite it just after this. +419 Set<String> cmdList = getSubCommandPossibilityList(subCommandParts); +420 +421 // Strip pipes off for auto complete addition +422 for (int i = 0; i < subCommandParts.length; i++) { +423 String[] split = ACFPatterns.PIPE.split(subCommandParts[i]); +424 if (split.length == 0 || split[0].isEmpty()) { +425 throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty"); +426 } +427 subCommandParts[i] = split[0]; +428 } +429 String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " "); +430 final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE); +431 +432 String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " "; +433 RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand); +434 +435 for (String subcmd : cmdList) { +436 subCommands.put(subcmd, cmd); +437 } +438 cmd.addSubcommands(cmdList); +439 +440 if (aliasNames != null) { +441 for (String name : aliasNames) { +442 register(name, new ForwardingCommand(this, subCommandParts)); +443 } +444 } +445 } +446 +447 /** +448 * Takes a string like "foo|bar baz|qux" and generates a list of +449 * - foo baz +450 * - foo qux +451 * - bar baz +452 * - bar qux +453 * +454 * For every possible sub command combination +455 * +456 * @param subCommandParts +457 * @return List of all sub command possibilities +458 */ +459 private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) { +460 int i = 0; +461 Set<String> current = null; +462 while (true) { +463 Set<String> newList = new HashSet<>(); +464 +465 if (i < subCommandParts.length) { +466 for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) { +467 if (current != null) { +468 newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList())); +469 } else { +470 newList.add(s1); +471 } +472 } +473 } +474 +475 if (i + 1 < subCommandParts.length) { +476 current = newList; +477 i = i + 1; +478 continue; +479 } +480 +481 return newList; +482 } +483 } +484 +485 public void execute(CommandIssuer issuer, String commandLabel, String[] args) { +486 commandLabel = commandLabel.toLowerCase(); 487 try { -488 CommandOperationContext commandOperationContext = preCommandOperation(issuer, commandLabel, args, isAsync); +488 CommandOperationContext commandContext = preCommandOperation(issuer, commandLabel, args, false); 489 -490 final CommandSearch search = findSubCommand(args, true); -491 -492 -493 final List<String> cmds = new ArrayList<>(); -494 -495 if (search != null) { -496 cmds.addAll(completeCommand(issuer, search.cmd, Arrays.copyOfRange(args, search.argIndex, args.length), commandLabel, isAsync)); -497 } else if (subCommands.get(CATCHUNKNOWN).size() == 1) { -498 cmds.addAll(completeCommand(issuer, Iterables.getOnlyElement(subCommands.get(CATCHUNKNOWN)), args, commandLabel, isAsync)); -499 } else if (subCommands.get(DEFAULT).size() == 1) { -500 cmds.addAll(completeCommand(issuer, Iterables.getOnlyElement(subCommands.get(DEFAULT)), args, commandLabel, isAsync)); -501 } -502 -503 return filterTabComplete(args[args.length - 1], cmds); -504 } finally { -505 postCommandOperation(); -506 } -507 } -508 -509 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { -510 final Set<String> cmds = new HashSet<>(); -511 final int cmdIndex = Math.max(0, args.length - 1); -512 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); -513 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { -514 final String key = entry.getKey(); -515 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { -516 final RegisteredCommand value = entry.getValue(); -517 if (!value.hasPermission(issuer) || value.isPrivate) { -518 continue; -519 } -520 -521 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); -522 cmds.add(split[cmdIndex]); -523 } -524 } -525 return new ArrayList<>(cmds); -526 } -527 -528 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { -529 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { -530 return ImmutableList.of(); -531 } -532 -533 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); -534 return filterTabComplete(args[args.length-1], cmds); -535 } -536 -537 private static List<String> filterTabComplete(String arg, List<String> cmds) { -538 return cmds.stream() -539 .distinct() -540 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) -541 .collect(Collectors.toList()); -542 } -543 -544 RegisteredCommand getSubcommand(String subcommand) { -545 return getSubcommand(subcommand, false); -546 } -547 -548 RegisteredCommand getSubcommand(String subcommand, boolean requireOne) { -549 final Set<RegisteredCommand> commands = subCommands.get(subcommand); -550 if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) { -551 return commands.iterator().next(); -552 } -553 return null; -554 } -555 -556 private boolean executeSubcommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { -557 final RegisteredCommand cmd = this.getSubcommand(subcommand); -558 if (cmd != null) { -559 executeCommand(commandContext, issuer, args, cmd); -560 return true; -561 } -562 -563 return false; +490 if (args.length > 0) { +491 CommandSearch cmd = findSubCommand(args); +492 if (cmd != null) { +493 execSubcommand = cmd.getCheckSub(); +494 final String[] execargs = Arrays.copyOfRange(args, cmd.argIndex, args.length); +495 executeCommand(commandContext, issuer, execargs, cmd.cmd); +496 return; +497 } +498 } +499 +500 if (subCommands.get(DEFAULT) != null && args.length == 0) { +501 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); +502 } else if (subCommands.get(CATCHUNKNOWN) != null) { +503 if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) { +504 help(issuer, args); +505 } +506 } else if (subCommands.get(DEFAULT) != null) { +507 findAndExecuteCommand(commandContext, DEFAULT, issuer, args); +508 } +509 +510 } finally { +511 postCommandOperation(); +512 } +513 } +514 +515 /** +516 * Gets the registered command of the given arguments. +517 * @param args +518 * The arguments given by the user. +519 * +520 * @return The subcommand or null if none were found. +521 * +522 * @see #findSubCommand(String[]) +523 */ +524 RegisteredCommand<?> getRegisteredCommand(String[] args) { +525 final CommandSearch cmd = findSubCommand(args); +526 return cmd != null ? cmd.cmd : null; +527 } +528 +529 /** +530 * This is ran after any command operation has been performed. +531 */ +532 private void postCommandOperation() { +533 CommandManager.commandOperationContext.get().pop(); +534 execSubcommand = null; +535 execLabel = null; +536 origArgs = new String[]{}; +537 } +538 +539 /** +540 * This is ran before any command operation has been performed. +541 * +542 * @param issuer +543 * The user who executed the command. +544 * @param commandLabel +545 * The label the user used to execute the command. This is not the command name, but their input. +546 * When there is multiple aliases, this is which alias was used +547 * @param args +548 * The arguments passed to the command when executing it. +549 * @param isAsync +550 * Whether the command is executed off of the main thread. +551 * +552 * @return The context which is being registered to the {@link CommandManager}'s {@link +553 * CommandManager#commandOperationContext thread local stack}. +554 */ +555 private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { +556 Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get(); +557 CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); +558 contexts.push(context); +559 lastCommandOperationContext = context; +560 execSubcommand = null; +561 execLabel = commandLabel; +562 origArgs = args; +563 return context; 564 } 565 -566 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { -567 Method pre = this.preCommandHandler; -568 if (pre != null) { -569 try { -570 Class<?>[] types = pre.getParameterTypes(); -571 Object[] parameters = new Object[pre.getParameterCount()]; -572 for (int i = 0; i < parameters.length; i++) { -573 Class<?> type = types[i]; -574 Object issuerObject = issuer.getIssuer(); -575 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { -576 parameters[i] = issuerObject; -577 } else if (CommandIssuer.class.isAssignableFrom(type)) { -578 parameters[i] = issuer; -579 } else if (RegisteredCommand.class.isAssignableFrom(type)) { -580 parameters[i] = cmd; -581 } else if (String[].class.isAssignableFrom((type))) { -582 parameters[i] = args; -583 } else { -584 parameters[i] = null; -585 } -586 } -587 -588 return (boolean) pre.invoke(this, parameters); -589 } catch (IllegalAccessException | InvocationTargetException e) { -590 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); -591 } -592 } -593 return false; -594 } -595 -596 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -597 public CommandHelp getCommandHelp() { -598 return manager.generateCommandHelp(); -599 } -600 -601 /** @deprecated Unstable API */ @Deprecated @UnstableAPI -602 public void showCommandHelp() { -603 getCommandHelp().showHelp(); -604 } -605 -606 public void help(Object issuer, String[] args) { -607 help(manager.getCommandIssuer(issuer), args); -608 } -609 public void help(CommandIssuer issuer, String[] args) { -610 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); -611 } -612 public void doHelp(Object issuer, String... args) { -613 doHelp(manager.getCommandIssuer(issuer), args); -614 } -615 public void doHelp(CommandIssuer issuer, String... args) { -616 help(issuer, args); -617 } -618 -619 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { -620 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, -621 "{command}", manager.getCommandPrefix(issuer) + cmd.command, -622 "{syntax}", cmd.syntaxText -623 ); -624 } -625 -626 public boolean hasPermission(Object issuer) { -627 return hasPermission(manager.getCommandIssuer(issuer)); -628 } -629 -630 public boolean hasPermission(CommandIssuer issuer) { -631 return permission == null || permission.isEmpty() || (manager.hasPermission(issuer, permission) && (parentCommand == null || parentCommand.hasPermission(issuer))); -632 } -633 -634 -635 public Set<String> getRequiredPermissions() { -636 if (this.permission == null || this.permission.isEmpty()) { -637 return ImmutableSet.of(); -638 } -639 return Sets.newHashSet(ACFPatterns.COMMA.split(this.permission)); -640 } -641 -642 public boolean requiresPermission(String permission) { -643 return getRequiredPermissions().contains(permission) || this.parentCommand != null && parentCommand.requiresPermission(permission); -644 } -645 -646 public String getName() { -647 return commandName; -648 } -649 -650 public ExceptionHandler getExceptionHandler() { -651 return exceptionHandler; -652 } -653 -654 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { -655 this.exceptionHandler = exceptionHandler; -656 return this; -657 } -658 -659 public RegisteredCommand getDefaultRegisteredCommand() { -660 return this.getSubcommand(DEFAULT); -661 } -662 -663 public String setContextFlags(Class<?> cls, String flags) { -664 return this.contextFlags.put(cls, flags); -665 } -666 -667 public String getContextFlags(Class<?> cls) { -668 return this.contextFlags.get(cls); +566 /** +567 * Gets the current command issuer. +568 * +569 * @return The current command issuer. +570 */ +571 public CommandIssuer getCurrentCommandIssuer() { +572 return CommandManager.getCurrentCommandIssuer(); +573 } +574 +575 /** +576 * Gets the current command manager. +577 * +578 * @return The current command manager. +579 */ +580 public CommandManager getCurrentCommandManager() { +581 return CommandManager.getCurrentCommandManager(); +582 } +583 +584 /** +585 * Finds a subcommand of the given arguments. +586 * +587 * @param args +588 * The arguments the user input. +589 * +590 * @return The identified subcommand. +591 * +592 * @see #findSubCommand(String[], boolean) +593 */ +594 private CommandSearch findSubCommand(String[] args) { +595 return findSubCommand(args, false); +596 } +597 +598 /** +599 * Finds a subcommand of the given arguments. +600 * +601 * @param args +602 * The arguments the user input. +603 * @param completion +604 * Whether or not completion of arguments should kick in. This may end up with worse than wanted results. +605 * +606 * @return The identified subcommand. +607 */ +608 private CommandSearch findSubCommand(String[] args, boolean completion) { +609 for (int i = args.length; i >= 0; i--) { +610 String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); +611 Set<RegisteredCommand> cmds = subCommands.get(checkSub); +612 +613 final int extraArgs = args.length - i; +614 if (!cmds.isEmpty()) { +615 RegisteredCommand cmd = null; +616 if (cmds.size() == 1) { +617 cmd = Iterables.getOnlyElement(cmds); +618 } else { +619 Optional<RegisteredCommand> optCmd = cmds.stream().filter(c -> { +620 int required = c.requiredResolvers; +621 int optional = c.optionalResolvers; +622 return extraArgs <= required + optional && (completion || extraArgs >= required); +623 }).min((c1, c2) -> { +624 int a = c1.consumeInputResolvers; +625 int b = c2.consumeInputResolvers; +626 +627 if (a == b) { +628 return 0; +629 } +630 return a < b ? 1 : -1; +631 }); +632 if (optCmd.isPresent()) { +633 cmd = optCmd.get(); +634 } +635 } +636 if (cmd != null) { +637 return new CommandSearch(cmd, i, checkSub); +638 } +639 } +640 } +641 return null; +642 } +643 +644 private void executeCommand(CommandOperationContext commandOperationContext, +645 CommandIssuer issuer, String[] args, RegisteredCommand cmd) { +646 if (cmd.hasPermission(issuer)) { +647 commandOperationContext.setRegisteredCommand(cmd); +648 if (checkPrecommand(commandOperationContext, cmd, issuer, args)) { +649 return; +650 } +651 List<String> sargs = Lists.newArrayList(args); +652 cmd.invoke(issuer, sargs, commandOperationContext); +653 } else { +654 issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); +655 } +656 } +657 +658 /** +659 * Please use command conditions for restricting execution +660 * @deprecated See {@link CommandConditions} +661 * @param issuer +662 * @param cmd +663 * @return +664 */ +665 @SuppressWarnings("DeprecatedIsStillUsed") +666 @Deprecated +667 public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) { +668 return true; 669 } 670 -671 private static class CommandSearch { RegisteredCommand cmd; int argIndex; String checkSub; -672 -673 CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) { -674 this.cmd = cmd; -675 this.argIndex = argIndex; -676 this.checkSub = checkSub; -677 } -678 -679 String getCheckSub() { -680 return this.checkSub; -681 } -682 -683 @Override -684 public boolean equals(Object o) { -685 if (this == o) return true; -686 if (o == null || getClass() != o.getClass()) return false; -687 CommandSearch that = (CommandSearch) o; -688 return argIndex == that.argIndex && -689 Objects.equals(cmd, that.cmd) && -690 Objects.equals(checkSub, that.checkSub); -691 } -692 -693 @Override -694 public int hashCode() { -695 return Objects.hash(cmd, argIndex, checkSub); -696 } -697 } -698} +671 /** +672 * Gets tab completed data from the given command from the user. +673 * +674 * @param issuer +675 * The user who executed the tabcomplete. +676 * @param commandLabel +677 * The label which is being used by the user. +678 * @param args +679 * The arguments the user has typed so far. +680 * +681 * @return All possibilities in the tab complete. +682 */ +683 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { +684 return tabComplete(issuer, commandLabel, args, false); +685 } +686 +687 /** +688 * Gets the tab complete suggestions from a given command. This will automatically find anything +689 * which is valid for the specified command through the command's implementation. +690 * +691 * @param issuer +692 * The issuer of the command. +693 * @param commandLabel +694 * The command name as entered by the user instead of the ACF registered name. +695 * @param args +696 * All arguments entered by the user. +697 * @param isAsync +698 * Whether this is run off of the main thread. +699 * +700 * @return The possibilities to tab complete in no particular order. +701 */ +702 @SuppressWarnings("WeakerAccess") +703 public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) +704 throws IllegalArgumentException { +705 +706 commandLabel = commandLabel.toLowerCase(); +707 if (args.length == 0) { +708 args = new String[]{""}; +709 } +710 try { +711 CommandOperationContext commandOperationContext = preCommandOperation(issuer, commandLabel, args, isAsync); +712 +713 final CommandSearch search = findSubCommand(args, true); +714 +715 +716 final List<String> cmds = new ArrayList<>(); +717 +718 if (search != null) { +719 cmds.addAll(completeCommand(issuer, search.cmd, Arrays.copyOfRange(args, search.argIndex, args.length), commandLabel, isAsync)); +720 } else if (subCommands.get(CATCHUNKNOWN).size() == 1) { +721 cmds.addAll(completeCommand(issuer, Iterables.getOnlyElement(subCommands.get(CATCHUNKNOWN)), args, commandLabel, isAsync)); +722 } else if (subCommands.get(DEFAULT).size() == 1) { +723 cmds.addAll(completeCommand(issuer, Iterables.getOnlyElement(subCommands.get(DEFAULT)), args, commandLabel, isAsync)); +724 } +725 +726 return filterTabComplete(args[args.length - 1], cmds); +727 } finally { +728 postCommandOperation(); +729 } +730 } +731 +732 /** +733 * Gets all subcommands which are possible to tabcomplete. +734 * +735 * @param issuer +736 * The command issuer. +737 * @param args +738 * +739 * @return +740 */ +741 List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) { +742 final Set<String> cmds = new HashSet<>(); +743 final int cmdIndex = Math.max(0, args.length - 1); +744 String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(); +745 for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) { +746 final String key = entry.getKey(); +747 if (key.startsWith(argString) && !CATCHUNKNOWN.equals(key) && !DEFAULT.equals(key)) { +748 final RegisteredCommand value = entry.getValue(); +749 if (!value.hasPermission(issuer) || value.isPrivate) { +750 continue; +751 } +752 +753 String[] split = ACFPatterns.SPACE.split(value.prefSubCommand); +754 cmds.add(split[cmdIndex]); +755 } +756 } +757 return new ArrayList<>(cmds); +758 } +759 +760 /** +761 * Complete a command properly per issuer and input. +762 * +763 * @param issuer +764 * The user who executed this. +765 * @param cmd +766 * The command to be completed. +767 * @param args +768 * All arguments given by the user. +769 * @param commandLabel +770 * The command name the user used. +771 * @param isAsync +772 * Whether the command was executed async. +773 * +774 * @return All results to complete the command. +775 */ +776 private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { +777 if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { +778 return ImmutableList.of(); +779 } +780 +781 List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync); +782 return filterTabComplete(args[args.length-1], cmds); +783 } +784 +785 /** +786 * Gets the actual args in string form the user typed +787 * This returns a list of all tab complete options which are possible with the given argument and commands. +788 * @param arg +789 * Argument which was pressed tab on. +790 * @param cmds +791 * The possibilities to return. +792 * +793 * @return All possible options. This may be empty. +794 */ +795 private static List<String> filterTabComplete(String arg, List<String> cmds) { +796 return cmds.stream() +797 .distinct() +798 .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg))) +799 .collect(Collectors.toList()); +800 } +801 +802 /** +803 * Gets a registered command under the given subcommand name. +804 * +805 * @param subcommand +806 * The name of the subcommand requested. +807 * +808 * @return The subcommand found or null if none. +809 */ +810 private RegisteredCommand getCommandBySubcommand(String subcommand) { +811 return getCommandBySubcommand(subcommand, false); +812 } +813 +814 /** +815 * Gets a registered command under the given name. +816 * If requireOne is true, it won't accept more than a single matching subcommand. +817 * +818 * @param subcommand +819 * Name of the subcommand wanted. +820 * @param requireOne +821 * Whether to only accept 1 result. +822 * +823 * @return The subcommand found, or null if none/too many. +824 */ +825 private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) { +826 final Set<RegisteredCommand> commands = subCommands.get(subcommand); +827 if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) { +828 return commands.iterator().next(); +829 } +830 return null; +831 } +832 +833 /** +834 * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)} +835 * and gets through {@link #getCommandBySubcommand(String)}. +836 * +837 * @param commandContext +838 * The command context to use. +839 * @param subcommand +840 * The subcommand to find the executor of. +841 * @param issuer +842 * The issuer who executed the subcommand. +843 * @param args +844 * All arguments given by the issuer. +845 * +846 * @return Whether it found a command or not. +847 * +848 * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand) +849 * @see #getCommandBySubcommand(String) +850 * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext) +851 */ +852 private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { +853 final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand); +854 if (cmd != null) { +855 executeCommand(commandContext, issuer, args, cmd); +856 return true; +857 } +858 +859 return false; +860 } +861 +862 /** +863 * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. +864 * +865 * @param commandOperationContext +866 * The context to use. +867 * @param cmd +868 * The command executed. +869 * @param issuer +870 * The issuer who executed the command. +871 * @param args +872 * The arguments the issuer provided. +873 * +874 * @return Whether something went wrong. +875 */ +876 private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { +877 Method pre = this.preCommandHandler; +878 if (pre != null) { +879 try { +880 Class<?>[] types = pre.getParameterTypes(); +881 Object[] parameters = new Object[pre.getParameterCount()]; +882 for (int i = 0; i < parameters.length; i++) { +883 Class<?> type = types[i]; +884 Object issuerObject = issuer.getIssuer(); +885 if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) { +886 parameters[i] = issuerObject; +887 } else if (CommandIssuer.class.isAssignableFrom(type)) { +888 parameters[i] = issuer; +889 } else if (RegisteredCommand.class.isAssignableFrom(type)) { +890 parameters[i] = cmd; +891 } else if (String[].class.isAssignableFrom((type))) { +892 parameters[i] = args; +893 } else { +894 parameters[i] = null; +895 } +896 } +897 +898 return (boolean) pre.invoke(this, parameters); +899 } catch (IllegalAccessException | InvocationTargetException e) { +900 this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e); +901 } +902 } +903 return false; +904 } +905 +906 /** @deprecated Unstable API */ @Deprecated @UnstableAPI +907 public CommandHelp getCommandHelp() { +908 return manager.generateCommandHelp(); +909 } +910 +911 /** @deprecated Unstable API */ @Deprecated @UnstableAPI +912 public void showCommandHelp() { +913 getCommandHelp().showHelp(); +914 } +915 +916 public void help(Object issuer, String[] args) { +917 help(manager.getCommandIssuer(issuer), args); +918 } +919 public void help(CommandIssuer issuer, String[] args) { +920 issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND); +921 } +922 public void doHelp(Object issuer, String... args) { +923 doHelp(manager.getCommandIssuer(issuer), args); +924 } +925 public void doHelp(CommandIssuer issuer, String... args) { +926 help(issuer, args); +927 } +928 +929 public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) { +930 issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX, +931 "{command}", manager.getCommandPrefix(issuer) + cmd.command, +932 "{syntax}", cmd.syntaxText +933 ); +934 } +935 +936 public boolean hasPermission(Object issuer) { +937 return hasPermission(manager.getCommandIssuer(issuer)); +938 } +939 +940 public boolean hasPermission(CommandIssuer issuer) { +941 return permission == null || permission.isEmpty() || (manager.hasPermission(issuer, permission) && (parentCommand == null || parentCommand.hasPermission(issuer))); +942 } +943 +944 +945 public Set<String> getRequiredPermissions() { +946 if (this.permission == null || this.permission.isEmpty()) { +947 return ImmutableSet.of(); +948 } +949 return Sets.newHashSet(ACFPatterns.COMMA.split(this.permission)); +950 } +951 +952 public boolean requiresPermission(String permission) { +953 return getRequiredPermissions().contains(permission) || this.parentCommand != null && parentCommand.requiresPermission(permission); +954 } +955 +956 public String getName() { +957 return commandName; +958 } +959 +960 public ExceptionHandler getExceptionHandler() { +961 return exceptionHandler; +962 } +963 +964 public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) { +965 this.exceptionHandler = exceptionHandler; +966 return this; +967 } +968 +969 public RegisteredCommand getDefaultRegisteredCommand() { +970 return this.getCommandBySubcommand(DEFAULT); +971 } +972 +973 public String setContextFlags(Class<?> cls, String flags) { +974 return this.contextFlags.put(cls, flags); +975 } +976 +977 public String getContextFlags(Class<?> cls) { +978 return this.contextFlags.get(cls); +979 } +980 +981 private static class CommandSearch { RegisteredCommand cmd; int argIndex; String checkSub; +982 +983 CommandSearch(RegisteredCommand cmd, int argIndex, String checkSub) { +984 this.cmd = cmd; +985 this.argIndex = argIndex; +986 this.checkSub = checkSub; +987 } +988 +989 String getCheckSub() { +990 return this.checkSub; +991 } +992 +993 @Override +994 public boolean equals(Object o) { +995 if (this == o) return true; +996 if (o == null || getClass() != o.getClass()) return false; +997 CommandSearch that = (CommandSearch) o; +998 return argIndex == that.argIndex && +999 Objects.equals(cmd, that.cmd) && +1000 Objects.equals(checkSub, that.checkSub); +1001 } +1002 +1003 @Override +1004 public int hashCode() { +1005 return Objects.hash(cmd, argIndex, checkSub); +1006 } +1007 } +1008} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html index d9ff5a50..ca4306a7 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html @@ -39,138 +39,209 @@ 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; -034import java.util.stream.Collectors; -035import java.util.stream.IntStream; -036 +034import java.util.function.Supplier; +035import java.util.stream.Collectors; +036import java.util.stream.IntStream; 037 -038@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) -039public class CommandCompletions <C extends CommandCompletionContext> { -040 private final CommandManager manager; -041 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -042 private Map<Class, String> defaultCompletions = new HashMap<>(); -043 -044 public CommandCompletions(CommandManager manager) { -045 this.manager = manager; -046 registerAsyncCompletion("nothing", c -> ImmutableList.of()); -047 registerAsyncCompletion("range", (c) -> { -048 String config = c.getConfig(); -049 if (config == null) { -050 return ImmutableList.of(); -051 } -052 final String[] ranges = ACFPatterns.DASH.split(config); -053 int start; -054 int end; -055 if (ranges.length != 2) { -056 start = 0; -057 end = ACFUtil.parseInt(ranges[0], 0); -058 } else { -059 start = ACFUtil.parseInt(ranges[0], 0); -060 end = ACFUtil.parseInt(ranges[1], 0); -061 } -062 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -063 }); -064 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); -065 } -066 -067 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -068 return this.completionMap.put("@" + id.toLowerCase(), handler); -069 } -070 -071 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -072 return this.completionMap.put("@" + id.toLowerCase(), handler); -073 } -074 -075 /** -076 * @deprecated Feature Not done yet -077 * @param id -078 * @param classes -079 * @return -080 */ -081 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -082 // get completion with specified id -083 id = id.toLowerCase(); -084 CommandCompletionHandler completion = completionMap.get(id); -085 -086 if(completion == null) { -087 // Throw something because no completion with specified id -088 ACFUtil.sneaky(new CommandCompletionTextLookupException()); -089 } -090 -091 for(Class clazz : classes) { -092 defaultCompletions.put(clazz, id); -093 } -094 -095 return completion; +038 +039@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) +040public class CommandCompletions <C extends CommandCompletionContext> { +041 private final CommandManager manager; +042 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +043 private Map<Class, String> defaultCompletions = new HashMap<>(); +044 +045 public CommandCompletions(CommandManager manager) { +046 this.manager = manager; +047 registerAsyncCompletion("nothing", c -> ImmutableList.of()); +048 registerAsyncCompletion("range", (c) -> { +049 String config = c.getConfig(); +050 if (config == null) { +051 return ImmutableList.of(); +052 } +053 final String[] ranges = ACFPatterns.DASH.split(config); +054 int start; +055 int end; +056 if (ranges.length != 2) { +057 start = 0; +058 end = ACFUtil.parseInt(ranges[0], 0); +059 } else { +060 start = ACFUtil.parseInt(ranges[0], 0); +061 end = ACFUtil.parseInt(ranges[1], 0); +062 } +063 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +064 }); +065 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); +066 } +067 +068 /** +069 * Registr a completion handler to provide command completions based on the user input. +070 * +071 * @param id +072 * @param handler +073 * @return +074 */ +075 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +076 return this.completionMap.put("@" + id.toLowerCase(), handler); +077 } +078 +079 /** +080 * Registr a completion handler to provide command completions based on the user input. +081 * This handler is declared to be safe to be executed asynchronously. +082 * <p> +083 * Not all platforms support this, so if the platform does not support asynchronous execution, +084 * your handler will be executed on the main thread. +085 * <p> +086 * Use this anytime your handler does not need to access state that is not considered thread safe. +087 * <p> +088 * Use context.isAsync() to determine if you are async or not. +089 * +090 * @param id +091 * @param handler +092 * @return +093 */ +094 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +095 return this.completionMap.put("@" + id.toLowerCase(), handler); 096 } 097 -098 @NotNull -099 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -100 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -101 final int argIndex = args.length - 1; -102 -103 String input = args[argIndex]; -104 -105 String completion = argIndex < completions.length ? completions[argIndex] : null; -106 if (completion == null && completions.length > 0) { -107 completion = completions[completions.length - 1]; -108 } -109 if (completion == null) { -110 return ImmutableList.of(input); -111 } -112 -113 return getCompletionValues(cmd, sender, completion, args, isAsync); -114 } -115 -116 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -117 completion = manager.getCommandReplacements().replace(completion); -118 -119 List<String> allCompletions = Lists.newArrayList(); -120 String input = args.length > 0 ? args[args.length - 1] : ""; -121 -122 for (String value : ACFPatterns.PIPE.split(completion)) { -123 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -124 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -125 if (handler != null) { -126 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -127 ACFUtil.sneaky(new SyncCompletionRequired()); -128 return null; -129 } -130 String config = complete.length == 1 ? null : complete[1]; -131 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -132 -133 try { -134 //noinspection unchecked -135 Collection<String> completions = handler.getCompletions(context); -136 if (completions != null) { -137 allCompletions.addAll(completions); -138 continue; -139 } -140 //noinspection ConstantIfStatement,ConstantConditions -141 if (false) { // Hack to fool compiler. since its sneakily thrown. -142 throw new CommandCompletionTextLookupException(); -143 } -144 } catch (CommandCompletionTextLookupException ignored) { -145 // This should only happen if some other feedback error occured. -146 } catch (Exception e) { -147 command.handleException(sender, Lists.newArrayList(args), e); -148 } -149 // Something went wrong in lookup, fall back to input -150 return ImmutableList.of(input); -151 } else { -152 // Plaintext value -153 allCompletions.add(value); -154 } -155 } -156 return allCompletions; -157 } -158 -159 public interface CommandCompletionHandler <C extends CommandCompletionContext> { -160 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -161 } -162 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} -163 public static class SyncCompletionRequired extends Exception {} -164 -165} +098 /** +099 * Register a static list of command completions that will never change. +100 * Like @CommandCompletion, values are | (PIPE) separated. +101 * <p> +102 * Example: foo|bar|baz +103 * +104 * @param id +105 * @param list +106 * @return +107 */ +108 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +109 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +110 } +111 +112 /** +113 * Register a static list of command completions that will never change +114 * +115 * @param id +116 * @param completions +117 * @return +118 */ +119 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +120 return registerStaticCompletion(id, Lists.newArrayList(completions)); +121 } +122 +123 /** +124 * Register a static list of command completions that will never change. The list is obtained from the supplier +125 * immediately as part of this method call. +126 * +127 * @param id +128 * @param supplier +129 * @return +130 */ +131 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<List<String>> supplier) { +132 return registerStaticCompletion(id, supplier.get()); +133 } +134 +135 /** +136 * Register a static list of command completions that will never change +137 * +138 * @param id +139 * @param completions +140 * @return +141 */ +142 public CommandCompletionHandler registerStaticCompletion(String id, List<String> completions) { +143 return registerAsyncCompletion(id, x -> completions); +144 } +145 +146 /** +147 * @deprecated Feature Not done yet +148 * @param id +149 * @param classes +150 * @return +151 */ +152 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { +153 // get completion with specified id +154 id = id.toLowerCase(); +155 CommandCompletionHandler completion = completionMap.get(id); +156 +157 if(completion == null) { +158 // Throw something because no completion with specified id +159 ACFUtil.sneaky(new CommandCompletionTextLookupException()); +160 } +161 +162 for(Class clazz : classes) { +163 defaultCompletions.put(clazz, id); +164 } +165 +166 return completion; +167 } +168 +169 @NotNull +170 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +171 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +172 final int argIndex = args.length - 1; +173 +174 String input = args[argIndex]; +175 +176 String completion = argIndex < completions.length ? completions[argIndex] : null; +177 if (completion == null && completions.length > 0) { +178 completion = completions[completions.length - 1]; +179 } +180 if (completion == null) { +181 return ImmutableList.of(input); +182 } +183 +184 return getCompletionValues(cmd, sender, completion, args, isAsync); +185 } +186 +187 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +188 completion = manager.getCommandReplacements().replace(completion); +189 +190 List<String> allCompletions = Lists.newArrayList(); +191 String input = args.length > 0 ? args[args.length - 1] : ""; +192 +193 for (String value : ACFPatterns.PIPE.split(completion)) { +194 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +195 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +196 if (handler != null) { +197 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +198 ACFUtil.sneaky(new SyncCompletionRequired()); +199 return null; +200 } +201 String config = complete.length == 1 ? null : complete[1]; +202 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +203 +204 try { +205 //noinspection unchecked +206 Collection<String> completions = handler.getCompletions(context); +207 if (completions != null) { +208 allCompletions.addAll(completions); +209 continue; +210 } +211 //noinspection ConstantIfStatement,ConstantConditions +212 if (false) { // Hack to fool compiler. since its sneakily thrown. +213 throw new CommandCompletionTextLookupException(); +214 } +215 } catch (CommandCompletionTextLookupException ignored) { +216 // This should only happen if some other feedback error occured. +217 } catch (Exception e) { +218 command.handleException(sender, Lists.newArrayList(args), e); +219 } +220 // Something went wrong in lookup, fall back to input +221 return ImmutableList.of(input); +222 } else { +223 // Plaintext value +224 allCompletions.add(value); +225 } +226 } +227 return allCompletions; +228 } +229 +230 public interface CommandCompletionHandler <C extends CommandCompletionContext> { +231 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +232 } +233 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} +234 public static class SyncCompletionRequired extends Exception {} +235 +236} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html index d9ff5a50..ca4306a7 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html @@ -39,138 +39,209 @@ 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; -034import java.util.stream.Collectors; -035import java.util.stream.IntStream; -036 +034import java.util.function.Supplier; +035import java.util.stream.Collectors; +036import java.util.stream.IntStream; 037 -038@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) -039public class CommandCompletions <C extends CommandCompletionContext> { -040 private final CommandManager manager; -041 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -042 private Map<Class, String> defaultCompletions = new HashMap<>(); -043 -044 public CommandCompletions(CommandManager manager) { -045 this.manager = manager; -046 registerAsyncCompletion("nothing", c -> ImmutableList.of()); -047 registerAsyncCompletion("range", (c) -> { -048 String config = c.getConfig(); -049 if (config == null) { -050 return ImmutableList.of(); -051 } -052 final String[] ranges = ACFPatterns.DASH.split(config); -053 int start; -054 int end; -055 if (ranges.length != 2) { -056 start = 0; -057 end = ACFUtil.parseInt(ranges[0], 0); -058 } else { -059 start = ACFUtil.parseInt(ranges[0], 0); -060 end = ACFUtil.parseInt(ranges[1], 0); -061 } -062 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -063 }); -064 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); -065 } -066 -067 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -068 return this.completionMap.put("@" + id.toLowerCase(), handler); -069 } -070 -071 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -072 return this.completionMap.put("@" + id.toLowerCase(), handler); -073 } -074 -075 /** -076 * @deprecated Feature Not done yet -077 * @param id -078 * @param classes -079 * @return -080 */ -081 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -082 // get completion with specified id -083 id = id.toLowerCase(); -084 CommandCompletionHandler completion = completionMap.get(id); -085 -086 if(completion == null) { -087 // Throw something because no completion with specified id -088 ACFUtil.sneaky(new CommandCompletionTextLookupException()); -089 } -090 -091 for(Class clazz : classes) { -092 defaultCompletions.put(clazz, id); -093 } -094 -095 return completion; +038 +039@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) +040public class CommandCompletions <C extends CommandCompletionContext> { +041 private final CommandManager manager; +042 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +043 private Map<Class, String> defaultCompletions = new HashMap<>(); +044 +045 public CommandCompletions(CommandManager manager) { +046 this.manager = manager; +047 registerAsyncCompletion("nothing", c -> ImmutableList.of()); +048 registerAsyncCompletion("range", (c) -> { +049 String config = c.getConfig(); +050 if (config == null) { +051 return ImmutableList.of(); +052 } +053 final String[] ranges = ACFPatterns.DASH.split(config); +054 int start; +055 int end; +056 if (ranges.length != 2) { +057 start = 0; +058 end = ACFUtil.parseInt(ranges[0], 0); +059 } else { +060 start = ACFUtil.parseInt(ranges[0], 0); +061 end = ACFUtil.parseInt(ranges[1], 0); +062 } +063 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +064 }); +065 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); +066 } +067 +068 /** +069 * Registr a completion handler to provide command completions based on the user input. +070 * +071 * @param id +072 * @param handler +073 * @return +074 */ +075 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +076 return this.completionMap.put("@" + id.toLowerCase(), handler); +077 } +078 +079 /** +080 * Registr a completion handler to provide command completions based on the user input. +081 * This handler is declared to be safe to be executed asynchronously. +082 * <p> +083 * Not all platforms support this, so if the platform does not support asynchronous execution, +084 * your handler will be executed on the main thread. +085 * <p> +086 * Use this anytime your handler does not need to access state that is not considered thread safe. +087 * <p> +088 * Use context.isAsync() to determine if you are async or not. +089 * +090 * @param id +091 * @param handler +092 * @return +093 */ +094 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +095 return this.completionMap.put("@" + id.toLowerCase(), handler); 096 } 097 -098 @NotNull -099 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -100 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -101 final int argIndex = args.length - 1; -102 -103 String input = args[argIndex]; -104 -105 String completion = argIndex < completions.length ? completions[argIndex] : null; -106 if (completion == null && completions.length > 0) { -107 completion = completions[completions.length - 1]; -108 } -109 if (completion == null) { -110 return ImmutableList.of(input); -111 } -112 -113 return getCompletionValues(cmd, sender, completion, args, isAsync); -114 } -115 -116 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -117 completion = manager.getCommandReplacements().replace(completion); -118 -119 List<String> allCompletions = Lists.newArrayList(); -120 String input = args.length > 0 ? args[args.length - 1] : ""; -121 -122 for (String value : ACFPatterns.PIPE.split(completion)) { -123 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -124 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -125 if (handler != null) { -126 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -127 ACFUtil.sneaky(new SyncCompletionRequired()); -128 return null; -129 } -130 String config = complete.length == 1 ? null : complete[1]; -131 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -132 -133 try { -134 //noinspection unchecked -135 Collection<String> completions = handler.getCompletions(context); -136 if (completions != null) { -137 allCompletions.addAll(completions); -138 continue; -139 } -140 //noinspection ConstantIfStatement,ConstantConditions -141 if (false) { // Hack to fool compiler. since its sneakily thrown. -142 throw new CommandCompletionTextLookupException(); -143 } -144 } catch (CommandCompletionTextLookupException ignored) { -145 // This should only happen if some other feedback error occured. -146 } catch (Exception e) { -147 command.handleException(sender, Lists.newArrayList(args), e); -148 } -149 // Something went wrong in lookup, fall back to input -150 return ImmutableList.of(input); -151 } else { -152 // Plaintext value -153 allCompletions.add(value); -154 } -155 } -156 return allCompletions; -157 } -158 -159 public interface CommandCompletionHandler <C extends CommandCompletionContext> { -160 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -161 } -162 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} -163 public static class SyncCompletionRequired extends Exception {} -164 -165} +098 /** +099 * Register a static list of command completions that will never change. +100 * Like @CommandCompletion, values are | (PIPE) separated. +101 * <p> +102 * Example: foo|bar|baz +103 * +104 * @param id +105 * @param list +106 * @return +107 */ +108 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +109 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +110 } +111 +112 /** +113 * Register a static list of command completions that will never change +114 * +115 * @param id +116 * @param completions +117 * @return +118 */ +119 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +120 return registerStaticCompletion(id, Lists.newArrayList(completions)); +121 } +122 +123 /** +124 * Register a static list of command completions that will never change. The list is obtained from the supplier +125 * immediately as part of this method call. +126 * +127 * @param id +128 * @param supplier +129 * @return +130 */ +131 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<List<String>> supplier) { +132 return registerStaticCompletion(id, supplier.get()); +133 } +134 +135 /** +136 * Register a static list of command completions that will never change +137 * +138 * @param id +139 * @param completions +140 * @return +141 */ +142 public CommandCompletionHandler registerStaticCompletion(String id, List<String> completions) { +143 return registerAsyncCompletion(id, x -> completions); +144 } +145 +146 /** +147 * @deprecated Feature Not done yet +148 * @param id +149 * @param classes +150 * @return +151 */ +152 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { +153 // get completion with specified id +154 id = id.toLowerCase(); +155 CommandCompletionHandler completion = completionMap.get(id); +156 +157 if(completion == null) { +158 // Throw something because no completion with specified id +159 ACFUtil.sneaky(new CommandCompletionTextLookupException()); +160 } +161 +162 for(Class clazz : classes) { +163 defaultCompletions.put(clazz, id); +164 } +165 +166 return completion; +167 } +168 +169 @NotNull +170 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +171 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +172 final int argIndex = args.length - 1; +173 +174 String input = args[argIndex]; +175 +176 String completion = argIndex < completions.length ? completions[argIndex] : null; +177 if (completion == null && completions.length > 0) { +178 completion = completions[completions.length - 1]; +179 } +180 if (completion == null) { +181 return ImmutableList.of(input); +182 } +183 +184 return getCompletionValues(cmd, sender, completion, args, isAsync); +185 } +186 +187 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +188 completion = manager.getCommandReplacements().replace(completion); +189 +190 List<String> allCompletions = Lists.newArrayList(); +191 String input = args.length > 0 ? args[args.length - 1] : ""; +192 +193 for (String value : ACFPatterns.PIPE.split(completion)) { +194 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +195 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +196 if (handler != null) { +197 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +198 ACFUtil.sneaky(new SyncCompletionRequired()); +199 return null; +200 } +201 String config = complete.length == 1 ? null : complete[1]; +202 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +203 +204 try { +205 //noinspection unchecked +206 Collection<String> completions = handler.getCompletions(context); +207 if (completions != null) { +208 allCompletions.addAll(completions); +209 continue; +210 } +211 //noinspection ConstantIfStatement,ConstantConditions +212 if (false) { // Hack to fool compiler. since its sneakily thrown. +213 throw new CommandCompletionTextLookupException(); +214 } +215 } catch (CommandCompletionTextLookupException ignored) { +216 // This should only happen if some other feedback error occured. +217 } catch (Exception e) { +218 command.handleException(sender, Lists.newArrayList(args), e); +219 } +220 // Something went wrong in lookup, fall back to input +221 return ImmutableList.of(input); +222 } else { +223 // Plaintext value +224 allCompletions.add(value); +225 } +226 } +227 return allCompletions; +228 } +229 +230 public interface CommandCompletionHandler <C extends CommandCompletionContext> { +231 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +232 } +233 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} +234 public static class SyncCompletionRequired extends Exception {} +235 +236} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html index d9ff5a50..ca4306a7 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html @@ -39,138 +39,209 @@ 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; -034import java.util.stream.Collectors; -035import java.util.stream.IntStream; -036 +034import java.util.function.Supplier; +035import java.util.stream.Collectors; +036import java.util.stream.IntStream; 037 -038@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) -039public class CommandCompletions <C extends CommandCompletionContext> { -040 private final CommandManager manager; -041 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -042 private Map<Class, String> defaultCompletions = new HashMap<>(); -043 -044 public CommandCompletions(CommandManager manager) { -045 this.manager = manager; -046 registerAsyncCompletion("nothing", c -> ImmutableList.of()); -047 registerAsyncCompletion("range", (c) -> { -048 String config = c.getConfig(); -049 if (config == null) { -050 return ImmutableList.of(); -051 } -052 final String[] ranges = ACFPatterns.DASH.split(config); -053 int start; -054 int end; -055 if (ranges.length != 2) { -056 start = 0; -057 end = ACFUtil.parseInt(ranges[0], 0); -058 } else { -059 start = ACFUtil.parseInt(ranges[0], 0); -060 end = ACFUtil.parseInt(ranges[1], 0); -061 } -062 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -063 }); -064 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); -065 } -066 -067 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -068 return this.completionMap.put("@" + id.toLowerCase(), handler); -069 } -070 -071 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -072 return this.completionMap.put("@" + id.toLowerCase(), handler); -073 } -074 -075 /** -076 * @deprecated Feature Not done yet -077 * @param id -078 * @param classes -079 * @return -080 */ -081 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -082 // get completion with specified id -083 id = id.toLowerCase(); -084 CommandCompletionHandler completion = completionMap.get(id); -085 -086 if(completion == null) { -087 // Throw something because no completion with specified id -088 ACFUtil.sneaky(new CommandCompletionTextLookupException()); -089 } -090 -091 for(Class clazz : classes) { -092 defaultCompletions.put(clazz, id); -093 } -094 -095 return completion; +038 +039@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) +040public class CommandCompletions <C extends CommandCompletionContext> { +041 private final CommandManager manager; +042 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +043 private Map<Class, String> defaultCompletions = new HashMap<>(); +044 +045 public CommandCompletions(CommandManager manager) { +046 this.manager = manager; +047 registerAsyncCompletion("nothing", c -> ImmutableList.of()); +048 registerAsyncCompletion("range", (c) -> { +049 String config = c.getConfig(); +050 if (config == null) { +051 return ImmutableList.of(); +052 } +053 final String[] ranges = ACFPatterns.DASH.split(config); +054 int start; +055 int end; +056 if (ranges.length != 2) { +057 start = 0; +058 end = ACFUtil.parseInt(ranges[0], 0); +059 } else { +060 start = ACFUtil.parseInt(ranges[0], 0); +061 end = ACFUtil.parseInt(ranges[1], 0); +062 } +063 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +064 }); +065 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); +066 } +067 +068 /** +069 * Registr a completion handler to provide command completions based on the user input. +070 * +071 * @param id +072 * @param handler +073 * @return +074 */ +075 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +076 return this.completionMap.put("@" + id.toLowerCase(), handler); +077 } +078 +079 /** +080 * Registr a completion handler to provide command completions based on the user input. +081 * This handler is declared to be safe to be executed asynchronously. +082 * <p> +083 * Not all platforms support this, so if the platform does not support asynchronous execution, +084 * your handler will be executed on the main thread. +085 * <p> +086 * Use this anytime your handler does not need to access state that is not considered thread safe. +087 * <p> +088 * Use context.isAsync() to determine if you are async or not. +089 * +090 * @param id +091 * @param handler +092 * @return +093 */ +094 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +095 return this.completionMap.put("@" + id.toLowerCase(), handler); 096 } 097 -098 @NotNull -099 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -100 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -101 final int argIndex = args.length - 1; -102 -103 String input = args[argIndex]; -104 -105 String completion = argIndex < completions.length ? completions[argIndex] : null; -106 if (completion == null && completions.length > 0) { -107 completion = completions[completions.length - 1]; -108 } -109 if (completion == null) { -110 return ImmutableList.of(input); -111 } -112 -113 return getCompletionValues(cmd, sender, completion, args, isAsync); -114 } -115 -116 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -117 completion = manager.getCommandReplacements().replace(completion); -118 -119 List<String> allCompletions = Lists.newArrayList(); -120 String input = args.length > 0 ? args[args.length - 1] : ""; -121 -122 for (String value : ACFPatterns.PIPE.split(completion)) { -123 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -124 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -125 if (handler != null) { -126 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -127 ACFUtil.sneaky(new SyncCompletionRequired()); -128 return null; -129 } -130 String config = complete.length == 1 ? null : complete[1]; -131 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -132 -133 try { -134 //noinspection unchecked -135 Collection<String> completions = handler.getCompletions(context); -136 if (completions != null) { -137 allCompletions.addAll(completions); -138 continue; -139 } -140 //noinspection ConstantIfStatement,ConstantConditions -141 if (false) { // Hack to fool compiler. since its sneakily thrown. -142 throw new CommandCompletionTextLookupException(); -143 } -144 } catch (CommandCompletionTextLookupException ignored) { -145 // This should only happen if some other feedback error occured. -146 } catch (Exception e) { -147 command.handleException(sender, Lists.newArrayList(args), e); -148 } -149 // Something went wrong in lookup, fall back to input -150 return ImmutableList.of(input); -151 } else { -152 // Plaintext value -153 allCompletions.add(value); -154 } -155 } -156 return allCompletions; -157 } -158 -159 public interface CommandCompletionHandler <C extends CommandCompletionContext> { -160 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -161 } -162 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} -163 public static class SyncCompletionRequired extends Exception {} -164 -165} +098 /** +099 * Register a static list of command completions that will never change. +100 * Like @CommandCompletion, values are | (PIPE) separated. +101 * <p> +102 * Example: foo|bar|baz +103 * +104 * @param id +105 * @param list +106 * @return +107 */ +108 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +109 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +110 } +111 +112 /** +113 * Register a static list of command completions that will never change +114 * +115 * @param id +116 * @param completions +117 * @return +118 */ +119 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +120 return registerStaticCompletion(id, Lists.newArrayList(completions)); +121 } +122 +123 /** +124 * Register a static list of command completions that will never change. The list is obtained from the supplier +125 * immediately as part of this method call. +126 * +127 * @param id +128 * @param supplier +129 * @return +130 */ +131 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<List<String>> supplier) { +132 return registerStaticCompletion(id, supplier.get()); +133 } +134 +135 /** +136 * Register a static list of command completions that will never change +137 * +138 * @param id +139 * @param completions +140 * @return +141 */ +142 public CommandCompletionHandler registerStaticCompletion(String id, List<String> completions) { +143 return registerAsyncCompletion(id, x -> completions); +144 } +145 +146 /** +147 * @deprecated Feature Not done yet +148 * @param id +149 * @param classes +150 * @return +151 */ +152 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { +153 // get completion with specified id +154 id = id.toLowerCase(); +155 CommandCompletionHandler completion = completionMap.get(id); +156 +157 if(completion == null) { +158 // Throw something because no completion with specified id +159 ACFUtil.sneaky(new CommandCompletionTextLookupException()); +160 } +161 +162 for(Class clazz : classes) { +163 defaultCompletions.put(clazz, id); +164 } +165 +166 return completion; +167 } +168 +169 @NotNull +170 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +171 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +172 final int argIndex = args.length - 1; +173 +174 String input = args[argIndex]; +175 +176 String completion = argIndex < completions.length ? completions[argIndex] : null; +177 if (completion == null && completions.length > 0) { +178 completion = completions[completions.length - 1]; +179 } +180 if (completion == null) { +181 return ImmutableList.of(input); +182 } +183 +184 return getCompletionValues(cmd, sender, completion, args, isAsync); +185 } +186 +187 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +188 completion = manager.getCommandReplacements().replace(completion); +189 +190 List<String> allCompletions = Lists.newArrayList(); +191 String input = args.length > 0 ? args[args.length - 1] : ""; +192 +193 for (String value : ACFPatterns.PIPE.split(completion)) { +194 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +195 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +196 if (handler != null) { +197 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +198 ACFUtil.sneaky(new SyncCompletionRequired()); +199 return null; +200 } +201 String config = complete.length == 1 ? null : complete[1]; +202 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +203 +204 try { +205 //noinspection unchecked +206 Collection<String> completions = handler.getCompletions(context); +207 if (completions != null) { +208 allCompletions.addAll(completions); +209 continue; +210 } +211 //noinspection ConstantIfStatement,ConstantConditions +212 if (false) { // Hack to fool compiler. since its sneakily thrown. +213 throw new CommandCompletionTextLookupException(); +214 } +215 } catch (CommandCompletionTextLookupException ignored) { +216 // This should only happen if some other feedback error occured. +217 } catch (Exception e) { +218 command.handleException(sender, Lists.newArrayList(args), e); +219 } +220 // Something went wrong in lookup, fall back to input +221 return ImmutableList.of(input); +222 } else { +223 // Plaintext value +224 allCompletions.add(value); +225 } +226 } +227 return allCompletions; +228 } +229 +230 public interface CommandCompletionHandler <C extends CommandCompletionContext> { +231 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +232 } +233 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} +234 public static class SyncCompletionRequired extends Exception {} +235 +236} diff --git a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html index d9ff5a50..ca4306a7 100644 --- a/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html +++ b/docs/acf-core/src-html/co/aikar/commands/CommandCompletions.html @@ -39,138 +39,209 @@ 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; -034import java.util.stream.Collectors; -035import java.util.stream.IntStream; -036 +034import java.util.function.Supplier; +035import java.util.stream.Collectors; +036import java.util.stream.IntStream; 037 -038@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) -039public class CommandCompletions <C extends CommandCompletionContext> { -040 private final CommandManager manager; -041 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); -042 private Map<Class, String> defaultCompletions = new HashMap<>(); -043 -044 public CommandCompletions(CommandManager manager) { -045 this.manager = manager; -046 registerAsyncCompletion("nothing", c -> ImmutableList.of()); -047 registerAsyncCompletion("range", (c) -> { -048 String config = c.getConfig(); -049 if (config == null) { -050 return ImmutableList.of(); -051 } -052 final String[] ranges = ACFPatterns.DASH.split(config); -053 int start; -054 int end; -055 if (ranges.length != 2) { -056 start = 0; -057 end = ACFUtil.parseInt(ranges[0], 0); -058 } else { -059 start = ACFUtil.parseInt(ranges[0], 0); -060 end = ACFUtil.parseInt(ranges[1], 0); -061 } -062 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); -063 }); -064 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); -065 } -066 -067 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { -068 return this.completionMap.put("@" + id.toLowerCase(), handler); -069 } -070 -071 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { -072 return this.completionMap.put("@" + id.toLowerCase(), handler); -073 } -074 -075 /** -076 * @deprecated Feature Not done yet -077 * @param id -078 * @param classes -079 * @return -080 */ -081 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { -082 // get completion with specified id -083 id = id.toLowerCase(); -084 CommandCompletionHandler completion = completionMap.get(id); -085 -086 if(completion == null) { -087 // Throw something because no completion with specified id -088 ACFUtil.sneaky(new CommandCompletionTextLookupException()); -089 } -090 -091 for(Class clazz : classes) { -092 defaultCompletions.put(clazz, id); -093 } -094 -095 return completion; +038 +039@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"}) +040public class CommandCompletions <C extends CommandCompletionContext> { +041 private final CommandManager manager; +042 private Map<String, CommandCompletionHandler> completionMap = new HashMap<>(); +043 private Map<Class, String> defaultCompletions = new HashMap<>(); +044 +045 public CommandCompletions(CommandManager manager) { +046 this.manager = manager; +047 registerAsyncCompletion("nothing", c -> ImmutableList.of()); +048 registerAsyncCompletion("range", (c) -> { +049 String config = c.getConfig(); +050 if (config == null) { +051 return ImmutableList.of(); +052 } +053 final String[] ranges = ACFPatterns.DASH.split(config); +054 int start; +055 int end; +056 if (ranges.length != 2) { +057 start = 0; +058 end = ACFUtil.parseInt(ranges[0], 0); +059 } else { +060 start = ACFUtil.parseInt(ranges[0], 0); +061 end = ACFUtil.parseInt(ranges[1], 0); +062 } +063 return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList()); +064 }); +065 registerAsyncCompletion("timeunits", (c) -> ImmutableList.of("minutes", "hours", "days", "weeks", "months", "years")); +066 } +067 +068 /** +069 * Registr a completion handler to provide command completions based on the user input. +070 * +071 * @param id +072 * @param handler +073 * @return +074 */ +075 public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler<C> handler) { +076 return this.completionMap.put("@" + id.toLowerCase(), handler); +077 } +078 +079 /** +080 * Registr a completion handler to provide command completions based on the user input. +081 * This handler is declared to be safe to be executed asynchronously. +082 * <p> +083 * Not all platforms support this, so if the platform does not support asynchronous execution, +084 * your handler will be executed on the main thread. +085 * <p> +086 * Use this anytime your handler does not need to access state that is not considered thread safe. +087 * <p> +088 * Use context.isAsync() to determine if you are async or not. +089 * +090 * @param id +091 * @param handler +092 * @return +093 */ +094 public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler<C> handler) { +095 return this.completionMap.put("@" + id.toLowerCase(), handler); 096 } 097 -098 @NotNull -099 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { -100 String[] completions = ACFPatterns.SPACE.split(cmd.complete); -101 final int argIndex = args.length - 1; -102 -103 String input = args[argIndex]; -104 -105 String completion = argIndex < completions.length ? completions[argIndex] : null; -106 if (completion == null && completions.length > 0) { -107 completion = completions[completions.length - 1]; -108 } -109 if (completion == null) { -110 return ImmutableList.of(input); -111 } -112 -113 return getCompletionValues(cmd, sender, completion, args, isAsync); -114 } -115 -116 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { -117 completion = manager.getCommandReplacements().replace(completion); -118 -119 List<String> allCompletions = Lists.newArrayList(); -120 String input = args.length > 0 ? args[args.length - 1] : ""; -121 -122 for (String value : ACFPatterns.PIPE.split(completion)) { -123 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); -124 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); -125 if (handler != null) { -126 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { -127 ACFUtil.sneaky(new SyncCompletionRequired()); -128 return null; -129 } -130 String config = complete.length == 1 ? null : complete[1]; -131 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); -132 -133 try { -134 //noinspection unchecked -135 Collection<String> completions = handler.getCompletions(context); -136 if (completions != null) { -137 allCompletions.addAll(completions); -138 continue; -139 } -140 //noinspection ConstantIfStatement,ConstantConditions -141 if (false) { // Hack to fool compiler. since its sneakily thrown. -142 throw new CommandCompletionTextLookupException(); -143 } -144 } catch (CommandCompletionTextLookupException ignored) { -145 // This should only happen if some other feedback error occured. -146 } catch (Exception e) { -147 command.handleException(sender, Lists.newArrayList(args), e); -148 } -149 // Something went wrong in lookup, fall back to input -150 return ImmutableList.of(input); -151 } else { -152 // Plaintext value -153 allCompletions.add(value); -154 } -155 } -156 return allCompletions; -157 } -158 -159 public interface CommandCompletionHandler <C extends CommandCompletionContext> { -160 Collection<String> getCompletions(C context) throws InvalidCommandArgument; -161 } -162 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} -163 public static class SyncCompletionRequired extends Exception {} -164 -165} +098 /** +099 * Register a static list of command completions that will never change. +100 * Like @CommandCompletion, values are | (PIPE) separated. +101 * <p> +102 * Example: foo|bar|baz +103 * +104 * @param id +105 * @param list +106 * @return +107 */ +108 public CommandCompletionHandler registerStaticCompletion(String id, String list) { +109 return registerStaticCompletion(id, ACFPatterns.PIPE.split(list)); +110 } +111 +112 /** +113 * Register a static list of command completions that will never change +114 * +115 * @param id +116 * @param completions +117 * @return +118 */ +119 public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) { +120 return registerStaticCompletion(id, Lists.newArrayList(completions)); +121 } +122 +123 /** +124 * Register a static list of command completions that will never change. The list is obtained from the supplier +125 * immediately as part of this method call. +126 * +127 * @param id +128 * @param supplier +129 * @return +130 */ +131 public CommandCompletionHandler registerStaticCompletion(String id, Supplier<List<String>> supplier) { +132 return registerStaticCompletion(id, supplier.get()); +133 } +134 +135 /** +136 * Register a static list of command completions that will never change +137 * +138 * @param id +139 * @param completions +140 * @return +141 */ +142 public CommandCompletionHandler registerStaticCompletion(String id, List<String> completions) { +143 return registerAsyncCompletion(id, x -> completions); +144 } +145 +146 /** +147 * @deprecated Feature Not done yet +148 * @param id +149 * @param classes +150 * @return +151 */ +152 CommandCompletionHandler setDefaultCompletion(String id, Class... classes) { +153 // get completion with specified id +154 id = id.toLowerCase(); +155 CommandCompletionHandler completion = completionMap.get(id); +156 +157 if(completion == null) { +158 // Throw something because no completion with specified id +159 ACFUtil.sneaky(new CommandCompletionTextLookupException()); +160 } +161 +162 for(Class clazz : classes) { +163 defaultCompletions.put(clazz, id); +164 } +165 +166 return completion; +167 } +168 +169 @NotNull +170 List<String> of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) { +171 String[] completions = ACFPatterns.SPACE.split(cmd.complete); +172 final int argIndex = args.length - 1; +173 +174 String input = args[argIndex]; +175 +176 String completion = argIndex < completions.length ? completions[argIndex] : null; +177 if (completion == null && completions.length > 0) { +178 completion = completions[completions.length - 1]; +179 } +180 if (completion == null) { +181 return ImmutableList.of(input); +182 } +183 +184 return getCompletionValues(cmd, sender, completion, args, isAsync); +185 } +186 +187 List<String> getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) { +188 completion = manager.getCommandReplacements().replace(completion); +189 +190 List<String> allCompletions = Lists.newArrayList(); +191 String input = args.length > 0 ? args[args.length - 1] : ""; +192 +193 for (String value : ACFPatterns.PIPE.split(completion)) { +194 String[] complete = ACFPatterns.COLONEQUALS.split(value, 2); +195 CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase()); +196 if (handler != null) { +197 if (isAsync && !(handler instanceof AsyncCommandCompletionHandler)) { +198 ACFUtil.sneaky(new SyncCompletionRequired()); +199 return null; +200 } +201 String config = complete.length == 1 ? null : complete[1]; +202 CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args); +203 +204 try { +205 //noinspection unchecked +206 Collection<String> completions = handler.getCompletions(context); +207 if (completions != null) { +208 allCompletions.addAll(completions); +209 continue; +210 } +211 //noinspection ConstantIfStatement,ConstantConditions +212 if (false) { // Hack to fool compiler. since its sneakily thrown. +213 throw new CommandCompletionTextLookupException(); +214 } +215 } catch (CommandCompletionTextLookupException ignored) { +216 // This should only happen if some other feedback error occured. +217 } catch (Exception e) { +218 command.handleException(sender, Lists.newArrayList(args), e); +219 } +220 // Something went wrong in lookup, fall back to input +221 return ImmutableList.of(input); +222 } else { +223 // Plaintext value +224 allCompletions.add(value); +225 } +226 } +227 return allCompletions; +228 } +229 +230 public interface CommandCompletionHandler <C extends CommandCompletionContext> { +231 Collection<String> getCompletions(C context) throws InvalidCommandArgument; +232 } +233 public interface AsyncCommandCompletionHandler <C extends CommandCompletionContext> extends CommandCompletionHandler <C> {} +234 public static class SyncCompletionRequired extends Exception {} +235 +236} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/CatchUnknown.html b/docs/acf-core/src-html/co/aikar/commands/annotation/CatchUnknown.html index 236694c6..5a1e1298 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/CatchUnknown.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/CatchUnknown.html @@ -36,10 +36,19 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD}) -033public @interface CatchUnknown { -034} +031/** +032 * Defines a method that should receive any unknown command for the related root command. +033 * +034 * For example, if a BaseCommand /foo has a method with this, and /foo someunknowncommand is used +035 * +036 * If a method is tagged with this annotation, it will catch unknown commands and let you react to them. +037 * +038 * Only one instance of this annotation can be used per root command. +039 */ +040@Retention(RetentionPolicy.RUNTIME) +041@Target({ElementType.METHOD}) +042public @interface CatchUnknown { +043} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandAlias.html b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandAlias.html index 898da37c..5579279e 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandAlias.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandAlias.html @@ -36,11 +36,19 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD, ElementType.TYPE}) -033public @interface CommandAlias { -034 String value(); -035} +031/** +032 * Allows to add a single or several command alias(es). +033 * In order to add more than one in a single go, use the syntax "alias|otheralias". +034 * You can register as many aliases as wanted in a single value. +035 * +036 * Used on a Class, defines the root command for all subcommands in the base command. +037 * Used on a method, defines a root command alias to that specific command +038 */ +039@Retention(RetentionPolicy.RUNTIME) +040@Target({ElementType.METHOD, ElementType.TYPE}) +041public @interface CommandAlias { +042 String value(); +043} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandCompletion.html b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandCompletion.html index 7b39ea13..9c5e08b2 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandCompletion.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandCompletion.html @@ -36,11 +36,21 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD}) -033public @interface CommandCompletion { -034 String value(); -035} +031/** +032 * Many implementation platforms have a concept of "Tab Completions", +033 * where pressing tab will give suggestions on what you can input. +034 * +035 * This annotation specifies either static completion values, +036 * or special @codes that let you define Completion Handlers to dynamically +037 * populate completion values. +038 * +039 * @see {@link co.aikar.commands.CommandCompletions} +040 */ +041@Retention(RetentionPolicy.RUNTIME) +042@Target({ElementType.METHOD}) +043public @interface CommandCompletion { +044 String value(); +045} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html index c469d517..ed90fee8 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/CommandPermission.html @@ -36,11 +36,16 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD, ElementType.TYPE}) -033public @interface CommandPermission { -034 String value(); -035} +031/** +032 * Sets the permission required to perform this command. +033 * +034 * Permission format will vary based on implementation platform +035 */ +036@Retention(RetentionPolicy.RUNTIME) +037@Target({ElementType.METHOD, ElementType.TYPE}) +038public @interface CommandPermission { +039 String value(); +040} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Conditions.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Conditions.html index 27346d60..908b1ec5 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Conditions.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Conditions.html @@ -36,11 +36,19 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE}) -033public @interface Conditions { -034 String value(); -035} +031/** +032 * Specifies conditions that must be met in order to execute this command. +033 * +034 * If used on a method or a class, will be checked before parameter context is resolved +035 * If used on a parameter, will be checked after the context is resolved +036 * +037 * @see {@link co.aikar.commands.CommandConditions} +038 */ +039@Retention(RetentionPolicy.RUNTIME) +040@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE}) +041public @interface Conditions { +042 String value(); +043} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Default.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Default.html index 59147b77..841880bf 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Default.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Default.html @@ -36,11 +36,15 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD, ElementType.PARAMETER}) -033public @interface Default { -034 String value() default ""; -035} +031/** +032 * If used on a method, sets default command handler for the root command of this group +033 * If used on a parameter, sets the value to be used for context resolution +034 */ +035@Retention(RetentionPolicy.RUNTIME) +036@Target({ElementType.METHOD, ElementType.PARAMETER}) +037public @interface Default { +038 String value() default ""; +039} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Dependency.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Dependency.html index d8d31014..894d5472 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Dependency.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Dependency.html @@ -36,15 +36,19 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target(ElementType.FIELD) -033public @interface Dependency { -034 /** -035 * The key that should be used to lookup the instances, defaults to \"\" -036 * @return the key -037 */ -038 String value() default ""; -039} +031/** +032 * Injects a dependency into the field this is attached to. +033 * Any time a new dependency is registered, this will be overwritten. +034 */ +035@Retention(RetentionPolicy.RUNTIME) +036@Target(ElementType.FIELD) +037public @interface Dependency { +038 /** +039 * The key that should be used to lookup the instances, defaults to \"\" +040 * @return the key +041 */ +042 String value() default ""; +043} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Description.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Description.html index 6fe8b19a..c4eca736 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Description.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Description.html @@ -36,11 +36,15 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD, ElementType.PARAMETER}) -033public @interface Description { -034 String value(); -035} +031/** +032 * Sets a description to the parameter or method this is attached to. +033 * This is used in the help menus. +034 */ +035@Retention(RetentionPolicy.RUNTIME) +036@Target({ElementType.METHOD, ElementType.PARAMETER}) +037public @interface Description { +038 String value(); +039} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Flags.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Flags.html index e6fa2f0e..2305636e 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Flags.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Flags.html @@ -36,11 +36,18 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.PARAMETER}) -033public @interface Flags { -034 String value(); -035} +031/** +032 * Provides configuration options for {@link co.aikar.commands.contexts.ContextResolver}'s to change how they resolve context. +033 * +034 * Example: Searching for a player, you might use @Flags("loose") to indicate a fuzzy match instead of an exact match. +035 * +036 * If you want to restrict if an issuer can use the command, please use {@link co.aikar.commands.CommandConditions.Condition} instead. +037 */ +038@Retention(RetentionPolicy.RUNTIME) +039@Target({ElementType.PARAMETER}) +040public @interface Flags { +041 String value(); +042} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/HelpCommand.html b/docs/acf-core/src-html/co/aikar/commands/annotation/HelpCommand.html index 6b2fb6e7..f76654b1 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/HelpCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/HelpCommand.html @@ -36,11 +36,21 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD}) -033public @interface HelpCommand { -034 String value() default "help|?|-help|-h|-?"; -035} +031/** +032 * A Shortcut for specifying {@link CatchUnknown}, {@link Default} and {@link Subcommand} on a method. +033 * Subcommand carries the same value as this annotations value to define the list of subcommands to register for. +034 * +035 * a method marked with this annotation should also use a {@link co.aikar.commands.CommandHelp} context parameter to show help. +036 */ +037@Retention(RetentionPolicy.RUNTIME) +038@Target({ElementType.METHOD}) +039public @interface HelpCommand { +040 /** +041 * The value to forward to the @Subcommand annotation. Lists which subcommands to register to trigger help +042 * @return +043 */ +044 String value() default "help|?|-help|-h|-?"; +045} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/HelpSearchTags.html b/docs/acf-core/src-html/co/aikar/commands/annotation/HelpSearchTags.html index 3efeabab..e9042db1 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/HelpSearchTags.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/HelpSearchTags.html @@ -36,11 +36,17 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD}) -033public @interface HelpSearchTags { -034 String value(); -035} +031/** +032 * Defines additional keywords to feed into the search help system. +033 * +034 * For example, if a specific word doesn't make sense to use in the command name or description, but should +035 * be used for help in discovering the correct command, then you can add it as a tag. +036 */ +037@Retention(RetentionPolicy.RUNTIME) +038@Target({ElementType.METHOD}) +039public @interface HelpSearchTags { +040 String value(); +041} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Optional.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Optional.html index c325d2dc..5ffd4f65 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Optional.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Optional.html @@ -36,10 +36,17 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.PARAMETER}) -033public @interface Optional { -034} +031/** +032 * Marks the parameter this is attached to as optional. +033 * This will set the parameter as null if it was not provided. +034 * <p> +035 * In the case the language used is Kotlin, Ceylon or any other null-enforcing JVM language, +036 * you will need to allow for a nullable value. +037 */ +038@Retention(RetentionPolicy.RUNTIME) +039@Target({ElementType.PARAMETER}) +040public @interface Optional { +041} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/PreCommand.html b/docs/acf-core/src-html/co/aikar/commands/annotation/PreCommand.html index ba9ab372..a5149019 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/PreCommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/PreCommand.html @@ -37,9 +37,12 @@ 029import java.lang.annotation.RetentionPolicy; 030import java.lang.annotation.Target; 031 -032@Retention(RetentionPolicy.RUNTIME) -033@Target({ElementType.METHOD}) -034public @interface PreCommand {} +032/** +033 * This runs before any other command method each time it is invoked. +034 */ +035@Retention(RetentionPolicy.RUNTIME) +036@Target({ElementType.METHOD}) +037public @interface PreCommand {} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Single.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Single.html index f60fd266..151ab4d6 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Single.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Single.html @@ -37,12 +37,11 @@ 029import java.lang.annotation.Target; 030 031/** -032 * Don't join remaining arguments +032 * Don't join remaining arguments. Used on String parameters, which normally would combine the remaining arguments 033 */ -034 -035@Retention(RetentionPolicy.RUNTIME) -036@Target({ElementType.PARAMETER}) -037public @interface Single {} +034@Retention(RetentionPolicy.RUNTIME) +035@Target({ElementType.PARAMETER}) +036public @interface Single {} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Split.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Split.html index f707e7d7..97254097 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Split.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Split.html @@ -37,11 +37,15 @@ 029import java.lang.annotation.RetentionPolicy; 030import java.lang.annotation.Target; 031 -032@Retention(RetentionPolicy.RUNTIME) -033@Target({ElementType.PARAMETER}) -034public @interface Split { -035 String value() default ","; -036} +032/** +033 * Joins arguments into a single piece of text with the specified separator. +034 * For array based parameters, defines the regex pattern to split on +035 */ +036@Retention(RetentionPolicy.RUNTIME) +037@Target({ElementType.PARAMETER}) +038public @interface Split { +039 String value() default ","; +040} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Subcommand.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Subcommand.html index 0f77bea4..1a1273e8 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Subcommand.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Subcommand.html @@ -36,11 +36,18 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD, ElementType.TYPE}) -033public @interface Subcommand { -034 String value(); -035} +031/** +032 * Defines the subcommand that can be used to execute this command. +033 * This is appended onto the root command for the command group, +034 * as well as any parent command groups subcommand base. +035 * +036 * Defines the part after root command like so: "/rootcommand {@link #value()}". +037 */ +038@Retention(RetentionPolicy.RUNTIME) +039@Target({ElementType.METHOD, ElementType.TYPE}) +040public @interface Subcommand { +041 String value(); +042} diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Syntax.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Syntax.html index d620bca9..610a6fc5 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Syntax.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Syntax.html @@ -36,12 +36,21 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.METHOD, ElementType.PARAMETER}) -033public @interface Syntax { -034 String value(); -035} -036 +031/** +032 * Specifies the syntax to be used when executing this command. +033 * It should not include any descriptions of the arguments nor when some are allowed and when they are not. +034 * +035 * Use of this annotation is not necessary. Syntax will be automatically generated for you. +036 * Use this annotation to override automatic syntax +037 * +038 * Use {@link Description} together with the help menu for that purpose. +039 **/ +040@Retention(RetentionPolicy.RUNTIME) +041@Target({ElementType.METHOD, ElementType.PARAMETER}) +042public @interface Syntax { +043 String value(); +044} +045 diff --git a/docs/acf-core/src-html/co/aikar/commands/annotation/Values.html b/docs/acf-core/src-html/co/aikar/commands/annotation/Values.html index 60355e8b..7212c35f 100644 --- a/docs/acf-core/src-html/co/aikar/commands/annotation/Values.html +++ b/docs/acf-core/src-html/co/aikar/commands/annotation/Values.html @@ -36,11 +36,16 @@ 028import java.lang.annotation.RetentionPolicy; 029import java.lang.annotation.Target; 030 -031@Retention(RetentionPolicy.RUNTIME) -032@Target({ElementType.PARAMETER}) -033public @interface Values { -034 String value(); -035} +031/** +032 * Specifies a list of values that the command input should be validated against, or else show an error. +033 * +034 * You may also use {@link CommandCompletion} handler codes here to feed dynamic values and avoid repetition. +035 */ +036@Retention(RetentionPolicy.RUNTIME) +037@Target({ElementType.PARAMETER}) +038public @interface Values { +039 String value(); +040} diff --git a/docs/acf-core/src-html/co/aikar/commands/contexts/ContextResolver.html b/docs/acf-core/src-html/co/aikar/commands/contexts/ContextResolver.html index ebc06467..9406fb91 100644 --- a/docs/acf-core/src-html/co/aikar/commands/contexts/ContextResolver.html +++ b/docs/acf-core/src-html/co/aikar/commands/contexts/ContextResolver.html @@ -35,10 +35,29 @@ 027import co.aikar.commands.CommandIssuer; 028import co.aikar.commands.InvalidCommandArgument; 029 -030@FunctionalInterface -031public interface ContextResolver <T, C extends CommandExecutionContext<?, ? extends CommandIssuer>> { -032 T getContext(C c) throws InvalidCommandArgument; -033} +030/** +031 * This defines a context resolver, which parses {@link T} from {@link C}. +032 * +033 * @param <T> +034 * The type to be parsed. +035 * @param <C> +036 * The type of the context which the resolver would get its data from. +037 */ +038@FunctionalInterface +039public interface ContextResolver <T, C extends CommandExecutionContext<?, ? extends CommandIssuer>> { +040 /** +041 * Parses the context of type {@link C} into {@link T}, or throws an exception. +042 * +043 * @param c +044 * The context to parse from. +045 * +046 * @return The parsed instance of the wanted type. +047 * +048 * @throws InvalidCommandArgument +049 * In case the context contains any discrepancies, it will throw this exception. +050 */ +051 T getContext(C c) throws InvalidCommandArgument; +052} diff --git a/docs/acf-core/src-html/co/aikar/commands/contexts/OptionalContextResolver.html b/docs/acf-core/src-html/co/aikar/commands/contexts/OptionalContextResolver.html index 0acdce4f..d8f52465 100644 --- a/docs/acf-core/src-html/co/aikar/commands/contexts/OptionalContextResolver.html +++ b/docs/acf-core/src-html/co/aikar/commands/contexts/OptionalContextResolver.html @@ -35,9 +35,14 @@ 027import co.aikar.commands.CommandIssuer; 028 029/** -030 * Context Resolver that can accept null input -031 */ -032public interface OptionalContextResolver <T, C extends CommandExecutionContext<?, ? extends CommandIssuer>> extends ContextResolver <T, C> {} +030 * The same as {@link ContextResolver}, however it can accept a null context. +031 * +032 * If the parameter was marked optional, will still be called with an empty args list +033 * +034 * @param <T> +035 * @param <C> +036 */ +037public interface OptionalContextResolver <T, C extends CommandExecutionContext<?, ? extends CommandIssuer>> extends ContextResolver <T, C> {} diff --git a/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html b/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html index e53df14b..5099a0b6 100644 --- a/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html +++ b/docs/acf-jda/co/aikar/commands/JDACommandCompletions.html @@ -177,6 +177,13 @@ extends co.aikar.commands.CommandCompletions<co.aikar.commands.CommandComplet
      +
    • + + +

      Methods inherited from class co.aikar.commands.CommandCompletions

      +registerStaticCompletion, registerStaticCompletion, registerStaticCompletion, registerStaticCompletion
    • +
    +
    • diff --git a/docs/acf-paper/co/aikar/commands/PaperCommandCompletions.html b/docs/acf-paper/co/aikar/commands/PaperCommandCompletions.html index bcd94e6d..e69440b2 100644 --- a/docs/acf-paper/co/aikar/commands/PaperCommandCompletions.html +++ b/docs/acf-paper/co/aikar/commands/PaperCommandCompletions.html @@ -162,7 +162,7 @@ extends co.aikar.commands.BukkitCommandCompletions

      Methods inherited from class co.aikar.commands.CommandCompletions

      -registerAsyncCompletion, registerCompletion
    • +registerAsyncCompletion, registerCompletion, registerStaticCompletion, registerStaticCompletion, registerStaticCompletion, registerStaticCompletion