diff --git a/src/main/java/com/mojang/brigadier/StringReader.java b/src/main/java/com/mojang/brigadier/StringReader.java index c1465df6..9d4a2089 100644 --- a/src/main/java/com/mojang/brigadier/StringReader.java +++ b/src/main/java/com/mojang/brigadier/StringReader.java @@ -174,6 +174,10 @@ public static boolean isAllowedInUnquotedString(final char c) { || c == '.' || c == '+'; } + public static boolean isAllowedInUnquotedStringRelaxed(final char c) { + return c != ' ' && c != '\\' && !isQuotedStringStart(c); + } + public String readUnquotedString() { final int start = cursor; while (canRead() && isAllowedInUnquotedString(peek())) { @@ -182,6 +186,14 @@ public String readUnquotedString() { return string.substring(start, cursor); } + public String readUnquotedStringRelaxed() { + final int start = cursor; + while (canRead() && isAllowedInUnquotedStringRelaxed(peek())) { + skip(); + } + return string.substring(start, cursor); + } + public String readQuotedString() throws CommandSyntaxException { if (!canRead()) { return ""; @@ -228,7 +240,7 @@ public String readString() throws CommandSyntaxException { skip(); return readStringUntil(next); } - return readUnquotedString(); + return readUnquotedStringRelaxed(); } public boolean readBoolean() throws CommandSyntaxException { diff --git a/src/main/java/com/mojang/brigadier/arguments/StringArgumentType.java b/src/main/java/com/mojang/brigadier/arguments/StringArgumentType.java index 0e36f340..0d728722 100644 --- a/src/main/java/com/mojang/brigadier/arguments/StringArgumentType.java +++ b/src/main/java/com/mojang/brigadier/arguments/StringArgumentType.java @@ -21,6 +21,10 @@ public static StringArgumentType word() { return new StringArgumentType(StringType.SINGLE_WORD); } + public static StringArgumentType relaxedWord() { + return new StringArgumentType(StringType.SINGLE_WORD_RELAXED); + } + public static StringArgumentType string() { return new StringArgumentType(StringType.QUOTABLE_PHRASE); } @@ -39,20 +43,23 @@ public StringType getType() { @Override public String parse(final StringReader reader) throws CommandSyntaxException { - if (type == StringType.GREEDY_PHRASE) { - final String text = reader.getRemaining(); - reader.setCursor(reader.getTotalLength()); - return text; - } else if (type == StringType.SINGLE_WORD) { - return reader.readUnquotedString(); - } else { - return reader.readString(); + switch (type) { + case SINGLE_WORD: + return reader.readUnquotedString(); + case QUOTABLE_PHRASE: + return reader.readString(); + case GREEDY_PHRASE: + final String text = reader.getRemaining(); + reader.setCursor(reader.getTotalLength()); + return text; + default: + return reader.readUnquotedStringRelaxed(); } } @Override public String toString() { - return "string()"; + return type.name; } @Override @@ -62,7 +69,7 @@ public Collection getExamples() { public static String escapeIfRequired(final String input) { for (final char c : input.toCharArray()) { - if (!StringReader.isAllowedInUnquotedString(c)) { + if (!StringReader.isAllowedInUnquotedStringRelaxed(c)) { return escape(input); } } @@ -85,16 +92,23 @@ private static String escape(final String input) { } public enum StringType { - SINGLE_WORD("word", "words_with_underscores"), - QUOTABLE_PHRASE("\"quoted phrase\"", "word", "\"\""), - GREEDY_PHRASE("word", "words with spaces", "\"and symbols\""),; + SINGLE_WORD("word()", "word", "words_with_underscores"), + QUOTABLE_PHRASE("string()", "\"quoted phrase\"", "word", "wörd!", "\"\""), + GREEDY_PHRASE("greedyString()", "word", "words with spaces", "\"and symbols\""), + SINGLE_WORD_RELAXED("wordRelaxed()", "word", "wörd!"); + private final String name; private final Collection examples; - StringType(final String... examples) { + StringType(final String name, final String... examples) { + this.name = name; this.examples = Arrays.asList(examples); } + public String getName() { + return name; + } + public Collection getExamples() { return examples; } diff --git a/src/test/java/com/mojang/brigadier/StringReaderTest.java b/src/test/java/com/mojang/brigadier/StringReaderTest.java index 23e2c14d..6f46300e 100644 --- a/src/test/java/com/mojang/brigadier/StringReaderTest.java +++ b/src/test/java/com/mojang/brigadier/StringReaderTest.java @@ -148,6 +148,14 @@ public void readUnquotedString_empty_withRemaining() throws Exception { assertThat(reader.getRemaining(), equalTo(" hello world")); } + @Test + public void readUnquotedStringRelaxed() throws Exception { + final StringReader reader = new StringReader("héllö world"); + assertThat(reader.readUnquotedStringRelaxed(), equalTo("héllö")); + assertThat(reader.getRead(), equalTo("héllö")); + assertThat(reader.getRemaining(), equalTo(" world")); + } + @Test public void readQuotedString() throws Exception { final StringReader reader = new StringReader("\"hello world\""); @@ -278,25 +286,25 @@ public void readQuotedString_invalidQuoteEscape() throws Exception { @Test public void readString_noQuotes() throws Exception { - final StringReader reader = new StringReader("hello world"); - assertThat(reader.readString(), equalTo("hello")); - assertThat(reader.getRead(), equalTo("hello")); - assertThat(reader.getRemaining(), equalTo(" world")); + final StringReader reader = new StringReader("héllo wörld"); + assertThat(reader.readString(), equalTo("héllo")); + assertThat(reader.getRead(), equalTo("héllo")); + assertThat(reader.getRemaining(), equalTo(" wörld")); } @Test public void readString_singleQuotes() throws Exception { - final StringReader reader = new StringReader("'hello world'"); - assertThat(reader.readString(), equalTo("hello world")); - assertThat(reader.getRead(), equalTo("'hello world'")); + final StringReader reader = new StringReader("'héllo wörld'"); + assertThat(reader.readString(), equalTo("héllo wörld")); + assertThat(reader.getRead(), equalTo("'héllo wörld'")); assertThat(reader.getRemaining(), equalTo("")); } @Test public void readString_doubleQuotes() throws Exception { - final StringReader reader = new StringReader("\"hello world\""); - assertThat(reader.readString(), equalTo("hello world")); - assertThat(reader.getRead(), equalTo("\"hello world\"")); + final StringReader reader = new StringReader("\"héllo wörld\""); + assertThat(reader.readString(), equalTo("héllo wörld")); + assertThat(reader.getRead(), equalTo("\"héllo wörld\"")); assertThat(reader.getRemaining(), equalTo("")); } diff --git a/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java b/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java index 68e52e16..2d83e25f 100644 --- a/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java +++ b/src/test/java/com/mojang/brigadier/arguments/StringArgumentTypeTest.java @@ -10,10 +10,7 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -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 com.mojang.brigadier.arguments.StringArgumentType.*; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.is; @@ -35,6 +32,14 @@ public void testParseWord() throws Exception { verify(reader).readUnquotedString(); } + @Test + public void testParseRelaxedWord() throws Exception { + final StringReader reader = mock(StringReader.class); + when(reader.readUnquotedStringRelaxed()).thenReturn("héllo"); + assertThat(relaxedWord().parse(reader), equalTo("héllo")); + verify(reader).readUnquotedStringRelaxed(); + } + @Test public void testParseString() throws Exception { final StringReader reader = mock(StringReader.class);