diff --git a/core/src/main/java/co/aikar/commands/ACFPatterns.java b/core/src/main/java/co/aikar/commands/ACFPatterns.java
index ee4e9b42..fc4765bb 100644
--- a/core/src/main/java/co/aikar/commands/ACFPatterns.java
+++ b/core/src/main/java/co/aikar/commands/ACFPatterns.java
@@ -60,6 +60,18 @@ final class ACFPatterns {
.expirationPolicy(ExpirationPolicy.ACCESSED)
.build();
+ /**
+ * Gets a pattern and compiles it.
+ * If the pattern is stored already in {@link #patternCache}, it will simply fetch it from there.
+ * If it is not, it will store it there for further use.
+ *
+ * The {@link #patternCache} does not contain the constant patterns defined in this class.
+ *
+ * @param pattern
+ * The raw pattern in a String.
+ *
+ * @return The pattern which has been cached.
+ */
public static Pattern getPattern(String pattern) {
return patternCache.computeIfAbsent(pattern, s -> Pattern.compile(pattern));
}
diff --git a/core/src/main/java/co/aikar/commands/AnnotationLookups.java b/core/src/main/java/co/aikar/commands/AnnotationLookups.java
index 72c52019..1089a333 100644
--- a/core/src/main/java/co/aikar/commands/AnnotationLookups.java
+++ b/core/src/main/java/co/aikar/commands/AnnotationLookups.java
@@ -29,25 +29,111 @@ import java.util.regex.Pattern;
abstract class AnnotationLookups {
+ /**
+ * This checks whether the {@link AnnotatedElement} given has an annotation of the type given as annoClass.
+ *
+ * Runs through annotation processing
+ *
+ * @param object
+ * The element to check whether has an annotation of annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ *
+ * @return Whether an annotation of annoClass is attached to element.
+ *
+ * @see #hasAnnotation(AnnotatedElement, Class, boolean)
+ */
boolean hasAnnotation(AnnotatedElement object, Class extends Annotation> annoClass) {
return getAnnotationValue(object, annoClass, Annotations.NOTHING) != null;
}
+ /**
+ * This checks whether the {@link AnnotatedElement} given has an annotation of the type given as annoClass.
+ * If the value is empty/null and allowEmpty is false, it will return false.
+ *
+ * @param object
+ * The element to check whether has an annotation of annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ * @param allowEmpty
+ * Whether or not to allow empty/null values.
+ *
+ * @return Whether an annotation of annoClass is attached to element, and if allowEmpty is false, whether it has a value.
+ */
boolean hasAnnotation(AnnotatedElement object, Class extends Annotation> annoClass, boolean allowEmpty) {
return getAnnotationValue(object, annoClass, Annotations.NOTHING | (allowEmpty ? 0 : Annotations.NO_EMPTY)) != null;
}
+ /**
+ * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has.
+ * If the value contains a pipe (|), it will split on this and return an array of more indicies than 1.
+ *
+ * @param object
+ * The element to check the value of the annotation of type annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ *
+ * @return All the values of annoClass on the object split by pipe (|). If the value is empty, this is null.
+ *
+ * @see #getAnnotationValues(AnnotatedElement, Class, Pattern, int)
+ */
String[] getAnnotationValues(AnnotatedElement object, Class extends Annotation> annoClass) {
return getAnnotationValues(object, annoClass, ACFPatterns.PIPE, Annotations.REPLACEMENTS);
}
+
+ /**
+ * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has.
+ * The value is split by the pattern given and return an array of more indicies than 1.
+ *
+ * @param object
+ * The element to check the value of the annotation of type annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ * @param pattern
+ * The pattern the value element is split on.
+ *
+ * @return All the values of annoClass on the object split by the pattern given. If the value is empty, this is null.
+ *
+ * @see #getAnnotationValues(AnnotatedElement, Class, Pattern, int)
+ */
String[] getAnnotationValues(AnnotatedElement object, Class extends Annotation> annoClass, Pattern pattern) {
return getAnnotationValues(object, annoClass, pattern, Annotations.REPLACEMENTS);
}
+ /**
+ * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has.
+ * The value is split by all pipes (|), but must follow the options.
+ *
+ * @param object
+ * The element to check the value of the annotation of type annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ * @param options
+ * The options to use. If several options are wanted, use the OR operator (opt1 | opt2).
+ *
+ * @return All the values of annoClass on the object split by a pipe (|). Nullability depends on options.
+ *
+ * @see #getAnnotationValues(AnnotatedElement, Class, Pattern, int)
+ */
String[] getAnnotationValues(AnnotatedElement object, Class extends Annotation> annoClass, int options) {
return getAnnotationValues(object, annoClass, ACFPatterns.PIPE, options);
}
+ /**
+ * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has.
+ * The value is split by the pattern given, and must also follow the options.
+ *
+ * @param object
+ * The element to check the value of the annotation of type annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ * @param options
+ * The options to use. If several options are wanted, use the OR operator (opt1 | opt2).
+ * @param pattern
+ * The pattern to split by each occurrence of.
+ *
+ * @return All the values of annoClass on the object split by the pattern given. Nullability depends on options.
+ */
String[] getAnnotationValues(AnnotatedElement object, Class extends Annotation> annoClass, Pattern pattern, int options) {
String value = getAnnotationValue(object, annoClass, options);
if (value == null) {
@@ -56,9 +142,32 @@ abstract class AnnotationLookups {
return pattern.split(value);
}
+ /**
+ * Gets the value of the {@link AnnotatedElement}'s annotation of type annoClass as a string.
+ *
+ * @param object
+ * The element to check the value of the annotation of type annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ *
+ * @return The value of the annotation on the object given.
+ */
String getAnnotationValue(AnnotatedElement object, Class extends Annotation> annoClass) {
return getAnnotationValue(object, annoClass, Annotations.REPLACEMENTS);
}
- abstract String getAnnotationValue(AnnotatedElement annotation, Class extends Annotation> annoClass, int options);
+ /**
+ * Gets the value of the {@link AnnotatedElement}'s annotation of type annoClass as a string.
+ * The value has to follow the given options.
+ *
+ * @param object
+ * The element to check the value of the annotation of type annoClass.
+ * @param annoClass
+ * The annotation type in form of a class.
+ * @param options
+ * The options to use. If several options are wanted, use the OR operator (opt1 | opt2).
+ *
+ * @return The value of the annotation on the object given. Nullability depends on options.
+ */
+ abstract String getAnnotationValue(AnnotatedElement object, Class extends Annotation> annoClass, int options);
}
diff --git a/core/src/main/java/co/aikar/commands/Annotations.java b/core/src/main/java/co/aikar/commands/Annotations.java
index f9a05b08..7821f28e 100644
--- a/core/src/main/java/co/aikar/commands/Annotations.java
+++ b/core/src/main/java/co/aikar/commands/Annotations.java
@@ -49,8 +49,8 @@ class Annotations extends AnnotationLookups {
this.manager = manager;
}
- String getAnnotationValue(AnnotatedElement element, Class extends Annotation> annoClass, int options) {
- Annotation annotation = element.getAnnotation(annoClass);
+ String getAnnotationValue(AnnotatedElement object, Class extends Annotation> annoClass, int options) {
+ Annotation annotation = object.getAnnotation(annoClass);
String value = null;
if (annotation != null) {
diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java
index 50d0a357..424dcb6a 100644
--- a/core/src/main/java/co/aikar/commands/BaseCommand.java
+++ b/core/src/main/java/co/aikar/commands/BaseCommand.java
@@ -42,6 +42,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
+import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -64,8 +65,17 @@ import java.util.stream.Stream;
@SuppressWarnings("unused")
public abstract class BaseCommand {
- public static final String CATCHUNKNOWN = "__catchunknown";
- public static final String DEFAULT = "__default";
+ /**
+ * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown
+ * argument to command states.
+ */
+ static final String CATCHUNKNOWN = "__catchunknown";
+ /**
+ * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the
+ * entire base command.
+ */
+ static final String DEFAULT = "__default";
+
final SetMultimap subCommands = HashMultimap.create();
final Map, String> contextFlags = Maps.newHashMap();
private Method preCommandHandler;
@@ -77,16 +87,42 @@ public abstract class BaseCommand {
@SuppressWarnings("WeakerAccess")
private String[] origArgs;
CommandManager, ?, ?, ?, ?, ?> manager = null;
+
+ /**
+ * The command which owns this. This may be null if there are no owners.
+ */
BaseCommand parentCommand;
Map registeredCommands = new HashMap<>();
- String description;
- String commandName;
- String permission;
- String conditions;
+ /**
+ * The description of the command. This may be null if no description has been provided.
+ * Used for help documentation
+ */
+ @Nullable String description;
+ /**
+ * The name of the command. This may be null if no name has been provided.
+ */
+ @Nullable String commandName;
+ /**
+ * The permission of the command. This may be null if no permission has been provided.
+ */
+ @Nullable String permission;
+ /**
+ * The conditions of the command. This may be null if no conditions has been provided.
+ */
+ @Nullable String conditions;
+ /**
+ * The handler of all uncaught exceptions thrown by the user's command implementation.
+ */
private ExceptionHandler exceptionHandler = null;
- CommandOperationContext lastCommandOperationContext;
- private String parentSubcommand;
+ /**
+ * The last operative context data of this command. This may be null if this command hasn't been run yet.
+ */
+ @Nullable CommandOperationContext lastCommandOperationContext;
+ /**
+ * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this
+ */
+ @Nullable private String parentSubcommand;
public BaseCommand() {}
public BaseCommand(String cmd) {
@@ -120,9 +156,27 @@ public abstract class BaseCommand {
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.
+ *
+ * @param manager
+ * The manager to register as this command's owner and handler.
+ */
void onRegister(CommandManager manager) {
onRegister(manager, this.commandName);
}
+
+ /**
+ * This should be called whenever the command gets registered.
+ * It sets all required fields correctly and injects dependencies.
+ *
+ * @param manager
+ * The manager to register as this command's owner and handler.
+ * @param cmd
+ * The command name to use register with.
+ */
void onRegister(CommandManager manager, String cmd) {
manager.injectDependencies(this);
this.manager = manager;
@@ -160,6 +214,12 @@ public abstract class BaseCommand {
}
+ /**
+ * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}.
+ *
+ * @param cmd
+ * The command name of this command.
+ */
private void registerSubclasses(String cmd) {
for (Class> clazz : this.getClass().getDeclaredClasses()) {
if (BaseCommand.class.isAssignableFrom(clazz)) {
@@ -191,6 +251,9 @@ public abstract class BaseCommand {
}
}
+ /**
+ * This registers all subcommands of the command.
+ */
private void registerSubcommands() {
final Annotations annotations = manager.getAnnotations();
boolean foundDefault = false;
@@ -256,6 +319,14 @@ public abstract class BaseCommand {
}
}
+ /**
+ * Gets the subcommand name of the method given.
+ *
+ * @param method
+ * The method to check.
+ *
+ * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached.
+ */
private String getSubcommandValue(Method method) {
final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING);
if (sub == null) {
@@ -279,6 +350,14 @@ public abstract class BaseCommand {
return ACFUtil.join(subList, " ");
}
+ /**
+ * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given.
+ *
+ * @param name
+ * Name of the parent to cmd.
+ * @param cmd
+ * The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field.
+ */
private void register(String name, BaseCommand cmd) {
String nameLower = name.toLowerCase();
RootCommand rootCommand = manager.obtainRootCommand(nameLower);
@@ -287,6 +366,14 @@ public abstract class BaseCommand {
this.registeredCommands.put(nameLower, rootCommand);
}
+ /**
+ * Registers the given {@link Method} as a subcommand.
+ *
+ * @param method
+ * The method to register as a subcommand.
+ * @param subCommand
+ * The subcommand's name(s).
+ */
private void registerSubcommand(Method method, String subCommand) {
subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase());
final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand);
@@ -373,13 +460,13 @@ public abstract class BaseCommand {
}
if (subCommands.get(DEFAULT) != null && args.length == 0) {
- executeSubcommand(commandContext, DEFAULT, issuer, args);
+ findAndExecuteCommand(commandContext, DEFAULT, issuer, args);
} else if (subCommands.get(CATCHUNKNOWN) != null) {
- if (!executeSubcommand(commandContext, CATCHUNKNOWN, issuer, args)) {
+ if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) {
help(issuer, args);
}
} else if (subCommands.get(DEFAULT) != null) {
- executeSubcommand(commandContext, DEFAULT, issuer, args);
+ findAndExecuteCommand(commandContext, DEFAULT, issuer, args);
}
} finally {
@@ -387,11 +474,23 @@ public abstract class BaseCommand {
}
}
+ /**
+ * Gets the registered command of the given arguments.
+ * @param args
+ * The arguments given by the user.
+ *
+ * @return The subcommand or null if none were found.
+ *
+ * @see #findSubCommand(String[])
+ */
RegisteredCommand> getRegisteredCommand(String[] args) {
final CommandSearch cmd = findSubCommand(args);
return cmd != null ? cmd.cmd : null;
}
+ /**
+ * This is ran after any command operation has been performed.
+ */
private void postCommandOperation() {
CommandManager.commandOperationContext.get().pop();
execSubcommand = null;
@@ -399,6 +498,22 @@ public abstract class BaseCommand {
origArgs = new String[]{};
}
+ /**
+ * This is ran before any command operation has been performed.
+ *
+ * @param issuer
+ * The user who executed the command.
+ * @param commandLabel
+ * The label the user used to execute the command. This is not the command name, but their input.
+ * When there is multiple aliases, this is which alias was used
+ * @param args
+ * The arguments passed to the command when executing it.
+ * @param isAsync
+ * Whether the command is executed off of the main thread.
+ *
+ * @return The context which is being registered to the {@link CommandManager}'s {@link
+ * CommandManager#commandOperationContext thread local stack}.
+ */
private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) {
Stack contexts = CommandManager.commandOperationContext.get();
CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync);
@@ -410,16 +525,48 @@ public abstract class BaseCommand {
return context;
}
+ /**
+ * Gets the current command issuer.
+ *
+ * @return The current command issuer.
+ */
public CommandIssuer getCurrentCommandIssuer() {
return CommandManager.getCurrentCommandIssuer();
}
+
+ /**
+ * Gets the current command manager.
+ *
+ * @return The current command manager.
+ */
public CommandManager getCurrentCommandManager() {
return CommandManager.getCurrentCommandManager();
}
+ /**
+ * Finds a subcommand of the given arguments.
+ *
+ * @param args
+ * The arguments the user input.
+ *
+ * @return The identified subcommand.
+ *
+ * @see #findSubCommand(String[], boolean)
+ */
private CommandSearch findSubCommand(String[] args) {
return findSubCommand(args, false);
}
+
+ /**
+ * Finds a subcommand of the given arguments.
+ *
+ * @param args
+ * The arguments the user input.
+ * @param completion
+ * Whether or not completion of arguments should kick in. This may end up with worse than wanted results.
+ *
+ * @return The identified subcommand.
+ */
private CommandSearch findSubCommand(String[] args, boolean completion) {
for (int i = args.length; i >= 0; i--) {
String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase();
@@ -470,13 +617,49 @@ public abstract class BaseCommand {
}
}
+ /**
+ * Please use command conditions for restricting execution
+ * @deprecated See {@link CommandConditions}
+ * @param issuer
+ * @param cmd
+ * @return
+ */
+ @Deprecated
public boolean canExecute(CommandIssuer issuer, RegisteredCommand> cmd) {
return true;
}
+ /**
+ * Gets tab completed data from the given command from the user.
+ *
+ * @param issuer
+ * The user who executed the tabcomplete.
+ * @param commandLabel
+ * The label which is being used by the user.
+ * @param args
+ * The arguments the user has typed so far.
+ *
+ * @return All possibilities in the tab complete.
+ */
public List tabComplete(CommandIssuer issuer, String commandLabel, String[] args) {
return tabComplete(issuer, commandLabel, args, false);
}
+
+ /**
+ * 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.
+ *
+ * @param issuer
+ * The issuer of the command.
+ * @param commandLabel
+ * The command name as entered by the user instead of the ACF registered name.
+ * @param args
+ * All arguments entered by the user.
+ * @param isAsync
+ * Whether this is run off of the main thread.
+ *
+ * @return The possibilities to tab complete in no particular order.
+ */
public List tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync)
throws IllegalArgumentException {
@@ -506,6 +689,15 @@ public abstract class BaseCommand {
}
}
+ /**
+ * Gets all subcommands which are possible to tabcomplete.
+ *
+ * @param issuer
+ * The command issuer.
+ * @param args
+ *
+ * @return
+ */
List getCommandsForCompletion(CommandIssuer issuer, String[] args) {
final Set cmds = new HashSet<>();
final int cmdIndex = Math.max(0, args.length - 1);
@@ -525,6 +717,22 @@ public abstract class BaseCommand {
return new ArrayList<>(cmds);
}
+ /**
+ * Complete a command properly per issuer and input.
+ *
+ * @param issuer
+ * The user who executed this.
+ * @param cmd
+ * The command to be completed.
+ * @param args
+ * All arguments given by the user.
+ * @param commandLabel
+ * The command name the user used.
+ * @param isAsync
+ * Whether the command was executed async.
+ *
+ * @return All results to complete the command.
+ */
private List completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) {
if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) {
return ImmutableList.of();
@@ -534,6 +742,16 @@ public abstract class BaseCommand {
return filterTabComplete(args[args.length-1], cmds);
}
+ /**
+ * Gets the actual args in string form the user typed
+ * This returns a list of all tab complete options which are possible with the given argument and commands.
+ * @param arg
+ * Argument which was pressed tab on.
+ * @param cmds
+ * The possibilities to return.
+ *
+ * @return All possible options. This may be empty.
+ */
private static List filterTabComplete(String arg, List cmds) {
return cmds.stream()
.distinct()
@@ -541,11 +759,30 @@ public abstract class BaseCommand {
.collect(Collectors.toList());
}
- RegisteredCommand getSubcommand(String subcommand) {
- return getSubcommand(subcommand, false);
+ /**
+ * Gets a registered command under the given subcommand name.
+ *
+ * @param subcommand
+ * The name of the subcommand requested.
+ *
+ * @return The subcommand found or null if none.
+ */
+ private RegisteredCommand getCommandBySubcommand(String subcommand) {
+ return getCommandBySubcommand(subcommand, false);
}
- RegisteredCommand getSubcommand(String subcommand, boolean requireOne) {
+ /**
+ * Gets a registered command under the given name.
+ * If requireOne is true, it won't accept more than a single matching subcommand.
+ *
+ * @param subcommand
+ * Name of the subcommand wanted.
+ * @param requireOne
+ * Whether to only accept 1 result.
+ *
+ * @return The subcommand found, or null if none/too many.
+ */
+ private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) {
final Set commands = subCommands.get(subcommand);
if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) {
return commands.iterator().next();
@@ -553,8 +790,27 @@ public abstract class BaseCommand {
return null;
}
- private boolean executeSubcommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) {
- final RegisteredCommand cmd = this.getSubcommand(subcommand);
+ /**
+ * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)}
+ * and gets through {@link #getCommandBySubcommand(String)}.
+ *
+ * @param commandContext
+ * The command context to use.
+ * @param subcommand
+ * The subcommand to find the executor of.
+ * @param issuer
+ * The issuer who executed the subcommand.
+ * @param args
+ * All arguments given by the issuer.
+ *
+ * @return Whether it found a command or not.
+ *
+ * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)
+ * @see #getCommandBySubcommand(String)
+ * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext)
+ */
+ private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) {
+ final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand);
if (cmd != null) {
executeCommand(commandContext, issuer, args, cmd);
return true;
@@ -563,6 +819,20 @@ public abstract class BaseCommand {
return false;
}
+ /**
+ * Executes the precommand and sees whether something is wrong. Ideally, you get false from this.
+ *
+ * @param commandOperationContext
+ * The context to use.
+ * @param cmd
+ * The command executed.
+ * @param issuer
+ * The issuer who executed the command.
+ * @param args
+ * The arguments the issuer provided.
+ *
+ * @return Whether something went wrong.
+ */
private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) {
Method pre = this.preCommandHandler;
if (pre != null) {
@@ -657,7 +927,7 @@ public abstract class BaseCommand {
}
public RegisteredCommand getDefaultRegisteredCommand() {
- return this.getSubcommand(DEFAULT);
+ return this.getCommandBySubcommand(DEFAULT);
}
public String setContextFlags(Class> cls, String flags) {
diff --git a/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java b/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java
index 2b1ab723..54b6c6dd 100644
--- a/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java
+++ b/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java
@@ -28,6 +28,14 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Allows to add a single or several command alias(es).
+ * In order to add more than one in a single go, use the syntax "alias|otheralias".
+ * You can register as many aliases as wanted in a single value.
+ *
+ * Used on a Class, defines the root command for all subcommands in the base command.
+ * Used on a method, defines a root command alias to that specific command
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CommandAlias {
diff --git a/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java b/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java
index 919bb6a6..96c3111a 100644
--- a/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java
+++ b/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java
@@ -28,6 +28,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Sets the permission required to perform this command.
+ *
+ * Permission format will vary based on implementation platform
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CommandPermission {
diff --git a/core/src/main/java/co/aikar/commands/annotation/Default.java b/core/src/main/java/co/aikar/commands/annotation/Default.java
index 2d60ca90..93be2219 100644
--- a/core/src/main/java/co/aikar/commands/annotation/Default.java
+++ b/core/src/main/java/co/aikar/commands/annotation/Default.java
@@ -28,6 +28,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * 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
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface Default {
diff --git a/core/src/main/java/co/aikar/commands/annotation/Dependency.java b/core/src/main/java/co/aikar/commands/annotation/Dependency.java
index 5b19d810..4df4d200 100644
--- a/core/src/main/java/co/aikar/commands/annotation/Dependency.java
+++ b/core/src/main/java/co/aikar/commands/annotation/Dependency.java
@@ -28,6 +28,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Injects a dependency into the field this is attached to.
+ * Any time a new dependency is registered, this will be overwritten.
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Dependency {
diff --git a/core/src/main/java/co/aikar/commands/annotation/Description.java b/core/src/main/java/co/aikar/commands/annotation/Description.java
index 6de1260d..96aa234e 100644
--- a/core/src/main/java/co/aikar/commands/annotation/Description.java
+++ b/core/src/main/java/co/aikar/commands/annotation/Description.java
@@ -28,6 +28,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Sets a description to the parameter or method this is attached to.
+ * This is used in the help menus.
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface Description {
diff --git a/core/src/main/java/co/aikar/commands/annotation/Optional.java b/core/src/main/java/co/aikar/commands/annotation/Optional.java
index a6e1618a..b7a96ead 100644
--- a/core/src/main/java/co/aikar/commands/annotation/Optional.java
+++ b/core/src/main/java/co/aikar/commands/annotation/Optional.java
@@ -28,6 +28,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * 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.
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Optional {
diff --git a/core/src/main/java/co/aikar/commands/annotation/PreCommand.java b/core/src/main/java/co/aikar/commands/annotation/PreCommand.java
index 6c7a5e21..3fa16168 100644
--- a/core/src/main/java/co/aikar/commands/annotation/PreCommand.java
+++ b/core/src/main/java/co/aikar/commands/annotation/PreCommand.java
@@ -29,6 +29,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * This runs before any other command method each time it is invoked.
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface PreCommand {}
diff --git a/core/src/main/java/co/aikar/commands/annotation/Split.java b/core/src/main/java/co/aikar/commands/annotation/Split.java
index 2b375d64..994e4de2 100644
--- a/core/src/main/java/co/aikar/commands/annotation/Split.java
+++ b/core/src/main/java/co/aikar/commands/annotation/Split.java
@@ -29,6 +29,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * Joins arguments into a single piece of text with the specified separator.
+ * For array based parameters, defines the regex pattern to split on
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Split {
diff --git a/core/src/main/java/co/aikar/commands/annotation/Syntax.java b/core/src/main/java/co/aikar/commands/annotation/Syntax.java
index e88f6d86..2f5072e4 100644
--- a/core/src/main/java/co/aikar/commands/annotation/Syntax.java
+++ b/core/src/main/java/co/aikar/commands/annotation/Syntax.java
@@ -28,6 +28,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * 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 {@link Description} together with the help menu for that purpose.
+ **/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface Syntax {
diff --git a/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java b/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java
index 5f2088c5..9b221a02 100644
--- a/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java
+++ b/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java
@@ -27,7 +27,26 @@ import co.aikar.commands.CommandExecutionContext;
import co.aikar.commands.CommandIssuer;
import co.aikar.commands.InvalidCommandArgument;
+/**
+ * This defines a context resolver, which parses {@link T} from {@link C}.
+ *
+ * @param
+ * The type to be parsed.
+ * @param
+ * The type of the context which the resolver would get its data from.
+ */
@FunctionalInterface
public interface ContextResolver > {
+ /**
+ * Parses the context of type {@link C} into {@link T}, or throws an exception.
+ *
+ * @param c
+ * The context to parse from.
+ *
+ * @return The parsed instance of the wanted type.
+ *
+ * @throws InvalidCommandArgument
+ * In case the context contains any discrepancies, it will throw this exception.
+ */
T getContext(C c) throws InvalidCommandArgument;
}
diff --git a/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java b/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java
index cb734c1e..15879fcc 100644
--- a/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java
+++ b/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java
@@ -27,6 +27,11 @@ import co.aikar.commands.CommandExecutionContext;
import co.aikar.commands.CommandIssuer;
/**
- * Context Resolver that can accept null input
+ * The same as {@link ContextResolver}, however it can accept a null context.
+ *
+ * If the parameter was marked optional, will still be called with an empty args list
+ *
+ * @param
+ * @param
*/
public interface OptionalContextResolver > extends ContextResolver {}