Don't consume optional arguments

This commit is contained in:
Jesse Boyd 2018-04-29 12:59:08 +10:00
parent 916bca59ba
commit 81a76dfd30
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
6 changed files with 451 additions and 6 deletions

View File

@ -69,9 +69,7 @@ import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.command.SimpleCommandMapping;
import com.sk89q.worldedit.util.command.SimpleDispatcher;
import com.sk89q.worldedit.util.command.fluent.DispatcherNode;
import com.sk89q.worldedit.util.command.parametric.ParameterData;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
import com.sk89q.worldedit.util.command.parametric.ParametricCallable;
import com.sk89q.worldedit.util.command.parametric.*;
import com.sk89q.worldedit.util.formatting.Fragment;
import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.CommandUsageBox;
@ -449,6 +447,9 @@ public class Fawe {
Request.inject(); // Custom pattern extent
// Commands
Commands.load(new File(INSTANCE.IMP.getDirectory(), "commands.yml"));
ArgumentStack.inject0(); // Mark/reset
ContextArgumentStack.inject();
StringArgumentStack.inject();
Commands.inject(); // Translations
BiomeCommands.inject(); // Translations + Optimizations
ChunkCommands.inject(); // Translations + Optimizations

View File

@ -70,9 +70,11 @@ public class FawePrimitiveBinding extends BindingHelper {
}
@BindingMatch(
type = {BufferedImage.class},
behavior = BindingBehavior.CONSUMES
behavior = BindingBehavior.CONSUMES,
consumedCount = 1,
provideModifiers = true
)
public BufferedImage getImage(ArgumentStack context) throws ParameterException {
public BufferedImage getImage(ArgumentStack context, Annotation[] modifiers) throws ParameterException {
return ImageUtil.getImage(context.next());
}

View File

@ -0,0 +1,98 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.command.parametric;
import com.sk89q.minecraft.util.commands.CommandContext;
public interface ArgumentStack {
/**
* Get the next string, which may come from the stack or a value flag.
*
* @return the value
* @throws ParameterException on a parameter error
*/
String next() throws ParameterException;
/**
* Get the next integer, which may come from the stack or a value flag.
*
* @return the value
* @throws ParameterException on a parameter error
*/
Integer nextInt() throws ParameterException;
/**
* Get the next double, which may come from the stack or a value flag.
*
* @return the value
* @throws ParameterException on a parameter error
*/
Double nextDouble() throws ParameterException;
/**
* Get the next boolean, which may come from the stack or a value flag.
*
* @return the value
* @throws ParameterException on a parameter error
*/
Boolean nextBoolean() throws ParameterException;
/**
* Get all remaining string values, which will consume the rest of the stack.
*
* @return the value
* @throws ParameterException on a parameter error
*/
String remaining() throws ParameterException;
/**
* Set as completely consumed.
*/
void markConsumed();
/**
* Get the underlying context.
*
* @return the context
*/
CommandContext getContext();
/**
* Mark the current position of the stack.
*
* <p>The marked position initially starts at 0.</p>
*/
void mark();
/**
* Reset to the previously {@link #mark()}ed position of the stack, and return
* the arguments that were consumed between this point and that previous point.
*
* <p>The marked position initially starts at 0.</p>
*
* @return the consumed arguments
*/
String reset();
static Class<ArgumentStack> inject0() {
return ArgumentStack.class;
}
}

View File

@ -0,0 +1,184 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.command.parametric;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.worldedit.util.command.MissingParameterException;
/**
* Makes an instance of a {@link CommandContext} into a stack of arguments
* that can be consumed.
*
* @see ParametricBuilder a user of this class
*/
public class ContextArgumentStack implements ArgumentStack {
private final CommandContext context;
private int index = 0;
private int markedIndex = 0;
/**
* Create a new instance using the given context.
*
* @param context the context
*/
public ContextArgumentStack(CommandContext context) {
this.context = context;
}
@Override
public String next() throws ParameterException {
try {
return context.getString(index++);
} catch (IndexOutOfBoundsException e) {
throw new MissingParameterException();
}
}
@Override
public Integer nextInt() throws ParameterException {
try {
return Integer.parseInt(next());
} catch (NumberFormatException e) {
throw new ParameterException(
"Expected a number, got '" + context.getString(index - 1) + "'");
}
}
@Override
public Double nextDouble() throws ParameterException {
try {
return Double.parseDouble(next());
} catch (NumberFormatException e) {
throw new ParameterException(
"Expected a number, got '" + context.getString(index - 1) + "'");
}
}
@Override
public Boolean nextBoolean() throws ParameterException {
try {
return next().equalsIgnoreCase("true");
} catch (IndexOutOfBoundsException e) {
throw new MissingParameterException();
}
}
@Override
public String remaining() throws ParameterException {
try {
String value = context.getJoinedStrings(index);
index = context.argsLength();
return value;
} catch (IndexOutOfBoundsException e) {
throw new MissingParameterException();
}
}
/**
* Get the unconsumed arguments left over, without touching the stack.
*
* @return the unconsumed arguments
*/
public String getUnconsumed() {
if (index >= context.argsLength()) {
return null;
}
return context.getJoinedStrings(index);
}
@Override
public void markConsumed() {
index = context.argsLength();
}
/**
* Return the current position.
*
* @return the position
*/
public int position() {
return index;
}
/**
* Mark the current position of the stack.
*
* <p>The marked position initially starts at 0.</p>
*/
@Override
public void mark() {
markedIndex = index;
}
/**
* Reset to the previously {@link #mark()}ed position of the stack, and return
* the arguments that were consumed between this point and that previous point.
*
* <p>The marked position initially starts at 0.</p>
*
* @return the consumed arguments
*/
@Override
public String reset() {
String value = context.getString(markedIndex, index - 1);
index = markedIndex;
return value;
}
/**
* Return whether any arguments were consumed between the marked position
* and the current position.
*
* <p>The marked position initially starts at 0.</p>
*
* @return true if values were consumed.
*/
public boolean wasConsumed() {
return markedIndex != index;
}
/**
* Return the arguments that were consumed between this point and that marked point.
*
* <p>The marked position initially starts at 0.</p>
*
* @return the consumed arguments
*/
public String getConsumed() {
return context.getString(markedIndex, index);
}
/**
* Get the underlying context.
*
* @return the context
*/
@Override
public CommandContext getContext() {
return context;
}
public static Class<?> inject() {
return ContextArgumentStack.class;
}
}

View File

@ -219,13 +219,15 @@ public class ParametricCallable implements CommandCallable {
ArgumentStack usedArguments = getScopedContext(parameter, arguments);
try {
usedArguments.mark();
args[i] = parameter.getBinding().bind(parameter, usedArguments, false);
} catch (MissingParameterException e) {
} catch (ParameterException e) {
// Not optional? Then we can't execute this command
if (!parameter.isOptional()) {
throw e;
}
usedArguments.reset();
args[i] = getDefaultValue(i, arguments);
}
} else {
@ -254,6 +256,7 @@ public class ParametricCallable implements CommandCallable {
} catch (UnconsumedParameterException e) {
throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), this, true);
} catch (ParameterException e) {
e.printStackTrace();
assert parameter != null;
String name = parameter.getName();

View File

@ -0,0 +1,157 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.command.parametric;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.worldedit.util.command.MissingParameterException;
import com.sk89q.util.StringUtil;
/**
* A virtual scope that does not actually read from the underlying
* {@link CommandContext}.
*/
public class StringArgumentStack implements ArgumentStack {
private final boolean nonNullBoolean;
private final CommandContext context;
private final String[] arguments;
private int markedIndex = 0;
private int index = 0;
/**
* Create a new instance using the given context.
*
* @param context the context
* @param arguments a list of arguments
* @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null
*/
public StringArgumentStack(
CommandContext context, String[] arguments, boolean nonNullBoolean) {
this.context = context;
this.arguments = arguments;
this.nonNullBoolean = nonNullBoolean;
}
/**
* Create a new instance using the given context.
*
* @param context the context
* @param arguments an argument string to be parsed
* @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null
*/
public StringArgumentStack(
CommandContext context, String arguments, boolean nonNullBoolean) {
this.context = context;
this.arguments = CommandContext.split(arguments);
this.nonNullBoolean = nonNullBoolean;
}
@Override
public String next() throws ParameterException {
try {
return arguments[index++];
} catch (ArrayIndexOutOfBoundsException e) {
throw new MissingParameterException();
}
}
@Override
public Integer nextInt() throws ParameterException {
try {
return Integer.parseInt(next());
} catch (NumberFormatException e) {
throw new ParameterException(
"Expected a number, got '" + context.getString(index - 1) + "'");
}
}
@Override
public Double nextDouble() throws ParameterException {
try {
return Double.parseDouble(next());
} catch (NumberFormatException e) {
throw new ParameterException(
"Expected a number, got '" + context.getString(index - 1) + "'");
}
}
@Override
public Boolean nextBoolean() throws ParameterException {
try {
return next().equalsIgnoreCase("true");
} catch (IndexOutOfBoundsException e) {
if (nonNullBoolean) { // Special case
return false;
}
throw new MissingParameterException();
}
}
@Override
public String remaining() throws ParameterException {
try {
String value = StringUtil.joinString(arguments, " ", index);
markConsumed();
return value;
} catch (IndexOutOfBoundsException e) {
throw new MissingParameterException();
}
}
@Override
public void markConsumed() {
index = arguments.length;
}
@Override
public CommandContext getContext() {
return context;
}
/**
* Mark the current position of the stack.
*
* <p>The marked position initially starts at 0.</p>
*/
@Override
public void mark() {
markedIndex = index;
}
/**
* Reset to the previously {@link #mark()}ed position of the stack, and return
* the arguments that were consumed between this point and that previous point.
*
* <p>The marked position initially starts at 0.</p>
*
* @return the consumed arguments
*/
@Override
public String reset() {
String value = context.getString(markedIndex, index - 1);
index = markedIndex;
return value;
}
public static Class<?> inject() {
return StringArgumentStack.class;
}
}