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 String ARGUMENT_SEPARATOR = " ";
|
||||
public static final char ARGUMENT_SEPARATOR_CHAR = ' ';
|
||||
private static final String USAGE_OPTIONAL_OPEN = "[";
|
||||
private static final String USAGE_OPTIONAL_CLOSE = "]";
|
||||
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