diff options
Diffstat (limited to 'dicore3/command')
9 files changed, 201 insertions, 77 deletions
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java index 73d82ca..022904e 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java @@ -24,11 +24,20 @@ public class ChildCommandAddress extends ModifiableCommandAddress { } public static ChildCommandAddress newPlaceHolderCommand(String name, String... aliases) { - ChildCommandAddress rv = new ChildCommandAddress(DefaultGroupCommand.getInstance(), name, aliases); - HelpCommand.registerAsChild(rv); + ChildCommandAddress rv = new ChildCommandAddress(); + rv.setupAsPlaceholder(name, aliases); return rv; } + public void setupAsPlaceholder(String name, String... aliases) { + if (!hasCommand()) { + setCommand(DefaultGroupCommand.getInstance()); + } + + addNameAndAliases(name, aliases); + HelpCommand.registerAsChild(this); + } + @Override public boolean isRoot() { return false; diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/Command.java b/dicore3/command/src/main/java/io/dico/dicore/command/Command.java index b66b5f5..868aa95 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/Command.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/Command.java @@ -145,43 +145,50 @@ public abstract class Command { ExecutionContext executionContext = new ExecutionContext(sender, caller, this, buffer, false); try { - //System.out.println("In Command.execute(sender, caller, buffer)#try{"); - int i, n; - for (i = 0, n = contextFilterPostParameterIndex; i < n; i++) { - contextFilters.get(i).filterContext(executionContext); - } - - executionContext.parseParameters(); + executeWithContext(executionContext); + } catch (Throwable t) { + caller.getChatController().handleException(sender, executionContext, t); + } + } - for (n = contextFilters.size(); i < n; i++) { - contextFilters.get(i).filterContext(executionContext); - } + public void executeWithContext(ExecutionContext context) throws CommandException { + //System.out.println("In Command.execute(sender, caller, buffer)#try{"); + int i, n; + for (i = 0, n = contextFilterPostParameterIndex; i < n; i++) { + contextFilters.get(i).filterContext(context); + } - //System.out.println("Post-contextfilters"); + context.parseParameters(); - String message = execute(sender, executionContext); - caller.getChatController().sendMessage(sender, EMessageType.RESULT, message); - } catch (Throwable t) { - caller.getChatController().handleException(sender, executionContext, t); + for (n = contextFilters.size(); i < n; i++) { + contextFilters.get(i).filterContext(context); } + + //System.out.println("Post-contextfilters"); + + String message = execute(context.getSender(), context); + context.getAddress().getChatController().sendMessage(context.getSender(), EMessageType.RESULT, message); } public abstract String execute(CommandSender sender, ExecutionContext context) throws CommandException; public List<String> tabComplete(CommandSender sender, ICommandAddress caller, Location location, ArgumentBuffer buffer) { ExecutionContext executionContext = new ExecutionContext(sender, caller, this, buffer, true); - try { - int i, n; - for (i = 0, n = contextFilterPostParameterIndex; i < n; i++) { - contextFilters.get(i).filterContext(executionContext); - } + return tabCompleteWithContext(executionContext, location); } catch (CommandException ex) { return Collections.emptyList(); } + } + + public List<String> tabCompleteWithContext(ExecutionContext context, Location location) throws CommandException { + int i, n; + for (i = 0, n = contextFilterPostParameterIndex; i < n; i++) { + contextFilters.get(i).filterContext(context); + } - executionContext.parseParametersQuietly(); - return tabComplete(sender, executionContext, location); + context.parseParametersQuietly(); + return tabComplete(context.getSender(), context, location); } public List<String> tabComplete(CommandSender sender, ExecutionContext context, Location location) { 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 e72d478..76211c2 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 @@ -197,13 +197,39 @@ public final class CommandBuilder { public CommandBuilder group(String name, String... aliases) { ChildCommandAddress address = cur.getChild(name); if (address == null || !name.equals(address.getMainKey())) { - cur.addChild(address = ChildCommandAddress.newPlaceHolderCommand(name, aliases)); + 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}. + * + * <p>The address must not have a parent or any keys</p> + * + * @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...)} * diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java b/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java index 4450a92..0608b80 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java @@ -17,14 +17,14 @@ import java.util.*; * It is also responsible for keeping track of the parameter to complete in the case of a tab completion. */ public class ExecutionContext { - private final CommandSender sender; - private final ICommandAddress address; - private final Command command; - private final ArgumentBuffer originalBuffer; - private final ArgumentBuffer processedBuffer; + private CommandSender sender; + private ICommandAddress address; + private Command command; + private ArgumentBuffer originalBuffer; + private ArgumentBuffer processedBuffer; // caches the buffer's cursor before parsing. This is needed to provide the original input of the player. - private final int cursorStart; + private int cursorStart; // when the context starts parsing parameters, this flag is set, and any subsequent calls to #parseParameters() throw an IllegalStateException. private boolean attemptedToParse; @@ -48,8 +48,14 @@ public class ExecutionContext { // if this flag is set, any messages sent through the sendMessage methods are discarded. private boolean muted; + public ExecutionContext(CommandSender sender, boolean tabComplete) { + this.sender = Objects.requireNonNull(sender); + this.muted = tabComplete; + this.tabComplete = tabComplete; + } + /** - * Construct an execution context, making it ready to parse the parameter values. + * Construct an execution context that is ready to parse the parameter values. * * @param sender the sender * @param address the address @@ -57,11 +63,22 @@ public class ExecutionContext { * @param tabComplete true if this execution is a tab-completion */ public ExecutionContext(CommandSender sender, ICommandAddress address, Command command, ArgumentBuffer buffer, boolean tabComplete) { - this.sender = Objects.requireNonNull(sender); + this(sender, tabComplete); + targetAcquired(address, command, buffer); + } + + void requireAddressPresent(boolean present) { + //noinspection DoubleNegation + if ((address != null) != present) { + throw new IllegalStateException(); + } + } + + void targetAcquired(ICommandAddress address, Command command, ArgumentBuffer buffer) { + requireAddressPresent(false); + this.address = Objects.requireNonNull(address); this.command = Objects.requireNonNull(command); - this.muted = tabComplete; - this.tabComplete = tabComplete; // If its tab completing, keep the empty element that might be at the end of the buffer // due to a space at the end of the command. @@ -80,7 +97,8 @@ public class ExecutionContext { * * @throws CommandException if an error occurs while parsing the parameters. */ - public synchronized void parseParameters() throws CommandException { + synchronized void parseParameters() throws CommandException { + requireAddressPresent(true); if (attemptedToParse) { throw new IllegalStateException(); } @@ -101,7 +119,8 @@ public class ExecutionContext { * This method is typically used by tab completions. * After calling this method, the context is ready to provide completions. */ - public synchronized void parseParametersQuietly() { + synchronized void parseParametersQuietly() { + requireAddressPresent(true); if (attemptedToParse) { throw new IllegalStateException(); } diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java index d6cd350..befdefa 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java @@ -126,6 +126,16 @@ public interface ICommandAddress { ICommandAddress getChild(String key); /** + * Query for a child at the given key, with the given context for reference. + * Can be used to override behaviour of the tree. + * + * @param key the key. The name or alias of a command. + * @param context context of a command being executed + * @return the child, or null if it's not found, altered freely by the implementation + */ + ICommandAddress getChild(String key, ExecutionContext context) throws CommandException; + + /** * Get the command dispatcher for this tree * * @return the command dispatcher diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandDispatcher.java b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandDispatcher.java index b18694e..055171d 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandDispatcher.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandDispatcher.java @@ -30,9 +30,24 @@ public interface ICommandDispatcher { * @param buffer the command itself as a buffer. * @return the address that is the target of the command. */ + @Deprecated ICommandAddress getCommandTarget(CommandSender sender, ArgumentBuffer buffer); /** + * Similar to {@link #getDeepChild(ArgumentBuffer)}, + * but this method incorporates checks on the command of traversed children: + * {@link Command#isVisibleTo(CommandSender)} + * and {@link Command#takePrecedenceOverSubcommand(String, ArgumentBuffer)} + * <p> + * The target of a command is never null, however, the same instance might be returned, and the returned address might not hold a command. + * + * @param context the context of the command. The context must not have its address set. + * @param buffer the command itself as a buffer. + * @return the address that is the target of the command. + */ + ICommandAddress getCommandTarget(ExecutionContext context, ArgumentBuffer buffer) throws CommandException; + + /** * dispatch the command * * @param sender the sender diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java index 8c2ab67..484eb5e 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java @@ -120,6 +120,11 @@ public abstract class ModifiableCommandAddress implements ICommandAddress { return children.get(key); } + @Override + public ChildCommandAddress getChild(String key, ExecutionContext context) throws CommandException { + return getChild(key); + } + public void addChild(ICommandAddress child) { if (!(child instanceof ChildCommandAddress)) { throw new IllegalArgumentException("Argument must be a ChildCommandAddress"); diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java b/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java index 6d38174..7577808 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java @@ -123,8 +123,6 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom @Override public ModifiableCommandAddress getCommandTarget(CommandSender sender, ArgumentBuffer buffer) { - //System.out.println("Buffer cursor upon getCommandTarget: " + buffer.getCursor()); - ModifiableCommandAddress cur = this; ChildCommandAddress child; while (buffer.hasNext()) { @@ -139,16 +137,25 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom cur = child; } - /* - if (!cur.hasCommand() && cur.hasHelpCommand()) { - cur = cur.getHelpCommand(); - } else { - while (!cur.hasCommand() && cur.hasParent()) { - cur = cur.getParent(); + return cur; + } + + @Override + public ModifiableCommandAddress getCommandTarget(ExecutionContext context, ArgumentBuffer buffer) throws CommandException { + CommandSender sender = context.getSender(); + ModifiableCommandAddress cur = this; + ChildCommandAddress child; + while (buffer.hasNext()) { + child = cur.getChild(buffer.next(), context); + if (child == null + || (child.hasCommand() && !child.getCommand().isVisibleTo(sender)) + || (cur.hasCommand() && cur.getCommand().takePrecedenceOverSubcommand(buffer.peekPrevious(), buffer.getUnaffectingCopy()))) { buffer.rewind(); + break; } + + cur = child; } - */ return cur; } @@ -165,18 +172,32 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom @Override public boolean dispatchCommand(CommandSender sender, ArgumentBuffer buffer) { - ModifiableCommandAddress targetAddress = getCommandTarget(sender, buffer); - Command target = targetAddress.getCommand(); - - if (target == null || target instanceof DefaultGroupCommand) { - if (targetAddress.hasHelpCommand()) { - target = targetAddress.getHelpCommand().getCommand(); - } else if (target == null){ - return false; + ExecutionContext context = new ExecutionContext(sender, false); + + ModifiableCommandAddress targetAddress = null; + + try { + targetAddress = getCommandTarget(context, buffer); + Command target = targetAddress.getCommand(); + + if (target == null || target instanceof DefaultGroupCommand) { + if (targetAddress.hasHelpCommand()) { + target = targetAddress.getHelpCommand().getCommand(); + } else if (target == null){ + return false; + } + } + + context.targetAcquired(targetAddress, target, buffer); + target.executeWithContext(context); + + } catch (Throwable t) { + if (targetAddress == null) { + targetAddress = this; } + targetAddress.getChatController().handleException(sender, context, t); } - target.execute(sender, targetAddress, buffer); return true; } @@ -192,28 +213,38 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom @Override public List<String> getTabCompletions(CommandSender sender, Location location, ArgumentBuffer buffer) { - ICommandAddress target = getCommandTarget(sender, buffer); - List<String> out = target.hasCommand() ? target.getCommand().tabComplete(sender, target, location, buffer.getUnaffectingCopy()) : Collections.emptyList(); - - int cursor = buffer.getCursor(); - String input; - if (cursor >= buffer.size()) { - input = ""; - } else { - input = buffer.get(cursor).toLowerCase(); - } + ExecutionContext context = new ExecutionContext(sender, true); + + try { + ICommandAddress target = getCommandTarget(context, buffer); + List<String> out = target.hasCommand() + ? target.getCommand().tabComplete(sender, target, location, buffer.getUnaffectingCopy()) + : Collections.emptyList(); + + int cursor = buffer.getCursor(); + String input; + if (cursor >= buffer.size()) { + input = ""; + } else { + input = buffer.get(cursor).toLowerCase(); + } - boolean wrapped = false; - for (String child : target.getChildren().keySet()) { - if (child.toLowerCase().startsWith(input)) { - if (!wrapped) { - out = new ArrayList<>(out); - wrapped = true; + boolean wrapped = false; + for (String child : target.getChildren().keySet()) { + if (child.toLowerCase().startsWith(input)) { + if (!wrapped) { + out = new ArrayList<>(out); + wrapped = true; + } + out.add(child); } - out.add(child); } + + return out; + + } catch (CommandException ex) { + return Collections.emptyList(); } - return out; } } diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java index 0495ba9..0c64533 100644 --- a/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java +++ b/dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java @@ -177,10 +177,12 @@ public class ReflectiveRegistration { GroupEntry matchEntry = matchEntries[i]; if (patterns[i].matcher(name).matches()) { if (addresses[i] == null) { - addresses[i] = ChildCommandAddress.newPlaceHolderCommand(matchEntry.group(), matchEntry.groupAliases()); - groupRootAddress.addChild(addresses[i]); - generateCommands(addresses[i], matchEntry.generatedCommands()); - setDescription(addresses[i], matchEntry.description(), matchEntry.shortDescription()); + ChildCommandAddress placeholder = new ChildCommandAddress(); + placeholder.setupAsPlaceholder(matchEntry.group(), matchEntry.groupAliases()); + addresses[i] = placeholder; + groupRootAddress.addChild(placeholder); + generateCommands(placeholder, matchEntry.generatedCommands()); + setDescription(placeholder, matchEntry.description(), matchEntry.shortDescription()); } return addresses[i]; } |