[groovy] handle raw paste in single and double quoted string literals (IDEA-223211)

GitOrigin-RevId: 12ae0f67a5092bade271a23100bf1ec2835d9fa5
This commit is contained in:
Daniil Ovchinnikov
2019-11-13 18:32:35 +00:00
committed by intellij-monorepo-bot
parent 57ece59604
commit f94a007182
3 changed files with 75 additions and 0 deletions
@@ -0,0 +1,28 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.psi.util
fun isValidSingleQuotedStringContent(text: String): Boolean = isValidContent(text, '\'', '\n')
fun isValidDoubleQuotedStringContent(text: String): Boolean = isValidContent(text, '"', '$', '\n')
private fun isValidContent(text: String, vararg escapedChars: Char): Boolean {
val length: Int = text.length
var idx = 0
while (idx < length) {
val ch: Char = text[idx]
if (ch in escapedChars) {
return false
}
if (ch == '\\') {
if (idx + 1 < length) {
val nextCh: Char = text[idx + 1]
if (nextCh == '\\' || nextCh in escapedChars) {
idx += 2
continue
}
}
}
idx++
}
return true
}
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyTokenSets;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.StringKind;
import org.jetbrains.plugins.groovy.lang.psi.util.StringUtilKt;
import org.jetbrains.plugins.groovy.lang.resolve.GroovyStringLiteralManipulator;
import static org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes.*;
@@ -68,6 +69,10 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
return text;
}
if (rawText != null && canPasteRaw(text, rawText.rawText, stringKind)) {
return rawText.rawText;
}
StringBuilder buffer = new StringBuilder(text.length());
@NonNls String breaker = stringKind.getLineBreaker();
final String[] lines = LineTokenizer.tokenize(text.toCharArray(), false, true);
@@ -80,6 +85,21 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
return buffer.toString();
}
private static boolean canPasteRaw(String text, String rawText, StringKind kind) {
if (!text.equals(kind.unescape(rawText))) {
return false;
}
if (kind == StringKind.SINGLE_QUOTED) {
return StringUtilKt.isValidSingleQuotedStringContent(rawText);
}
else if (kind == StringKind.DOUBLE_QUOTED) {
return StringUtilKt.isValidDoubleQuotedStringContent(rawText);
}
else {
return true;
}
}
@NotNull
private static String escape(@NotNull StringKind kind, @NotNull String s) {
if (kind != StringKind.DOUBLE_QUOTED && kind != StringKind.TRIPLE_DOUBLE_QUOTED) {
@@ -177,6 +177,17 @@ class GroovyCopyPasteStringTest extends GroovyLatestTest implements BaseTest {
}.run()
}
@Test
void 'paste raw'() {
def data = [
['\'<selection>\\$ \\\' \\" \\\n \\u2318</selection>\'', '"<caret>"', '"\\$ \\\' \\" \\\n \\u2318"'],
['"<selection>\\$ \\\' \\" \\\n \\u2318</selection>"', "'<caret>'", '\'\\$ \\\' \\" \\\n \\u2318\'']
]
RunAll.runAll(data) { List<String> entry ->
doCopyPasteTest(entry[0], entry[1], entry[2])
}.run()
}
@Test
void 'multiline paste'() {
def from = '<selection>hi\nthere</selection>'
@@ -193,6 +204,22 @@ class GroovyCopyPasteStringTest extends GroovyLatestTest implements BaseTest {
}.run()
}
@Test
void 'multiline paste raw'() {
def from = '$/<selection>hi\nthere\\u2318</selection>/$'
def data = [
/'<caret>'/ : "'hi\\n' +\n 'there⌘'", // cannot paste raw
/'''<caret>'''/: "'''hi\nthere\\u2318'''",
/"<caret>"/ : '"hi\\n" +\n "there⌘"', // cannot paste raw
/"""<caret>"""/: '"""hi\nthere\\u2318"""',
'/ <caret>/' : '/ hi\nthere\\u2318/',
'$/<caret>/$' : '$/hi\nthere\\u2318/$',
]
RunAll.runAll(data) { to, expected ->
doCopyPasteTest(from, to, expected)
}.run()
}
@Test
void 'paste injection'() {
def data = [