diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertStringLiteralToRawAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertStringLiteralToRawAction.java
index fcc6b1cfa6b6..1f12005af483 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertStringLiteralToRawAction.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertStringLiteralToRawAction.java
@@ -2,7 +2,6 @@
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
-import com.intellij.codeInsight.editorActions.RawStringLiteralPasteProcessor;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.LowPriorityAction;
import com.intellij.openapi.editor.Editor;
@@ -33,8 +32,15 @@ public class ConvertStringLiteralToRawAction implements IntentionAction, LowPrio
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
final PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
- return PsiUtil.isJavaToken(element, JavaTokenType.STRING_LITERAL) &&
- PsiUtil.getLanguageLevel(file) == LanguageLevel.JDK_11_PREVIEW;
+ if (PsiUtil.isJavaToken(element, JavaTokenType.STRING_LITERAL) &&
+ PsiUtil.getLanguageLevel(file) == LanguageLevel.JDK_11_PREVIEW) {
+ PsiElement parent = element.getParent();
+ if (parent instanceof PsiLiteralExpressionImpl) {
+ String text = ((PsiLiteralExpressionImpl)parent).getInnerText();
+ return text != null && PsiRawStringLiteralUtil.getLeadingTicsSequence(text) < text.length();
+ }
+ }
+ return false;
}
@Override
@@ -55,10 +61,21 @@ public class ConvertStringLiteralToRawAction implements IntentionAction, LowPrio
if (innerText == null) return;
text = StringUtil.unescapeStringCharacters(innerText);
}
- String additionalQuotes = RawStringLiteralPasteProcessor.getAdditionalQuotes(text, "`");
+ String prefix = "";
+ int startingSeq = PsiRawStringLiteralUtil.getLeadingTicsSequence(text);
+ if (startingSeq > 0) {
+ prefix = "\"" + StringUtil.repeat("`", startingSeq) + "\" + ";
+ }
+ String suffix = "";
+ int tailingSequence = PsiRawStringLiteralUtil.getTailingTicsSequence(text);
+ if (tailingSequence > 0) {
+ suffix = "+ \"" + StringUtil.repeat("`", tailingSequence) + "\"";
+ }
+ String textTicsTrimmed = text.substring(Math.max(startingSeq, 0), text.length() - Math.max(tailingSequence, 0));
+ String additionalQuotes = PsiRawStringLiteralUtil.getAdditionalTics(textTicsTrimmed, "`");
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
CodeStyleManager.getInstance(project).reformat(
- elementToReplace.replace(elementFactory.createExpressionFromText('`' + additionalQuotes + text + additionalQuotes + '`', null)));
+ elementToReplace.replace(elementFactory.createExpressionFromText(prefix + '`' + additionalQuotes + textTicsTrimmed + additionalQuotes + '`' + suffix, null)));
}
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/RawStringLiteralPasteProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/RawStringLiteralPasteProcessor.java
index ddec9daaab87..17ee9539477a 100644
--- a/java/java-impl/src/com/intellij/codeInsight/editorActions/RawStringLiteralPasteProcessor.java
+++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/RawStringLiteralPasteProcessor.java
@@ -13,11 +13,7 @@ import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.JavaTokenType;
-import com.intellij.psi.PsiDocumentManager;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
+import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -45,38 +41,12 @@ public class RawStringLiteralPasteProcessor implements PasteProvider {
if (stringLiteral == null) return;
String literalText = stringLiteral.getText();
- int length = literalText.length();
- int quotesLength = getQuotesSequence(literalText, length, 0);
-
- String quotes = literalText.substring(0, quotesLength);
- String additionalQuotes = getAdditionalQuotes(text, quotes);
+ int ticsLength = PsiRawStringLiteralUtil.getLeadingTicsSequence(literalText);
+ String quotes = literalText.substring(0, ticsLength);
+ String additionalQuotes = PsiRawStringLiteralUtil.getAdditionalTics(text, quotes);
insertAtCaret(text, additionalQuotes, stringLiteral, editor);
}
- public static String getAdditionalQuotes(String text, String quotes) {
- int quotesLength = quotes.length();
- int textLength = text.length();
- int idx = quotesLength;
- int maxQuotesNumber = -1;
- boolean hasToReplace = false;
- while ((idx = text.indexOf(quotes, idx)) > 0 && idx < textLength) {
- int additionalQuotesLength = getQuotesSequence(text, textLength, idx + quotesLength);
- if (additionalQuotesLength == 0) {
- hasToReplace = true;
- }
- maxQuotesNumber = Math.max(maxQuotesNumber, additionalQuotesLength);
- idx += additionalQuotesLength + quotesLength;
- }
-
- return hasToReplace ? StringUtil.repeat("`", maxQuotesNumber + 1) : "";
- }
-
- private static int getQuotesSequence(String literalText, int length, int startIndex) {
- int quotesLength = startIndex;
- while (quotesLength < length && literalText.charAt(quotesLength) == '`') quotesLength++;
- return quotesLength - startIndex;
- }
-
@Override
public boolean isPastePossible(@NotNull DataContext dataContext) {
final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
diff --git a/java/java-psi-api/src/com/intellij/psi/PsiRawStringLiteralUtil.java b/java/java-psi-api/src/com/intellij/psi/PsiRawStringLiteralUtil.java
new file mode 100644
index 000000000000..71a25bf6bae1
--- /dev/null
+++ b/java/java-psi-api/src/com/intellij/psi/PsiRawStringLiteralUtil.java
@@ -0,0 +1,51 @@
+// Copyright 2000-2018 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 com.intellij.psi;
+
+import com.intellij.openapi.util.text.StringUtil;
+
+public class PsiRawStringLiteralUtil {
+ /**
+ * Check if text contains tics, and
+ * if yes, returns the number of additional tics required around text to have a valid raw string literal
+ * empty string otherwise
+ */
+ public static String getAdditionalTics(String text, String tics) {
+ int quotesLength = tics.length();
+ int textLength = text.length();
+ int idx = quotesLength;
+ int maxQuotesNumber = -1;
+ boolean hasToReplace = false;
+ while ((idx = text.indexOf(tics, idx)) > 0 && idx < textLength) {
+ int additionalQuotesLength = getTicsSequence(text, textLength, idx + quotesLength);
+ if (additionalQuotesLength == 0) {
+ hasToReplace = true;
+ }
+ maxQuotesNumber = Math.max(maxQuotesNumber, additionalQuotesLength);
+ idx += additionalQuotesLength + quotesLength;
+ }
+
+ return hasToReplace ? StringUtil.repeat("`", maxQuotesNumber + 1) : "";
+ }
+
+ /**
+ * Return number of leading tics in the text
+ */
+ public static int getLeadingTicsSequence(String text) {
+ return getTicsSequence(text, text.length(), 0);
+ }
+
+ /**
+ * Return number of tailing tics in the text
+ */
+ public static int getTailingTicsSequence(String text) {
+ int length = text.length();
+ while (length > 0 && text.charAt(length - 1) == '`') length--;
+ return text.length() - length;
+ }
+
+ private static int getTicsSequence(String literalText, int length, int startIndex) {
+ int quotesLength = startIndex;
+ while (quotesLength < length && literalText.charAt(quotesLength) == '`') quotesLength++;
+ return quotesLength - startIndex;
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationLeadingTics.after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationLeadingTics.after.java
new file mode 100644
index 000000000000..de0ec8596559
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationLeadingTics.after.java
@@ -0,0 +1,5 @@
+class A {
+ {
+ String s = "````" + `a` + "`";
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationLeadingTics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationLeadingTics.java
new file mode 100644
index 000000000000..9ebf0bf0a509
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationLeadingTics.java
@@ -0,0 +1,5 @@
+class A {
+ {
+ String s = "````a`";
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationOnlyTics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationOnlyTics.java
new file mode 100644
index 000000000000..26830e023992
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/StringToRawTransformationOnlyTics.java
@@ -0,0 +1,5 @@
+class A {
+ {
+ String s = "`````";
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightAdvRawStringLiteralsTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightAdvRawStringLiteralsTest.java
index 7266c41fc0e9..cb6b7f53f0c9 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightAdvRawStringLiteralsTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightAdvRawStringLiteralsTest.java
@@ -40,6 +40,15 @@ public class LightAdvRawStringLiteralsTest extends LightCodeInsightFixtureTestCa
doTestIntention(QuickFixBundle.message("convert.to.raw.string.text"));
}
+ public void testStringToRawTransformationLeadingTics() {
+ doTestIntention(QuickFixBundle.message("convert.to.raw.string.text"));
+ }
+
+ public void testStringToRawTransformationOnlyTics() {
+ myFixture.configureByFile(getTestName(false) + ".java");
+ assertEmpty(myFixture.filterAvailableIntentions(QuickFixBundle.message("convert.to.raw.string.text")));
+ }
+
public void testStringToRawTransformationWithTicsInside() {
doTestIntention(QuickFixBundle.message("convert.to.raw.string.text"));
}