More Documentation

This commit is contained in:
Aikar
2018-05-31 19:33:48 -04:00
parent 0be34242db
commit 27eb9fa733
10 changed files with 115 additions and 14 deletions
@@ -62,6 +62,17 @@ import java.util.Stack;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 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
*/
@SuppressWarnings("unused")
public abstract class BaseCommand {
@@ -76,16 +87,40 @@ public abstract class BaseCommand {
*/
static final String DEFAULT = "__default";
/**
* A map of all the registered commands for this base command, keyed to each potential subcommand to access it.
*/
final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create();
final Map<Class<?>, String> contextFlags = Maps.newHashMap();
private Method preCommandHandler;
/**
* A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each.
*/
final Map<Class<?>, String> contextFlags = Maps.newHashMap();
/**
* What method was annoated with {@link PreCommand} to execute before commands.
*/
@Nullable private Method preCommandHandler;
/**
* What root command the user actually entered to access the currently executing command
*/
@SuppressWarnings("WeakerAccess")
private String execLabel;
/**
* What subcommand the user actually entered to access the currently executing command
*/
@SuppressWarnings("WeakerAccess")
private String execSubcommand;
/**
* What arguments the user actually entered after the root command to access the currently executing command
*/
@SuppressWarnings("WeakerAccess")
private String[] origArgs;
/**
* The manager this is registered to
*/
CommandManager<?, ?, ?, ?, ?, ?> manager = null;
/**
@@ -125,7 +160,14 @@ public abstract class BaseCommand {
@Nullable private String parentSubcommand;
public BaseCommand() {}
public BaseCommand(String cmd) {
/**
* Constructor based defining of commands will be removed in the next version bump.
* @deprecated Please switch to {@link CommandAlias} for defining all root commands.
* @param cmd
*/
@Deprecated
public BaseCommand(@Nullable String cmd) {
this.commandName = cmd;
}
@@ -153,10 +195,6 @@ public abstract class BaseCommand {
return origArgs;
}
void setParentCommand(BaseCommand command) {
this.parentCommand = command;
}
/**
* This should be called whenever the command gets registered.
* It sets all required fields correctly and injects dependencies.
@@ -177,7 +215,7 @@ public abstract class BaseCommand {
* @param cmd
* The command name to use register with.
*/
void onRegister(CommandManager manager, String cmd) {
private void onRegister(CommandManager manager, String cmd) {
manager.injectDependencies(this);
this.manager = manager;
@@ -237,7 +275,7 @@ public abstract class BaseCommand {
}
}
if (subCommand != null) {
subCommand.setParentCommand(this);
subCommand.parentCommand = this;
subCommand.onRegister(manager, cmd);
this.subCommands.putAll(subCommand.subCommands);
this.registeredCommands.putAll(subCommand.registeredCommands);
@@ -258,7 +296,7 @@ public abstract class BaseCommand {
final Annotations annotations = manager.getAnnotations();
boolean foundDefault = false;
boolean foundCatchUnknown = false;
boolean isParentEmpty = parentSubcommand.isEmpty();
boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty();
for (Method method : this.getClass().getMethods()) {
method.setAccessible(true);
@@ -582,7 +620,7 @@ public abstract class BaseCommand {
int required = c.requiredResolvers;
int optional = c.optionalResolvers;
return extraArgs <= required + optional && (completion || extraArgs >= required);
}).sorted((c1, c2) -> {
}).min((c1, c2) -> {
int a = c1.consumeInputResolvers;
int b = c2.consumeInputResolvers;
@@ -590,7 +628,7 @@ public abstract class BaseCommand {
return 0;
}
return a < b ? 1 : -1;
}).findFirst();
});
if (optCmd.isPresent()) {
cmd = optCmd.get();
}
@@ -624,6 +662,7 @@ public abstract class BaseCommand {
* @param cmd
* @return
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) {
return true;
@@ -660,6 +699,7 @@ public abstract class BaseCommand {
*
* @return The possibilities to tab complete in no particular order.
*/
@SuppressWarnings("WeakerAccess")
public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync)
throws IllegalArgumentException {
@@ -28,6 +28,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Defines a method that should receive any unknown command for the related root command.
*
* For example, if a BaseCommand /foo has a method with this, and /foo someunknowncommand is used
*
* If a method is tagged with this annotation, it will catch unknown commands and let you react to them.
*
* Only one instance of this annotation can be used per root command.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CatchUnknown {
@@ -28,6 +28,16 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 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 {@link co.aikar.commands.CommandCompletions}
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CommandCompletion {
@@ -28,6 +28,14 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 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 {@link co.aikar.commands.CommandConditions}
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
public @interface Conditions {
@@ -28,6 +28,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Provides configuration options for {@link co.aikar.commands.contexts.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 {@link co.aikar.commands.CommandConditions.Condition} instead.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Flags {
@@ -28,8 +28,18 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A Shortcut for specifying {@link CatchUnknown}, {@link Default} and {@link 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 {@link co.aikar.commands.CommandHelp} context parameter to show help.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface HelpCommand {
/**
* The value to forward to the @Subcommand annotation. Lists which subcommands to register to trigger help
* @return
*/
String value() default "help|?|-help|-h|-?";
}
@@ -28,6 +28,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 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.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface HelpSearchTags {
@@ -29,9 +29,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Don't join remaining arguments
* Don't join remaining arguments. Used on String parameters, which normally would combine the remaining arguments
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Single {}
@@ -28,6 +28,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 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 {@link #value()}".
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Subcommand {
@@ -28,6 +28,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifies a list of values that the command input should be validated against, or else show an error.
*
* You may also use {@link CommandCompletion} handler codes here to feed dynamic values and avoid repetition.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Values {