[java] Implement Join lines action for text block

Support ending \, insert \n otherwise (to preserve semantics)
IDEA-337178 Join lines: support terminating \ in text blocks

GitOrigin-RevId: 2acb64443b83a27f29a969360b2cbbe34f7ea7d4
This commit is contained in:
Tagir Valeev
2024-02-01 16:16:56 +01:00
committed by intellij-monorepo-bot
parent 21b52d4e0c
commit 48cb7b5154
21 changed files with 221 additions and 0 deletions

View File

@@ -1222,6 +1222,7 @@
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.VariableJoinLinesHandler"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.FieldJoinLinesHandler"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.LiteralJoinLinesHandler"/>
<joinLinesHandler implementation="com.intellij.codeInsight.editorActions.TextBlockJoinLinesHandler"/>
<editorSmartKeysConfigurable instance="com.intellij.application.options.JavadocOptionsProvider" id="editor.preferences.javadocOptions"/>
<wordBoundaryFilter language="JAVA" implementationClass="com.intellij.codeInsight.editorActions.JavaWordBoundaryFilter"/>
<editorActionHandler action="PrevParameter" implementationClass="com.intellij.codeInsight.editorActions.JavaPrevParameterHandler"/>

View File

@@ -0,0 +1,68 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.editorActions;
import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiFragmentImpl;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
public final class TextBlockJoinLinesHandler implements JoinRawLinesHandlerDelegate {
@Override
public int tryJoinRawLines(@NotNull Document doc, @NotNull PsiFile file, int start, int endWithSpaces) {
CharSequence text = doc.getCharsSequence();
int end = getNextLineStart(start, text);
start--;
PsiJavaToken token = ObjectUtils.tryCast(file.findElementAt(start), PsiJavaToken.class);
if (token == null) return CANNOT_JOIN;
IElementType tokenType = token.getTokenType();
if (!tokenType.equals(JavaTokenType.TEXT_BLOCK_LITERAL) &&
!tokenType.equals(JavaTokenType.TEXT_BLOCK_TEMPLATE_BEGIN) &&
!tokenType.equals(JavaTokenType.TEXT_BLOCK_TEMPLATE_END) &&
!tokenType.equals(JavaTokenType.TEXT_BLOCK_TEMPLATE_MID)) {
return CANNOT_JOIN;
}
boolean singleSlash = false;
if (text.charAt(start) == '\\') {
int lineNumber = doc.getLineNumber(start);
int startOffset = Math.max(token.getTextRange().getStartOffset(), doc.getLineStartOffset(lineNumber));
String substring = doc.getText(TextRange.create(startOffset, start)) + "\\\n";
CharSequence parsed = CodeInsightUtilCore.parseStringCharacters(substring, null);
singleSlash = parsed != null && parsed.charAt(parsed.length() - 1) != '\n';
}
if (!singleSlash) {
start++;
}
int indent = token instanceof PsiFragment fragment
? PsiFragmentImpl.getTextBlockFragmentIndent(fragment)
: BasicLiteralUtil.getTextBlockIndent(token);
while (indent > 0 && text.charAt(end) == ' ' || text.charAt(end) == '\t') {
indent--;
end++;
}
if (singleSlash) {
doc.deleteString(start, end);
} else {
doc.replaceString(start, end, "\\n");
}
return start;
}
private static int getNextLineStart(int start, CharSequence text) {
int end = start;
while (text.charAt(end) != '\n') {
end++;
}
end++;
return end;
}
@Override
public int tryJoinLines(@NotNull Document document, @NotNull PsiFile file, int start, int end) {
return CANNOT_JOIN;
}
}

View File

@@ -0,0 +1,8 @@
class A {
void test() {
String s = STR."""
<caret>He\{1+1}llo \
World!
""";
}
}

View File

@@ -0,0 +1,8 @@
class A {
void test() {
String s = STR."""
<caret>Hello \
World!\{1+1}
""";
}
}

View File

@@ -0,0 +1,7 @@
class A {
void test() {
String s = STR."""
Hello World!\{1+1}
""";
}
}

View File

@@ -0,0 +1,7 @@
class A {
void test() {
String s = STR."""
He\{1+1}llo World!
""";
}
}

View File

@@ -0,0 +1,13 @@
class A {
void test() {
String s = """
Line1
<selection> Line2
Line3
Line4
Line5
</selection> Line6
Line7
""";
}
}

View File

@@ -0,0 +1,8 @@
class A {
void test() {
String s = """
<caret>Hello \\
World!
""";
}
}

View File

@@ -0,0 +1,7 @@
class A {
void test() {
String s = """
Hello \\\nWorld!
""";
}
}

View File

@@ -0,0 +1,8 @@
class A {
void test() {
String s = """
<caret>Hello \
World!
""";
}
}

View File

@@ -0,0 +1,8 @@
class A {
void test() {
String s = """
<caret>Hello \
World!
""";
}
}

View File

@@ -0,0 +1,7 @@
class A {
void test() {
String s = """
Hello World!
""";
}
}

View File

@@ -0,0 +1,9 @@
class A {
void test() {
String s = """
<caret>Hello \
World!
""";
}
}

View File

@@ -0,0 +1,8 @@
class A {
void test() {
String s = """
Hello \
World!
""";
}
}

View File

@@ -0,0 +1,7 @@
class A {
void test() {
String s = STR."""
<caret>Hello \
""";
}
}

View File

@@ -0,0 +1,6 @@
class A {
void test() {
String s = STR."""
Hello <caret>""";
}
}

View File

@@ -0,0 +1,7 @@
class A {
void test() {
String s = """
Hello World!
""";
}
}

View File

@@ -0,0 +1,8 @@
class A {
void test() {
String s = """
<caret>Hello \\\
World!
""";
}
}

View File

@@ -0,0 +1,7 @@
class A {
void test() {
String s = """
Hello \\<caret>World!
""";
}
}

View File

@@ -0,0 +1,9 @@
class A {
void test() {
String s = """
Line1
Line2\nLine3\n Line4\nLine5\n Line6
Line7
""";
}
}

View File

@@ -297,6 +297,16 @@ public class JoinLinesTest extends LightJavaCodeInsightTestCase {
doTest();
}
public void testCaseLabels3() {doTest();}
public void testJoinTextBlock() {doTest();}
public void testJoinTextBlockBackSlash() {doTest();}
public void testJoinTextBlockBackSlash2() {doTest();}
public void testJoinTextBlockBackDoubleSlash() {doTest();}
public void testJoinTextBlockBackTripleSlash() {doTest();}
public void testJoinTextBlockBackSlashEmptyLineAfter() {doTest();}
public void testJoinTextBlockBackSlashLastLine() {doTest();}
public void testJoinStringTemplateBackSlash() {doTest();}
public void testJoinStringTemplateBackSlash2() {doTest();}
private void doTest() {
doTest(".java");