diff --git a/java/java-impl/src/META-INF/JavaPlugin.xml b/java/java-impl/src/META-INF/JavaPlugin.xml index fcf1d2f2146d..0e4bbe658265 100644 --- a/java/java-impl/src/META-INF/JavaPlugin.xml +++ b/java/java-impl/src/META-INF/JavaPlugin.xml @@ -987,6 +987,10 @@ com.intellij.codeInsight.intention.impl.BreakStringOnLineBreaksIntentionAction Java/Strings + + com.intellij.codeInsight.intention.impl.SplitRawStringIntentionAction + Java/Strings + com.intellij.codeInsight.intention.impl.ReplaceCastWithVariableAction Java/Imports diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitRawStringIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitRawStringIntentionAction.java new file mode 100644 index 000000000000..b37b76ea5aa2 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitRawStringIntentionAction.java @@ -0,0 +1,86 @@ +// 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.codeInsight.intention.impl; + +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +public class SplitRawStringIntentionAction extends PsiElementBaseIntentionAction { + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + if (!(element instanceof PsiJavaToken)) { + return false; + } + + final PsiJavaToken token = (PsiJavaToken)element; + + if (token.getTokenType() != JavaTokenType.RAW_STRING_LITERAL) { + return false; + } + + final String text = token.getText(); + if (text == null) { + return false; + } + + int leadingTicsSequence = PsiRawStringLiteralUtil.getLeadingTicsSequence(text); + int trailingTicsSequence = PsiRawStringLiteralUtil.getTrailingTicsSequence(text); + if (leadingTicsSequence == trailingTicsSequence) { + int offset = editor.getCaretModel().getOffset(); + int caretInTokenIdx = offset - token.getTextOffset(); + if (caretInTokenIdx > leadingTicsSequence && + offset < token.getTextRange().getEndOffset() - trailingTicsSequence && + text.charAt(caretInTokenIdx) != '`' && + text.charAt(caretInTokenIdx - 1) != '`') { + return true; + } + } + return false; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + if (!(element instanceof PsiJavaToken)) { + return; + } + + final PsiJavaToken token = (PsiJavaToken)element; + + if (token.getTokenType() != JavaTokenType.RAW_STRING_LITERAL) { + return; + } + + + final String text = token.getText(); + if (text == null) { + return; + } + + int ticsSequenceLength = PsiRawStringLiteralUtil.getLeadingTicsSequence(text); + String breakSequence = StringUtil.repeat("`", ticsSequenceLength); + + int offset = editor.getCaretModel().getOffset(); + int splitIdx = offset - token.getTextOffset(); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + PsiBinaryExpression concatenation = + (PsiBinaryExpression)token.getParent().replace(factory.createExpressionFromText(text.substring(0, splitIdx) + breakSequence + " + " + + breakSequence + text.substring(splitIdx), element)); + editor.getCaretModel().moveToOffset(concatenation.getOperationSign().getTextOffset()); + } + + @NotNull + @Override + public String getText() { + return getFamilyName(); + } + + @NotNull + @Override + public String getFamilyName() { + return "Split raw string literal"; + } +} diff --git a/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/after.java.template b/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/after.java.template new file mode 100644 index 000000000000..f0f6d121b227 --- /dev/null +++ b/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/after.java.template @@ -0,0 +1 @@ +String s = ```Hello, ``` + ```world!```; \ No newline at end of file diff --git a/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/before.java.template b/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/before.java.template new file mode 100644 index 000000000000..f74b3af6c8a4 --- /dev/null +++ b/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/before.java.template @@ -0,0 +1 @@ +String s = ```Hello, world!```; \ No newline at end of file diff --git a/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/description.html b/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/description.html new file mode 100644 index 000000000000..f6182e73603f --- /dev/null +++ b/java/java-impl/src/intentionDescriptions/SplitRawStringIntentionAction/description.html @@ -0,0 +1,5 @@ + + +This intention allows to break raw string literal into 2 parts at caret position. + + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteral.after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteral.after.java new file mode 100644 index 000000000000..e7eb78860c68 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteral.after.java @@ -0,0 +1,5 @@ +class Test { + { + String s = ```ab``` + ```c```; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteral.java new file mode 100644 index 000000000000..f9f6d8170dfb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteral.java @@ -0,0 +1,5 @@ +class Test { + { + String s = ```abc```; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteralDisabledOnTic.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteralDisabledOnTic.java new file mode 100644 index 000000000000..b2701608c305 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advRawStringLiteral/SplitRawStringLiteralDisabledOnTic.java @@ -0,0 +1,5 @@ +class Test { + { + String s = ```ab`c```; + } +} \ 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 bafd7b302717..cccfa6dd8d82 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,9 +40,7 @@ public class LightAdvRawStringLiteralsTest extends LightCodeInsightFixtureTestCa public void testStringToRawTransformation() { doTestIntention(QuickFixBundle.message("convert.to.raw.string.text")); } public void testStringToRawTransformationWithWrongSeparators() { doTestIntention(QuickFixBundle.message("convert.to.raw.string.text")); } - public void testStringToRawTransformationLeadingTics() { - 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"); @@ -53,6 +51,12 @@ public class LightAdvRawStringLiteralsTest extends LightCodeInsightFixtureTestCa doTestIntention(QuickFixBundle.message("convert.to.raw.string.text")); } + public void testSplitRawStringLiteral() { doTestIntention("Split raw string literal"); } + public void testSplitRawStringLiteralDisabledOnTic() { + myFixture.configureByFile(getTestName(false) + ".java"); + assertEmpty(myFixture.filterAvailableIntentions("Split raw string literal")); + } + public void testPasteInRawStringLiteral() { doTestPaste("class A {{String s = `q`;}}", "a\nb`\nc", "class A {{String s = ``qa\nb`\nc``;}}"); }