Make progress
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
for (n = contextFilters.size(); i < n; i++) {
|
||||
contextFilters.get(i).filterContext(executionContext);
|
||||
}
|
||||
|
||||
//System.out.println("Post-contextfilters");
|
||||
|
||||
String message = execute(sender, executionContext);
|
||||
caller.getChatController().sendMessage(sender, EMessageType.RESULT, message);
|
||||
executeWithContext(executionContext);
|
||||
} catch (Throwable t) {
|
||||
caller.getChatController().handleException(sender, executionContext, t);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
context.parseParameters();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
executionContext.parseParametersQuietly();
|
||||
return tabComplete(sender, executionContext, location);
|
||||
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);
|
||||
}
|
||||
|
||||
context.parseParametersQuietly();
|
||||
return tabComplete(context.getSender(), context, location);
|
||||
}
|
||||
|
||||
public List<String> tabComplete(CommandSender sender, ExecutionContext context, Location location) {
|
||||
|
||||
@@ -197,12 +197,38 @@ 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...)}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -125,6 +125,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
|
||||
*
|
||||
|
||||
@@ -30,8 +30,23 @@ 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
|
||||
*
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
ExecutionContext context = new ExecutionContext(sender, false);
|
||||
|
||||
if (target == null || target instanceof DefaultGroupCommand) {
|
||||
if (targetAddress.hasHelpCommand()) {
|
||||
target = targetAddress.getHelpCommand().getCommand();
|
||||
} else if (target == null){
|
||||
return 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();
|
||||
ExecutionContext context = new ExecutionContext(sender, true);
|
||||
|
||||
int cursor = buffer.getCursor();
|
||||
String input;
|
||||
if (cursor >= buffer.size()) {
|
||||
input = "";
|
||||
} else {
|
||||
input = buffer.get(cursor).toLowerCase();
|
||||
}
|
||||
try {
|
||||
ICommandAddress target = getCommandTarget(context, buffer);
|
||||
List<String> out = target.hasCommand()
|
||||
? target.getCommand().tabComplete(sender, target, location, buffer.getUnaffectingCopy())
|
||||
: Collections.emptyList();
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
out.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
} catch (CommandException ex) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user