Added new StringArgumentType
This commit is contained in:
parent
60c5770f5e
commit
4337a9645e
3 changed files with 405 additions and 0 deletions
|
@ -25,6 +25,7 @@ public class CommandDispatcher<S> {
|
||||||
public static final ParameterizedCommandExceptionType ERROR_UNKNOWN_ARGUMENT = new ParameterizedCommandExceptionType("command.unknown.argument", "Incorrect argument for command, couldn't parse: ${argument}", "argument");
|
public static final ParameterizedCommandExceptionType ERROR_UNKNOWN_ARGUMENT = new ParameterizedCommandExceptionType("command.unknown.argument", "Incorrect argument for command, couldn't parse: ${argument}", "argument");
|
||||||
|
|
||||||
public static final String ARGUMENT_SEPARATOR = " ";
|
public static final String ARGUMENT_SEPARATOR = " ";
|
||||||
|
public static final char ARGUMENT_SEPARATOR_CHAR = ' ';
|
||||||
private static final String USAGE_OPTIONAL_OPEN = "[";
|
private static final String USAGE_OPTIONAL_OPEN = "[";
|
||||||
private static final String USAGE_OPTIONAL_CLOSE = "]";
|
private static final String USAGE_OPTIONAL_CLOSE = "]";
|
||||||
private static final String USAGE_REQUIRED_OPEN = "(";
|
private static final String USAGE_REQUIRED_OPEN = "(";
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
package com.mojang.brigadier.arguments;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.context.FixedParsedArgument;
|
||||||
|
import com.mojang.brigadier.context.ParsedArgument;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandException;
|
||||||
|
import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType;
|
||||||
|
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class StringArgumentType implements CommandArgumentType<String> {
|
||||||
|
public static final ParameterizedCommandExceptionType ERROR_INVALID_ESCAPE = new ParameterizedCommandExceptionType("argument.string.escape.invalid", "Unknown or invalid escape sequence: ${input}", "input");
|
||||||
|
public static final SimpleCommandExceptionType ERROR_UNEXPECTED_ESCAPE = new SimpleCommandExceptionType("argument.string.escape.unexpected", "Unexpected escape sequence, please quote the whole argument");
|
||||||
|
public static final SimpleCommandExceptionType ERROR_UNEXPECTED_START_OF_QUOTE = new SimpleCommandExceptionType("argument.string.quote.unexpected_start", "Unexpected start-of-quote character (\"), please quote the whole argument");
|
||||||
|
public static final SimpleCommandExceptionType ERROR_UNEXPECTED_END_OF_QUOTE = new SimpleCommandExceptionType("argument.string.quote.unexpected_end", "Unexpected end-of-quote character (\"), it must be at the end or followed by a space (' ') for the next argument");
|
||||||
|
public static final SimpleCommandExceptionType ERROR_EXPECTED_END_OF_QUOTE = new SimpleCommandExceptionType("argument.string.quote.expected_end", "Expected end-of-quote character (\") but found no more input");
|
||||||
|
private final StringType type;
|
||||||
|
|
||||||
|
private StringArgumentType(StringType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringArgumentType word() {
|
||||||
|
return new StringArgumentType(StringType.SINGLE_WORLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringArgumentType string() {
|
||||||
|
return new StringArgumentType(StringType.QUOTABLE_PHRASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringArgumentType greedyString() {
|
||||||
|
return new StringArgumentType(StringType.GREEDY_PHRASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getString(CommandContext<?> context, String name) {
|
||||||
|
return context.getArgument(name, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParsedArgument<String> parse(String command) throws CommandException {
|
||||||
|
if (type == StringType.GREEDY_PHRASE) {
|
||||||
|
return new FixedParsedArgument<>(command, command);
|
||||||
|
} else if (type == StringType.SINGLE_WORLD) {
|
||||||
|
int index = command.indexOf(CommandDispatcher.ARGUMENT_SEPARATOR);
|
||||||
|
if (index > 0) {
|
||||||
|
final String word = command.substring(0, index);
|
||||||
|
return new FixedParsedArgument<>(word, word);
|
||||||
|
} else {
|
||||||
|
return new FixedParsedArgument<>(command, command);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
int i = 0;
|
||||||
|
boolean escaped = false;
|
||||||
|
boolean quoted = false;
|
||||||
|
while (i < command.length()) {
|
||||||
|
char c = command.charAt(i);
|
||||||
|
if (escaped) {
|
||||||
|
if (c == '"' || c == '\\') {
|
||||||
|
result.append(c);
|
||||||
|
} else {
|
||||||
|
throw ERROR_INVALID_ESCAPE.create("\\" + c);
|
||||||
|
}
|
||||||
|
escaped = false;
|
||||||
|
} else if (c == '\\') {
|
||||||
|
if (quoted) {
|
||||||
|
escaped = true;
|
||||||
|
} else {
|
||||||
|
throw ERROR_UNEXPECTED_ESCAPE.create();
|
||||||
|
}
|
||||||
|
} else if (c == '"') {
|
||||||
|
if (i == 0) {
|
||||||
|
quoted = true;
|
||||||
|
} else if (!quoted) {
|
||||||
|
throw ERROR_UNEXPECTED_START_OF_QUOTE.create();
|
||||||
|
} else if (i == command.length() - 1 || command.charAt(i + 1) == CommandDispatcher.ARGUMENT_SEPARATOR_CHAR) {
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw ERROR_UNEXPECTED_END_OF_QUOTE.create();
|
||||||
|
}
|
||||||
|
} else if (!quoted && c == CommandDispatcher.ARGUMENT_SEPARATOR_CHAR) {
|
||||||
|
break;
|
||||||
|
} else if (quoted && i == command.length() - 1) {
|
||||||
|
throw ERROR_EXPECTED_END_OF_QUOTE.create();
|
||||||
|
} else {
|
||||||
|
result.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return new FixedParsedArgument<>(command.substring(0, i), result.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void listSuggestions(String command, Set<String> output) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "string()";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String escapeIfRequired(String input) {
|
||||||
|
if (input.contains("\\") || input.contains("\"") || input.contains(CommandDispatcher.ARGUMENT_SEPARATOR)) {
|
||||||
|
return escape(input);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String escape(String input) {
|
||||||
|
StringBuilder result = new StringBuilder("\"");
|
||||||
|
|
||||||
|
for (int i = 0; i < input.length(); i++) {
|
||||||
|
final char c = input.charAt(i);
|
||||||
|
if (c == '\\' || c == '"') {
|
||||||
|
result.append('\\');
|
||||||
|
}
|
||||||
|
result.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append("\"");
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StringType {
|
||||||
|
SINGLE_WORLD,
|
||||||
|
QUOTABLE_PHRASE,
|
||||||
|
GREEDY_PHRASE,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,270 @@
|
||||||
|
package com.mojang.brigadier.arguments;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.mojang.brigadier.context.ParsedArgument;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandException;
|
||||||
|
import com.sun.xml.internal.ws.api.ComponentEx;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_EXPECTED_END_OF_QUOTE;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_INVALID_ESCAPE;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_UNEXPECTED_END_OF_QUOTE;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_UNEXPECTED_ESCAPE;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_UNEXPECTED_START_OF_QUOTE;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.escapeIfRequired;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.string;
|
||||||
|
import static com.mojang.brigadier.arguments.StringArgumentType.word;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.hasToString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class StringArgumentTypeTest {
|
||||||
|
private StringArgumentType type;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseWord() throws Exception {
|
||||||
|
type = word();
|
||||||
|
ParsedArgument<String> result = type.parse("hello world");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("hello"));
|
||||||
|
assertThat(result.getResult(), is("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseWord_empty() throws Exception {
|
||||||
|
type = word();
|
||||||
|
ParsedArgument<String> result = type.parse("");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is(""));
|
||||||
|
assertThat(result.getResult(), is(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseWord_simple() throws Exception {
|
||||||
|
type = word();
|
||||||
|
ParsedArgument<String> result = type.parse("hello");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("hello"));
|
||||||
|
assertThat(result.getResult(), is("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseString() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("hello world");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("hello"));
|
||||||
|
assertThat(result.getResult(), is("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseGreedyString() throws Exception {
|
||||||
|
type = greedyString();
|
||||||
|
ParsedArgument<String> result = type.parse("hello world");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("hello world"));
|
||||||
|
assertThat(result.getResult(), is("hello world"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParse() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("hello");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("hello"));
|
||||||
|
assertThat(result.getResult(), is("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseWordQuoted() throws Exception {
|
||||||
|
type = word();
|
||||||
|
ParsedArgument<String> result = type.parse("\"hello \\\" world\"");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("\"hello"));
|
||||||
|
assertThat(result.getResult(), is("\"hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseQuoted() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("\"hello \\\" world\"");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("\"hello \\\" world\""));
|
||||||
|
assertThat(result.getResult(), is("hello \" world"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseQuotedWithRemaining() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("\"hello \\\" world\" with remaining");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("\"hello \\\" world\""));
|
||||||
|
assertThat(result.getResult(), is("hello \" world"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNotQuoted() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("hello world");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("hello"));
|
||||||
|
assertThat(result.getResult(), is("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseInvalidQuote_earlyUnquote() throws Exception {
|
||||||
|
try {
|
||||||
|
type = string();
|
||||||
|
type.parse("\"hello \"world");
|
||||||
|
fail();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
assertThat(e.getType(), is(ERROR_UNEXPECTED_END_OF_QUOTE));
|
||||||
|
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseQuote_earlyUnquoteWithRemaining() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("\"hello\" world");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("\"hello\""));
|
||||||
|
assertThat(result.getResult(), is("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseInvalidQuote_lateQuote() throws Exception {
|
||||||
|
try {
|
||||||
|
type = string();
|
||||||
|
type.parse("hello\" world\"");
|
||||||
|
fail();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
assertThat(e.getType(), is(ERROR_UNEXPECTED_START_OF_QUOTE));
|
||||||
|
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseQuote_lateQuoteWithRemaining() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("hello \"world\"");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is("hello"));
|
||||||
|
assertThat(result.getResult(), is("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseInvalidQuote_middleQuote() throws Exception {
|
||||||
|
try {
|
||||||
|
type = string();
|
||||||
|
type.parse("hel\"lo");
|
||||||
|
fail();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
assertThat(e.getType(), is(ERROR_UNEXPECTED_START_OF_QUOTE));
|
||||||
|
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseInvalidQuote_noUnquote() throws Exception {
|
||||||
|
try {
|
||||||
|
type = string();
|
||||||
|
type.parse("\"hello world");
|
||||||
|
fail();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
assertThat(e.getType(), is(ERROR_EXPECTED_END_OF_QUOTE));
|
||||||
|
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseEmpty() throws Exception {
|
||||||
|
type = string();
|
||||||
|
ParsedArgument<String> result = type.parse("");
|
||||||
|
|
||||||
|
assertThat(result.getRaw(), is(""));
|
||||||
|
assertThat(result.getResult(), is(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseInvalidEscape_onlyEscape() throws Exception {
|
||||||
|
try {
|
||||||
|
type = string();
|
||||||
|
type.parse("\\");
|
||||||
|
fail();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
assertThat(e.getType(), is(ERROR_UNEXPECTED_ESCAPE));
|
||||||
|
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseInvalidEscape_unknownSequence() throws Exception {
|
||||||
|
try {
|
||||||
|
type = string();
|
||||||
|
type.parse("\"\\n\"");
|
||||||
|
fail();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
assertThat(e.getType(), is(ERROR_INVALID_ESCAPE));
|
||||||
|
assertThat(e.getData(), is(equalTo(Collections.singletonMap("input", "\\n"))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseInvalidEscape_notQuoted() throws Exception {
|
||||||
|
try {
|
||||||
|
type = string();
|
||||||
|
type.parse("hel\\\\o");
|
||||||
|
fail();
|
||||||
|
} catch (CommandException e) {
|
||||||
|
assertThat(e.getType(), is(ERROR_UNEXPECTED_ESCAPE));
|
||||||
|
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuggestions() throws Exception {
|
||||||
|
type = string();
|
||||||
|
Set<String> set = Sets.newHashSet();
|
||||||
|
type.listSuggestions("", set);
|
||||||
|
assertThat(set, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToString() throws Exception {
|
||||||
|
assertThat(string(), hasToString("string()"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeIfRequired_notRequired() throws Exception {
|
||||||
|
assertThat(escapeIfRequired("hello!"), is(equalTo("hello!")));
|
||||||
|
assertThat(escapeIfRequired(""), is(equalTo("")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeIfRequired_multipleWords() throws Exception {
|
||||||
|
assertThat(escapeIfRequired("hello world"), is(equalTo("\"hello world\"")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeIfRequired_quote() throws Exception {
|
||||||
|
assertThat(escapeIfRequired("hello \"world\"!"), is(equalTo("\"hello \\\"world\\\"!\"")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeIfRequired_escapes() throws Exception {
|
||||||
|
assertThat(escapeIfRequired("\\"), is(equalTo("\"\\\\\"")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEscapeIfRequired_singleQuote() throws Exception {
|
||||||
|
assertThat(escapeIfRequired("\""), is(equalTo("\"\\\"\"")));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue