diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java
index 99cbe653ce02..015a357c4cdf 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java
@@ -17,10 +17,13 @@ package org.jetbrains.plugins.groovy.lang.editor;
import com.intellij.codeInsight.editorActions.StringLiteralCopyPasteProcessor;
import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*;
@@ -38,9 +41,52 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
@Override
protected boolean isStringLiteral(@NotNull PsiElement token) {
ASTNode node = token.getNode();
- return node != null ? TokenSets.STRING_LITERALS.contains(node.getElementType()):false;
+ return node != null && TokenSets.STRING_LITERALS.contains(node.getElementType());
}
+ @Nullable
+ protected PsiElement findLiteralTokenType(PsiFile file, int selectionStart, int selectionEnd) {
+ PsiElement elementAtSelectionStart = file.findElementAt(selectionStart);
+ if (elementAtSelectionStart == null) {
+ return null;
+ }
+ IElementType elementType = elementAtSelectionStart.getNode().getElementType();
+ if ((elementType == mREGEX_END || elementType == mDOLLAR_SLASH_REGEX_END || elementType == mGSTRING_END) &&
+ elementAtSelectionStart.getTextOffset() == selectionStart) {
+ elementAtSelectionStart = elementAtSelectionStart.getPrevSibling();
+ if (elementAtSelectionStart == null) return null;
+ elementType = elementAtSelectionStart.getNode().getElementType();
+ }
+
+ if (!isStringLiteral(elementAtSelectionStart) && !isCharLiteral(elementAtSelectionStart)) {
+ return null;
+ }
+
+ if (elementAtSelectionStart.getTextRange().getEndOffset() < selectionEnd) {
+ final PsiElement elementAtSelectionEnd = file.findElementAt(selectionEnd);
+ if (elementAtSelectionEnd == null) {
+ return null;
+ }
+ if (elementAtSelectionEnd.getNode().getElementType() == elementType &&
+ elementAtSelectionEnd.getTextRange().getStartOffset() < selectionEnd) {
+ return elementAtSelectionStart;
+ }
+ }
+
+ final TextRange textRange = elementAtSelectionStart.getTextRange();
+
+ //content elements don't have quotes, so they are shorter than whole string literals
+ if (elementType == mREGEX_CONTENT || elementType == mGSTRING_CONTENT || elementType == mDOLLAR_SLASH_REGEX_CONTENT) {
+ selectionStart++;
+ selectionEnd--;
+ }
+ if (selectionStart <= textRange.getStartOffset() || selectionEnd >= textRange.getEndOffset()) {
+ return null;
+ }
+ return elementAtSelectionStart;
+ }
+
+
@Override
protected String getLineBreaker(PsiElement token) {
final String text = token.getText();
@@ -65,7 +111,10 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
protected String escapeCharCharacters(@NotNull String s, @NotNull PsiElement token, boolean escapeSlashes) {
IElementType tokenType = token.getNode().getElementType();
- if (tokenType == mREGEX_CONTENT || tokenType == mREGEX_LITERAL) {
+ if (tokenType == mREGEX_CONTENT ||
+ tokenType == mREGEX_LITERAL ||
+ tokenType == mDOLLAR_SLASH_REGEX_CONTENT ||
+ tokenType == mDOLLAR_SLASH_REGEX_LITERAL) {
if (escapeSlashes) {
return StringUtil.escapeSlashes(s);
}
@@ -100,7 +149,10 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce
protected String unescape(String text, PsiElement token) {
final IElementType tokenType = token.getNode().getElementType();
- if (tokenType == mREGEX_CONTENT || tokenType == mREGEX_LITERAL) {
+ if (tokenType == mREGEX_CONTENT ||
+ tokenType == mREGEX_LITERAL ||
+ tokenType == mDOLLAR_SLASH_REGEX_CONTENT ||
+ tokenType == mDOLLAR_SLASH_REGEX_LITERAL) {
return StringUtil.unescapeSlashes(text);
}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy
index 068f9efe47d3..f03bbc966f1b 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy
@@ -54,7 +54,7 @@ class GroovyCopyPasteTest extends LightCodeInsightFixtureTestCase {
}
public void testEscapeSlashesInRegexFromRegex() {
- doTest 'a.groovy', 'def x = /a\\/b/', 'def x = /smth/', 'def x = /smtha\\/b/'
+ doTest 'a.groovy', 'def x = / a\\/b/', 'def x = /smth/', 'def x = /smtha\\/b/'
}
void testDontEscapeSymbolsInRegex(){
@@ -100,4 +100,8 @@ second
"""'''
}
+ void testPasteInGStringContent() {
+ doTest 'a.groovy', 'def a = 5\\6', 'def x = " "', 'def x = "5\\\\6 "'
+ }
+
}