summaryrefslogtreecommitdiff
path: root/dicore3/command
diff options
context:
space:
mode:
Diffstat (limited to 'dicore3/command')
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/ChildCommandAddress.java13
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/Command.java51
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/CommandBuilder.java28
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java43
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/ICommandAddress.java10
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/ICommandDispatcher.java15
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/ModifiableCommandAddress.java5
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/RootCommandAddress.java103
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/registration/reflect/ReflectiveRegistration.java10
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];
}