diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/stringUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/stringUtil.kt
new file mode 100644
index 000000000000..ca2edb7be9fa
--- /dev/null
+++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/stringUtil.kt
@@ -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
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyLiteralCopyPasteProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyLiteralCopyPasteProcessor.java
index d48605d77091..95adb7268a58 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyLiteralCopyPasteProcessor.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyLiteralCopyPasteProcessor.java
@@ -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) {
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteStringTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteStringTest.groovy
index 64d1084ccad5..9013cf379a9b 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteStringTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteStringTest.groovy
@@ -177,6 +177,17 @@ class GroovyCopyPasteStringTest extends GroovyLatestTest implements BaseTest {
}.run()
}
+ @Test
+ void 'paste raw'() {
+ def data = [
+ ['\'\\$ \\\' \\" \\\n \\u2318\'', '""', '"\\$ \\\' \\" \\\n \\u2318"'],
+ ['"\\$ \\\' \\" \\\n \\u2318"', "''", '\'\\$ \\\' \\" \\\n \\u2318\'']
+ ]
+ RunAll.runAll(data) { List entry ->
+ doCopyPasteTest(entry[0], entry[1], entry[2])
+ }.run()
+ }
+
@Test
void 'multiline paste'() {
def from = 'hi\nthere'
@@ -193,6 +204,22 @@ class GroovyCopyPasteStringTest extends GroovyLatestTest implements BaseTest {
}.run()
}
+ @Test
+ void 'multiline paste raw'() {
+ def from = '$/hi\nthere\\u2318/$'
+ def data = [
+ /''/ : "'hi\\n' +\n 'there⌘'", // cannot paste raw
+ /''''''/: "'''hi\nthere\\u2318'''",
+ /""/ : '"hi\\n" +\n "there⌘"', // cannot paste raw
+ /""""""/: '"""hi\nthere\\u2318"""',
+ '/ /' : '/ hi\nthere\\u2318/',
+ '$//$' : '$/hi\nthere\\u2318/$',
+ ]
+ RunAll.runAll(data) { to, expected ->
+ doCopyPasteTest(from, to, expected)
+ }.run()
+ }
+
@Test
void 'paste injection'() {
def data = [