mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Convert escaped seqs properly in YAML dq strings
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package org.jetbrains.yaml.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.yaml.YAMLTokenTypes;
|
||||
import org.jetbrains.yaml.YAMLUtil;
|
||||
@@ -12,6 +15,7 @@ import org.jetbrains.yaml.psi.YAMLQuotedText;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class YAMLQuotedTextImpl extends YAMLScalarImpl implements YAMLQuotedText {
|
||||
private final boolean myIsSingleQuoted;
|
||||
@@ -73,32 +77,29 @@ public class YAMLQuotedTextImpl extends YAMLScalarImpl implements YAMLQuotedText
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("AssignmentToForLoopParameter")
|
||||
@Override
|
||||
protected List<Pair<TextRange, String>> getDecodeReplacements(@NotNull CharSequence input) {
|
||||
List<Pair<TextRange, String>> result = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i + 1 < input.length(); ++i) {
|
||||
final CharSequence subSequence = input.subSequence(i, i + 2);
|
||||
final TextRange textRange = TextRange.create(i, i + 2);
|
||||
|
||||
if (isSingleQuote() && "''".equals(subSequence)) {
|
||||
result.add(Pair.create(textRange, "'"));
|
||||
if (isSingleQuote() && input.charAt(i) == '\'' && input.charAt(i + 1) == '\'') {
|
||||
result.add(Pair.create(TextRange.from(i, 2), "'"));
|
||||
i++;
|
||||
}
|
||||
else if (!isSingleQuote() && "\\\n".equals(subSequence)) {
|
||||
result.add(Pair.create(textRange, ""));
|
||||
else if (!isSingleQuote() && input.charAt(i) == '\\') {
|
||||
if (input.charAt(i + 1) == '\n') {
|
||||
result.add(Pair.create(TextRange.from(i, 2), ""));
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
final int length = Escaper.findEscapementLength(input, i);
|
||||
final int charCode = Escaper.toUnicodeChar(input, i, length);
|
||||
final TextRange range = TextRange.create(i, Math.min(i + length + 1, input.length()));
|
||||
result.add(Pair.create(range, Character.toString((char)charCode)));
|
||||
i += range.getLength() - 1;
|
||||
}
|
||||
else if (!isSingleQuote() && "\\ ".equals(subSequence)) {
|
||||
result.add(Pair.create(textRange, " "));
|
||||
}
|
||||
else if (!isSingleQuote() && "\\\"".equals(subSequence)) {
|
||||
result.add(Pair.create(textRange, "\""));
|
||||
}
|
||||
else {
|
||||
//noinspection AssignmentToForLoopParameter
|
||||
i--;
|
||||
}
|
||||
//noinspection AssignmentToForLoopParameter
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -120,9 +121,10 @@ public class YAMLQuotedTextImpl extends YAMLScalarImpl implements YAMLQuotedText
|
||||
final List<Pair<TextRange, String>> result = new ArrayList<>();
|
||||
int currentLength = 0;
|
||||
for (int i = 0; i < input.length(); ++i) {
|
||||
if (input.charAt(i) == '\n') {
|
||||
final char c = input.charAt(i);
|
||||
if (c == '\n') {
|
||||
if (!isSingleQuote() && i + 1 < input.length() && YAMLGrammarCharUtil.isSpaceLike(input.charAt(i + 1))) {
|
||||
result.add(Pair.create(TextRange.from(i, 1), "\\\n" + indentString + "\\"));
|
||||
result.add(Pair.create(TextRange.from(i, 1), "\\n\\\n" + indentString + "\\"));
|
||||
}
|
||||
else {
|
||||
result.add(Pair.create(TextRange.from(i, 1), "\n\n" + indentString));
|
||||
@@ -133,12 +135,12 @@ public class YAMLQuotedTextImpl extends YAMLScalarImpl implements YAMLQuotedText
|
||||
|
||||
|
||||
if (currentLength > MAX_SCALAR_LENGTH_PREDEFINED
|
||||
&& (!isSingleQuote() || (input.charAt(i) == ' ' && isSurroundedByNoSpace(input, i)))) {
|
||||
&& (!isSingleQuote() || (c == ' ' && isSurroundedByNoSpace(input, i)))) {
|
||||
final String replacement;
|
||||
if (isSingleQuote()) {
|
||||
replacement = "\n" + indentString;
|
||||
}
|
||||
else if (YAMLGrammarCharUtil.isSpaceLike(input.charAt(i))) {
|
||||
else if (YAMLGrammarCharUtil.isSpaceLike(c)) {
|
||||
replacement = "\\\n" + indentString + "\\";
|
||||
}
|
||||
else {
|
||||
@@ -150,16 +152,16 @@ public class YAMLQuotedTextImpl extends YAMLScalarImpl implements YAMLQuotedText
|
||||
|
||||
currentLength++;
|
||||
|
||||
if (isSingleQuote() && input.charAt(i) == '\'') {
|
||||
if (isSingleQuote() && c == '\'') {
|
||||
result.add(Pair.create(TextRange.from(i, 1), "''"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isSingleQuote()) {
|
||||
if (input.charAt(i) == '"') {
|
||||
if (c == '"') {
|
||||
result.add(Pair.create(TextRange.from(i, 1), "\\\""));
|
||||
}
|
||||
else if (input.charAt(i) == '\\') {
|
||||
else if (c == '\\') {
|
||||
result.add(Pair.create(TextRange.from(i, 1), "\\\\"));
|
||||
}
|
||||
}
|
||||
@@ -180,4 +182,87 @@ public class YAMLQuotedTextImpl extends YAMLScalarImpl implements YAMLQuotedText
|
||||
public String toString() {
|
||||
return "YAML quoted text";
|
||||
}
|
||||
|
||||
private static class Escaper {
|
||||
private static final int[][] ONE_LETTER_CONVERSIONS = new int[][] {
|
||||
{'0', 0},
|
||||
{'a', 7},
|
||||
{'b', 8},
|
||||
{'t', 9},
|
||||
{9, 9},
|
||||
{'n', 10},
|
||||
{'v', 11},
|
||||
{'f', 12},
|
||||
{'r', 13},
|
||||
{'e', 27},
|
||||
{' ', 32},
|
||||
{'"', 34},
|
||||
{'/', 47},
|
||||
{'\\', 92},
|
||||
{'N', 133},
|
||||
{'_', 160},
|
||||
{'L', 8232},
|
||||
{'P', 8233},
|
||||
};
|
||||
|
||||
private static final NotNullLazyValue<Map<Integer, Integer>> ESC_TO_CODE = new NotNullLazyValue<Map<Integer, Integer>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<Integer, Integer> compute() {
|
||||
final HashMap<Integer, Integer> map = new HashMap<>(ONE_LETTER_CONVERSIONS.length);
|
||||
for (int[] conversion : ONE_LETTER_CONVERSIONS) {
|
||||
map.put(conversion[0], conversion[1]);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
};
|
||||
|
||||
private static final NotNullLazyValue<Map<Integer, Integer>> CODE_TO_ESC = new NotNullLazyValue<Map<Integer, Integer>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<Integer, Integer> compute() {
|
||||
final HashMap<Integer, Integer> map = new HashMap<>(ONE_LETTER_CONVERSIONS.length);
|
||||
for (int[] conversion : ONE_LETTER_CONVERSIONS) {
|
||||
map.put(conversion[1], conversion[2]);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
};
|
||||
|
||||
static int findEscapementLength(@NotNull CharSequence text, int pos) {
|
||||
if (pos + 1 >= text.length() || text.charAt(pos) != '\\') {
|
||||
throw new IllegalArgumentException("This is not an escapement start");
|
||||
}
|
||||
|
||||
final char c = text.charAt(pos + 1);
|
||||
if (c == 'x') {
|
||||
return 3;
|
||||
}
|
||||
else if (c == 'u') {
|
||||
return 5;
|
||||
}
|
||||
else if (c == 'U') {
|
||||
return 9;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int toUnicodeChar(@NotNull CharSequence text, int pos, int length) {
|
||||
if (length > 1) {
|
||||
CharSequence s = text.subSequence(pos + 2, Math.min(text.length(), pos + length + 1));
|
||||
try {
|
||||
return Integer.parseInt(s.toString(), 16);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return (int)'?';
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Integer result = ESC_TO_CODE.getValue().get((int)text.charAt(pos + 1));
|
||||
return ObjectUtils.notNull(result, (int)text.charAt(pos + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,10 @@ public class YAMLScalarContentTest extends LightPlatformCodeInsightFixtureTestCa
|
||||
public void testDoubleQuote2() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testDoubleQuote4() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile(getTestName(true) + ".yml");
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
"\n\n\nFun with \\
|
||||
\" \a \b \e \f \
|
||||
\n \r \t \v \0 \
|
||||
\ \_ \N \L \P \
|
||||
\x41 \u0041 \U00000041"
|
||||
Reference in New Issue
Block a user