diff --git a/src/main/java/ch/njol/skript/lang/SkriptParser.java b/src/main/java/ch/njol/skript/lang/SkriptParser.java index 47ee1ee9bfa..7903f385162 100644 --- a/src/main/java/ch/njol/skript/lang/SkriptParser.java +++ b/src/main/java/ch/njol/skript/lang/SkriptParser.java @@ -1351,11 +1351,15 @@ static int countUnescaped(final String pattern, final char c, final int start, f * @return Index of the end quote */ private static int nextQuote(final String s, final int from) { + boolean inExpression = false; for (int i = from; i < s.length(); i++) { - if (s.charAt(i) == '"') { + char c = s.charAt(i); + if (c == '"' && !inExpression) { if (i == s.length() - 1 || s.charAt(i + 1) != '"') return i; i++; + } else if (c == '%') { + inExpression = !inExpression; } } return -1; diff --git a/src/main/java/ch/njol/skript/lang/VariableString.java b/src/main/java/ch/njol/skript/lang/VariableString.java index e1447363a2c..c608e0ef221 100644 --- a/src/main/java/ch/njol/skript/lang/VariableString.java +++ b/src/main/java/ch/njol/skript/lang/VariableString.java @@ -147,6 +147,7 @@ public static VariableString newInstance(String s) { /** * Tests whether a string is correctly quoted, i.e. only has doubled double quotes in it. + * Singular double quotes are only allowed between percentage signs. * * @param s The string * @param withQuotes Whether s must be surrounded by double quotes or not @@ -156,12 +157,22 @@ public static boolean isQuotedCorrectly(String s, boolean withQuotes) { if (withQuotes && (!s.startsWith("\"") || !s.endsWith("\""))) return false; boolean quote = false; + boolean percentage = false; for (int i = withQuotes ? 1 : 0; i < (withQuotes ? s.length() - 1 : s.length()); i++) { - if (s.charAt(i) != '"') { - if (quote) - return false; - } else { + if (percentage) { + if (s.charAt(i) == '%') + percentage = false; + + continue; + } + + if (quote && s.charAt(i) != '"') + return false; + + if (s.charAt(i) == '"') { quote = !quote; + } else if (s.charAt(i) == '%') { + percentage = true; } } return !quote; @@ -190,7 +201,7 @@ public static String unquote(String s, boolean surroundingQuotes) { */ @Nullable public static VariableString newInstance(String orig, StringMode mode) { - if (!isQuotedCorrectly(orig, false)) + if (mode != StringMode.VARIABLE_NAME && !isQuotedCorrectly(orig, false)) return null; int n = StringUtils.count(orig, '%'); if (n % 2 != 0) { @@ -199,7 +210,26 @@ public static VariableString newInstance(String orig, StringMode mode) { } // We must not parse color codes yet, as JSON support would be broken :( - String s = orig.replace("\"\"", "\""); + String s; + if (mode != StringMode.VARIABLE_NAME) { + // Replace every double " character with a single ", except for those in expressions (between %) + StringBuilder stringBuilder = new StringBuilder(); + + boolean expression = false; + for (int i = 0; i < orig.length(); i++) { + char c = orig.charAt(i); + stringBuilder.append(c); + + if (c == '%') + expression = !expression; + + if (!expression && c == '"') + i++; + } + s = stringBuilder.toString(); + } else { + s = orig; + } List string = new ArrayList<>(n / 2 + 2); // List of strings and expressions @@ -275,7 +305,8 @@ public static VariableString newInstance(String orig, StringMode mode) { Object[] sa = string.toArray(); if (string.size() == 1 && string.get(0) instanceof Expression && ((Expression) string.get(0)).getReturnType() == String.class && - ((Expression) string.get(0)).isSingle()) { + ((Expression) string.get(0)).isSingle() && + mode == StringMode.MESSAGE) { String expr = ((Expression) string.get(0)).toString(null, false); Skript.warning(expr + " is already a text, so you should not put it in one (e.g. " + expr + " instead of " + "\"%" + expr.replace("\"", "\"\"") + "%\")"); } @@ -680,7 +711,7 @@ public void change(Event e, @Nullable Object[] delta, ChangeMode mode) throws Un @Override public boolean getAnd() { - return false; + return true; } @Override diff --git a/src/test/skript/tests/regressions/590-escaping quotes is required in some places it shouldn't be.sk b/src/test/skript/tests/regressions/590-escaping quotes is required in some places it shouldn't be.sk new file mode 100644 index 00000000000..d8552d32207 --- /dev/null +++ b/src/test/skript/tests/regressions/590-escaping quotes is required in some places it shouldn't be.sk @@ -0,0 +1,19 @@ +function myFunction_five_nine_zero(s: string) :: string: + return {_s} + +test "double quote parsing": + assert "Testing" is set with "simple string failed" + + assert "Testing %1 + 1%" is set with "simple string with expression failed" + + assert "Testing """ is set with "simple string with escaped quote failed" + + assert "Testing %length of "abc"%" is set with "string with expression with string ##1 failed" + assert "%myFunction_five_nine_zero("Hello")% world" is "Hello world" with "string with expression with string ##2 failed" + + + assert {_abc} is not set with "simple variable failed" + assert {_abc%%} is not set with "simple variable with escaped percentage sign failed" + assert {_abc%1 + 1%} is not set with "simple variable with expression failed" + + assert {_%subtext of "test" from characters 1 to 1%} is not set with "variable with expression with string failed" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprEntities.sk b/src/test/skript/tests/syntaxes/expressions/ExprEntities.sk index be40ab07b80..e98cad46aa3 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprEntities.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprEntities.sk @@ -1,6 +1,6 @@ test "entities in chunk": spawn 10 sheep at spawn of world "world" wait 1 tick - assert size of all entities in chunk at spawn of world "world" >= 10 with "Size of all entities in spawn chunk is not > 10: %size of all entities in chunk at spawn of world ""world""%" + assert size of all entities in chunk at spawn of world "world" >= 10 with "Size of all entities in spawn chunk is not > 10: %size of all entities in chunk at spawn of world "world"%" delete all entities in chunk at spawn of world "world" - assert size of all entities in chunk at spawn of world "world" = 0 with "Size of all entities in spawn chunk != 0: %size of all entities in chunk at spawn of world ""world""%" \ No newline at end of file + assert size of all entities in chunk at spawn of world "world" = 0 with "Size of all entities in spawn chunk != 0: %size of all entities in chunk at spawn of world "world"%"