From 0f196f59c6a4cb76ab8409da62ff1f35505f94a8 Mon Sep 17 00:00:00 2001 From: Dico Karssiens Date: Sun, 11 Nov 2018 14:06:45 +0000 Subject: Changes I made before breaking my local repository. Hoping this works. --- .../io/dico/dicore/command/CommandBuilder.java | 864 ++++++++++----------- 1 file changed, 432 insertions(+), 432 deletions(-) (limited to 'dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java') diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java b/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java index e527f27..118dd0f 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java @@ -1,432 +1,432 @@ -package io.dico.dicore.command; - -import io.dico.dicore.command.chat.IChatHandler; -import io.dico.dicore.command.parameter.type.IParameterTypeSelector; -import io.dico.dicore.command.parameter.type.MapBasedParameterTypeSelector; -import io.dico.dicore.command.parameter.type.ParameterType; -import io.dico.dicore.command.predef.HelpCommand; -import io.dico.dicore.command.predef.PredefinedCommand; -import io.dico.dicore.command.predef.SyntaxCommand; -import io.dico.dicore.command.registration.reflect.ReflectiveRegistration; - -import java.util.HashSet; -import java.util.Objects; -import java.util.function.Consumer; - -/** - * Mimic of WorldEdit's CommandGraph - */ -public final class CommandBuilder { - private final RootCommandAddress root; - private ModifiableCommandAddress cur; - private IParameterTypeSelector selector; - - /** - * Instantiate a new CommandBuilder with a new command root system - * Commands registered to this command builder might interfere with - * commands registered to other commands builders or by other plugins. - */ - public CommandBuilder() { - this(new RootCommandAddress()); - } - - /** - * Instantiate a new CommandBuilder with a specified root address. - * If the root address is identical to that of another command builder, - * they will modify the same tree. - * - * @param root the root address - */ - public CommandBuilder(RootCommandAddress root) { - this.root = Objects.requireNonNull(root); - this.cur = root; - this.selector = new MapBasedParameterTypeSelector(true); - } - - /** - * Add a sub command at the current address - * The current address can be inspected using {@link #getAddress()} - * - * @param name the name of the command - * @param command the command executor - * @param aliases any aliases - * @return this - */ - public CommandBuilder addSubCommand(String name, Command command, String... aliases) { - ChildCommandAddress address = new ChildCommandAddress(command); - address.addNameAndAliases(name, aliases); - return addSubCommand(address); - } - - /** - * Add a subcommand as an address at the current address - * The result of this call is the same as - * {@code addSubCommand(address.getMainKey(), address.getCommand(), address.getNames().sublist(1).toArray(new String[0]))} - * - * @param address the address - * @return this - * @throws IllegalArgumentException if {@code address.isRoot()} - */ - public CommandBuilder addSubCommand(ICommandAddress address) { - cur.addChild(address); - return this; - } - - /** - * Search the given class for any (static) methods using command annotations - * The class gets a localized parameter type selector if it defines parameter types. - * Any commands found are registered as sub commands to the current address. - * - * @param clazz the clazz - * @return this - * @throws IllegalArgumentException if an exception occurs while parsing the methods of this class - * @see #registerCommands(Class, Object) - */ - public CommandBuilder registerCommands(Class clazz) { - return registerCommands(clazz, null); - } - - /** - * Search the given object's class for methods using command annotations. - * If the object is null, only static methods are checked. Otherwise, instance methods are also checked. - * The class gets a localized parameter type selector if it defines parameter types. - * Any commands found are registered as sub commands to the current address. - * - * @param object the object - * @return this - * @throws IllegalArgumentException if an exception occurs while parsing the methods of this class - * @see #registerCommands(Class, Object) - */ - public CommandBuilder registerCommands(Object object) { - return registerCommands(object.getClass(), object); - } - - /** - * Search the given class for methods using command annotations. - * The class gets a localized parameter type selector if it defines parameter types. - * Any commands found are registered as sub commands to the current address. - * The instance is used to invoke non-static methods. - * - * @param clazz the class - * @param instance the instance, null if only static methods - * @return this - * @throws IllegalArgumentException if instance is not null and it's not an instance of the class - * @throws IllegalArgumentException if another exception occurs while parsing the methods of this class - */ - public CommandBuilder registerCommands(Class clazz, Object instance) { - try { - ReflectiveRegistration.parseCommandGroup(cur, selector, clazz, instance); - return this; - } catch (Exception ex) { - throw new IllegalArgumentException(ex); - } - } - - /** - * register the {@link HelpCommand} as a sub command at the current address - * - * @return this - */ - public CommandBuilder registerHelpCommand() { - HelpCommand.registerAsChild(cur); - return this; - } - - /** - * register the {@link SyntaxCommand} as a sub command a the current address - * - * @return this - */ - public CommandBuilder registerSyntaxCommand() { - SyntaxCommand.registerAsChild(cur); - return this; - } - - /** - * Generate the predefined commands. - * These are presets. - * Examples include {@code help} and {@code syntax}. - *

- * Predefined commands can be registered through {@link PredefinedCommand#registerPredefinedCommandGenerator(String, Consumer)} - * - * @param commands the commands - * @return this - */ - public CommandBuilder generatePredefinedCommands(String... commands) { - ReflectiveRegistration.generateCommands(cur, commands); - return this; - } - - /** - * Unregister any childs present at the given keys. - *

- * This method can be used to remove unwanted keys, that might have been added - * outside of your control. For example, because you didn't want all commands - * registered by {@link #registerCommands(Class, Object)}, or because you didn't - * want the help command registered by {@link #group(String, String...)} - * - * @param removeAliases true if any aliases of the children present at the keys should be removed - * @param keys a varargs array containing the keys - * @return this - * @throws IllegalArgumentException if keys array is empty - */ - public CommandBuilder unregisterCommands(boolean removeAliases, String... keys) { - cur.removeChildren(removeAliases, keys); - return this; - } - - /** - * Jump to the sub-address with the given name as main key. - * If an address with the exact name as main key exists, - * that address becomes the current address. - *

- * Otherwise, a new addresses is registered with the name and aliases. - * New addresses registered by this command have a HelpCommand added by default. - *

- * After this call, any registered commands are registered as a sub command - * to the new address. To restore the previous state, a call to {@link #parent()} - * should be made. - *

- * If the address is the target of a command, it will provide information about its sub commands - * using the HelpCommand. - * - * @param name the main key - * @param aliases the aliases - * @return this - */ - public CommandBuilder group(String name, String... aliases) { - ChildCommandAddress address = cur.getChild(name); - if (address == null || !name.equals(address.getMainKey())) { - address = new ChildCommandAddress(); - address.setupAsPlaceholder(name, aliases); - cur.addChild(address); - } - cur = address; - return this; - } - - /** - * Similar to {@link #group(String, String[])} but this will force overwrite any present group, - * using the address passed. The address MUST be an instance of {@link ChildCommandAddress}. - * - *

The address must not have a parent or any keys

- * - * @param address the address object to use - * @param name the main key - * @param aliases any aliases - * @return this - * @throws IllegalArgumentException if any of the requirements set out above aren't met - */ - public CommandBuilder group(ICommandAddress address, String name, String... aliases) { - if (address.hasParent() || address.getMainKey() != null || !(address instanceof ChildCommandAddress)) { - throw new IllegalArgumentException(); - } - - ChildCommandAddress asChild = (ChildCommandAddress) address; - asChild.setupAsPlaceholder(name, aliases); - cur.addChild(address); - cur = asChild; - return this; - } - - /** - * Sets the description of a group created by {@link #group(String, String...)} - * Can be called subsequently to making a call to {@link #group(String, String...)} - * - * @param shortDescription a short description - * @param description the lines of a full description. - * @return this - * @throws IllegalStateException if the current group has no command - */ - public CommandBuilder setGroupDescription(String shortDescription, String... description) { - Command command = cur.getCommand(); - if (command == null) throw new IllegalStateException(); - cur.setCommand(command - .setShortDescription(shortDescription) - .setDescription(description)); - return this; - } - - /** - * Add a context filter to the command of the current group - * @return this - * @throws IllegalStateException if the current group has no command - */ - public CommandBuilder addContextFilter(IContextFilter contextFilter) { - Command command = cur.getCommand(); - if (command == null) throw new IllegalStateException(); - cur.setCommand(command - .addContextFilter(contextFilter)); - return this; - } - - /** - * Add a required permission to the command of the current group - * @return this - * @throws IllegalStateException if the current group has no command - */ - public CommandBuilder addPermission(String permission) { - return addContextFilter(IContextFilter.permission(permission)); - } - - /** - * Add a required permission to the command of the current group, which can be inherited - * @return this - * @throws IllegalStateException if the current group has no command - */ - public CommandBuilder addInheritablePermission(String permission) { - return addContextFilter(IContextFilter.inheritablePermission(permission)); - } - - /** - * Jump up a level in the address - * - * @return this - * @throws IllegalStateException if the address is empty - * // has a depth of 0 // is at level 0 - */ - public CommandBuilder parent() { - if (cur.hasParent()) { - cur = cur.getParent(); - return this; - } - throw new IllegalStateException("No parent exists at this address"); - } - - /** - * Jump to the root (empty) address, - * such that a subsequent call to {@link #parent()} - * will throw a {@link IllegalStateException} - * - * @return this - */ - public CommandBuilder root() { - cur = root; - return this; - } - - /** - * Get the current address, as a space-separated string - * - * @return the current address - */ - public String getAddress() { - return cur.getAddress(); - } - - /** - * Get the depth of the current address. - * This is equivalent to {@code getAddress().split(" ").length}. - * If the address is empty, the depth is 0. - * - * @return the depth - */ - public int getDepth() { - return cur.getDepth(); - } - - /** - * Set the command at the current group. The command is set - * a level higher than it would be if this were a call to {@link #addSubCommand(String, Command, String...)} - *

- * If a call to {@link #setGroupDescription(String, String...)} was made at the same address before, - * the description is copied to the given executor. - * - * @param command the executor - * @return this - * @throws IllegalArgumentException if the command at the address is present and declared by the user, - * in other words, it's not a {@link PredefinedCommand} - */ - public CommandBuilder setCommand(Command command) { - Command current = cur.getCommand(); - if (current instanceof HelpCommand && current != HelpCommand.INSTANCE) { - command.setShortDescription(current.getShortDescription()); - command.setDescription(current.getDescription()); - } - - cur.setCommand(command); - return this; - } - - /** - * Configure the chat handler at this address. The chat handler - * is used for all children down the tree if they don't explicitly have - * their own chat handler configured. If this isn't configured, - * {@code ChatHandlers.defaultChat()} is used. - * - * @param chatHandler the chat handler - * @return this - */ - public CommandBuilder setChatHandler(IChatHandler chatHandler) { - cur.setChatHandler(chatHandler); - return this; - } - - /** - * Add the parameter type to this builder's selector. - * - * @param type the type - * @param the return type of the parameter type - * @return this - */ - public CommandBuilder addParameterType(ParameterType type) { - selector.addType(false, type); - return this; - } - - /** - * Add the parameter type to this builder's selector. - * - * @param infolessAlias whether to also register the type with an infoless alias. - * this increases the priority assigned to the type if no info object is present. - * @param type the type - * @param the return type of the parameter type - * @param the parameter config type (info object) - * @return this - */ - - public CommandBuilder addParameterType(boolean infolessAlias, ParameterType type) { - selector.addType(infolessAlias, type); - return this; - } - - /** - * Get the dispatcher for the root address. - * The dispatcher should be used to finally register all commands, - * after they are all declared. - * - * @return the dispatcher - */ - public ICommandDispatcher getDispatcher() { - return root; - } - - /** - * Print debugging information about the current addresses and commands in this builder - * A StackTraceElement indicating where this was called from is also included - * - * @return this - */ - public CommandBuilder printDebugInformation() { - String address = cur == root ? "" : cur.getAddress(); - StackTraceElement caller = getCallsite(); - - StringBuilder message = new StringBuilder("### CommandBuilder dump ###"); - message.append("\nCalled from ").append(caller); - message.append("\nPosition: ").append(address); - cur.appendDebugInformation(message, "", new HashSet<>()); - - System.out.println(message); - return this; - } - - private static StackTraceElement getCallsite() { - // [0] Thread.currentThread() - // [1] CommandBuilder.getCallsite() - // [2] Calling method - // [3] Method calling the calling method - StackTraceElement[] trace = Thread.currentThread().getStackTrace(); - return trace.length > 3 ? trace[3] : null; - } - -} +package io.dico.dicore.command; + +import io.dico.dicore.command.chat.IChatHandler; +import io.dico.dicore.command.parameter.type.IParameterTypeSelector; +import io.dico.dicore.command.parameter.type.MapBasedParameterTypeSelector; +import io.dico.dicore.command.parameter.type.ParameterType; +import io.dico.dicore.command.predef.HelpCommand; +import io.dico.dicore.command.predef.PredefinedCommand; +import io.dico.dicore.command.predef.SyntaxCommand; +import io.dico.dicore.command.registration.reflect.ReflectiveRegistration; + +import java.util.HashSet; +import java.util.Objects; +import java.util.function.Consumer; + +/** + * Mimic of WorldEdit's CommandGraph + */ +public final class CommandBuilder { + private final RootCommandAddress root; + private ModifiableCommandAddress cur; + private IParameterTypeSelector selector; + + /** + * Instantiate a new CommandBuilder with a new command root system + * Commands registered to this command builder might interfere with + * commands registered to other commands builders or by other plugins. + */ + public CommandBuilder() { + this(new RootCommandAddress()); + } + + /** + * Instantiate a new CommandBuilder with a specified root address. + * If the root address is identical to that of another command builder, + * they will modify the same tree. + * + * @param root the root address + */ + public CommandBuilder(RootCommandAddress root) { + this.root = Objects.requireNonNull(root); + this.cur = root; + this.selector = new MapBasedParameterTypeSelector(true); + } + + /** + * Add a sub command at the current address + * The current address can be inspected using {@link #getAddress()} + * + * @param name the name of the command + * @param command the command executor + * @param aliases any aliases + * @return this + */ + public CommandBuilder addSubCommand(String name, Command command, String... aliases) { + ChildCommandAddress address = new ChildCommandAddress(command); + address.addNameAndAliases(name, aliases); + return addSubCommand(address); + } + + /** + * Add a subcommand as an address at the current address + * The result of this call is the same as + * {@code addSubCommand(address.getMainKey(), address.getCommand(), address.getNames().sublist(1).toArray(new String[0]))} + * + * @param address the address + * @return this + * @throws IllegalArgumentException if {@code address.isRoot()} + */ + public CommandBuilder addSubCommand(ICommandAddress address) { + cur.addChild(address); + return this; + } + + /** + * Search the given class for any (static) methods using command annotations + * The class gets a localized parameter type selector if it defines parameter types. + * Any commands found are registered as sub commands to the current address. + * + * @param clazz the clazz + * @return this + * @throws IllegalArgumentException if an exception occurs while parsing the methods of this class + * @see #registerCommands(Class, Object) + */ + public CommandBuilder registerCommands(Class clazz) { + return registerCommands(clazz, null); + } + + /** + * Search the given object's class for methods using command annotations. + * If the object is null, only static methods are checked. Otherwise, instance methods are also checked. + * The class gets a localized parameter type selector if it defines parameter types. + * Any commands found are registered as sub commands to the current address. + * + * @param object the object + * @return this + * @throws IllegalArgumentException if an exception occurs while parsing the methods of this class + * @see #registerCommands(Class, Object) + */ + public CommandBuilder registerCommands(Object object) { + return registerCommands(object.getClass(), object); + } + + /** + * Search the given class for methods using command annotations. + * The class gets a localized parameter type selector if it defines parameter types. + * Any commands found are registered as sub commands to the current address. + * The instance is used to invoke non-static methods. + * + * @param clazz the class + * @param instance the instance, null if only static methods + * @return this + * @throws IllegalArgumentException if instance is not null and it's not an instance of the class + * @throws IllegalArgumentException if another exception occurs while parsing the methods of this class + */ + public CommandBuilder registerCommands(Class clazz, Object instance) { + try { + ReflectiveRegistration.parseCommandGroup(cur, selector, clazz, instance); + return this; + } catch (Exception ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * register the {@link HelpCommand} as a sub command at the current address + * + * @return this + */ + public CommandBuilder registerHelpCommand() { + HelpCommand.registerAsChild(cur); + return this; + } + + /** + * register the {@link SyntaxCommand} as a sub command a the current address + * + * @return this + */ + public CommandBuilder registerSyntaxCommand() { + SyntaxCommand.registerAsChild(cur); + return this; + } + + /** + * Generate the predefined commands. + * These are presets. + * Examples include {@code help} and {@code syntax}. + *

+ * Predefined commands can be registered through {@link PredefinedCommand#registerPredefinedCommandGenerator(String, Consumer)} + * + * @param commands the commands + * @return this + */ + public CommandBuilder generatePredefinedCommands(String... commands) { + ReflectiveRegistration.generateCommands(cur, commands); + return this; + } + + /** + * Unregister any childs present at the given keys. + *

+ * This method can be used to remove unwanted keys, that might have been added + * outside of your control. For example, because you didn't want all commands + * registered by {@link #registerCommands(Class, Object)}, or because you didn't + * want the help command registered by {@link #group(String, String...)} + * + * @param removeAliases true if any aliases of the children present at the keys should be removed + * @param keys a varargs array containing the keys + * @return this + * @throws IllegalArgumentException if keys array is empty + */ + public CommandBuilder unregisterCommands(boolean removeAliases, String... keys) { + cur.removeChildren(removeAliases, keys); + return this; + } + + /** + * Jump to the sub-address with the given name as main key. + * If an address with the exact name as main key exists, + * that address becomes the current address. + *

+ * Otherwise, a new addresses is registered with the name and aliases. + * New addresses registered by this command have a HelpCommand added by default. + *

+ * After this call, any registered commands are registered as a sub command + * to the new address. To restore the previous state, a call to {@link #parent()} + * should be made. + *

+ * If the address is the target of a command, it will provide information about its sub commands + * using the HelpCommand. + * + * @param name the main key + * @param aliases the aliases + * @return this + */ + public CommandBuilder group(String name, String... aliases) { + ChildCommandAddress address = cur.getChild(name); + if (address == null || !name.equals(address.getMainKey())) { + address = new ChildCommandAddress(); + address.setupAsPlaceholder(name, aliases); + cur.addChild(address); + } + cur = address; + return this; + } + + /** + * Similar to {@link #group(String, String[])} but this will force overwrite any present group, + * using the address passed. The address MUST be an instance of {@link ChildCommandAddress}. + * + *

The address must not have a parent or any keys

+ * + * @param address the address object to use + * @param name the main key + * @param aliases any aliases + * @return this + * @throws IllegalArgumentException if any of the requirements set out above aren't met + */ + public CommandBuilder group(ICommandAddress address, String name, String... aliases) { + if (address.hasParent() || address.getMainKey() != null || !(address instanceof ChildCommandAddress)) { + throw new IllegalArgumentException(); + } + + ChildCommandAddress asChild = (ChildCommandAddress) address; + asChild.setupAsPlaceholder(name, aliases); + cur.addChild(address); + cur = asChild; + return this; + } + + /** + * Sets the description of a group created by {@link #group(String, String...)} + * Can be called subsequently to making a call to {@link #group(String, String...)} + * + * @param shortDescription a short description + * @param description the lines of a full description. + * @return this + * @throws IllegalStateException if the current group has no command + */ + public CommandBuilder setGroupDescription(String shortDescription, String... description) { + Command command = cur.getCommand(); + if (command == null) throw new IllegalStateException(); + cur.setCommand(command + .setShortDescription(shortDescription) + .setDescription(description)); + return this; + } + + /** + * Add a context filter to the command of the current group + * @return this + * @throws IllegalStateException if the current group has no command + */ + public CommandBuilder addContextFilter(IContextFilter contextFilter) { + Command command = cur.getCommand(); + if (command == null) throw new IllegalStateException(); + cur.setCommand(command + .addContextFilter(contextFilter)); + return this; + } + + /** + * Add a required permission to the command of the current group + * @return this + * @throws IllegalStateException if the current group has no command + */ + public CommandBuilder addPermission(String permission) { + return addContextFilter(IContextFilter.permission(permission)); + } + + /** + * Add a required permission to the command of the current group, which can be inherited + * @return this + * @throws IllegalStateException if the current group has no command + */ + public CommandBuilder addInheritablePermission(String permission) { + return addContextFilter(IContextFilter.inheritablePermission(permission)); + } + + /** + * Jump up a level in the address + * + * @return this + * @throws IllegalStateException if the address is empty + * // has a depth of 0 // is at level 0 + */ + public CommandBuilder parent() { + if (cur.hasParent()) { + cur = cur.getParent(); + return this; + } + throw new IllegalStateException("No parent exists at this address"); + } + + /** + * Jump to the root (empty) address, + * such that a subsequent call to {@link #parent()} + * will throw a {@link IllegalStateException} + * + * @return this + */ + public CommandBuilder root() { + cur = root; + return this; + } + + /** + * Get the current address, as a space-separated string + * + * @return the current address + */ + public String getAddress() { + return cur.getAddress(); + } + + /** + * Get the depth of the current address. + * This is equivalent to {@code getAddress().split(" ").length}. + * If the address is empty, the depth is 0. + * + * @return the depth + */ + public int getDepth() { + return cur.getDepth(); + } + + /** + * Set the command at the current group. The command is set + * a level higher than it would be if this were a call to {@link #addSubCommand(String, Command, String...)} + *

+ * If a call to {@link #setGroupDescription(String, String...)} was made at the same address before, + * the description is copied to the given executor. + * + * @param command the executor + * @return this + * @throws IllegalArgumentException if the command at the address is present and declared by the user, + * in other words, it's not a {@link PredefinedCommand} + */ + public CommandBuilder setCommand(Command command) { + Command current = cur.getCommand(); + if (current instanceof HelpCommand && current != HelpCommand.INSTANCE) { + command.setShortDescription(current.getShortDescription()); + command.setDescription(current.getDescription()); + } + + cur.setCommand(command); + return this; + } + + /** + * Configure the chat handler at this address. The chat handler + * is used for all children down the tree if they don't explicitly have + * their own chat handler configured. If this isn't configured, + * {@code ChatHandlers.defaultChat()} is used. + * + * @param chatHandler the chat handler + * @return this + */ + public CommandBuilder setChatHandler(IChatHandler chatHandler) { + cur.setChatHandler(chatHandler); + return this; + } + + /** + * Add the parameter type to this builder's selector. + * + * @param type the type + * @param the return type of the parameter type + * @return this + */ + public CommandBuilder addParameterType(ParameterType type) { + selector.addType(false, type); + return this; + } + + /** + * Add the parameter type to this builder's selector. + * + * @param infolessAlias whether to also register the type with an infoless alias. + * this increases the priority assigned to the type if no info object is present. + * @param type the type + * @param the return type of the parameter type + * @param the parameter config type (info object) + * @return this + */ + + public CommandBuilder addParameterType(boolean infolessAlias, ParameterType type) { + selector.addType(infolessAlias, type); + return this; + } + + /** + * Get the dispatcher for the root address. + * The dispatcher should be used to finally register all commands, + * after they are all declared. + * + * @return the dispatcher + */ + public ICommandDispatcher getDispatcher() { + return root; + } + + /** + * Print debugging information about the current addresses and commands in this builder + * A StackTraceElement indicating where this was called from is also included + * + * @return this + */ + public CommandBuilder printDebugInformation() { + String address = cur == root ? "" : cur.getAddress(); + StackTraceElement caller = getCallsite(); + + StringBuilder message = new StringBuilder("### CommandBuilder dump ###"); + message.append("\nCalled from ").append(caller); + message.append("\nPosition: ").append(address); + cur.appendDebugInformation(message, "", new HashSet<>()); + + System.out.println(message); + return this; + } + + private static StackTraceElement getCallsite() { + // [0] Thread.currentThread() + // [1] CommandBuilder.getCallsite() + // [2] Calling method + // [3] Method calling the calling method + StackTraceElement[] trace = Thread.currentThread().getStackTrace(); + return trace.length > 3 ? trace[3] : null; + } + +} -- cgit v1.2.3