mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
JavaEnterInTextBlockHandler: new line on third open quote, preserve indent when inserting line break at block start (IDEA-CR-53311)
GitOrigin-RevId: 6d919937a6624f6a05e0386c8f10c5ba26bce249
This commit is contained in:
committed by
intellij-monorepo-bot
parent
443204183c
commit
7129bbcce7
+55
-63
@@ -5,87 +5,79 @@ import com.intellij.codeInsight.editorActions.enter.EnterInStringLiteralHandler;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class JavaEnterInTextBlockHandler extends EnterInStringLiteralHandler {
|
||||
|
||||
@Override
|
||||
public Result postProcessEnter(@NotNull PsiFile file, @NotNull Editor editor, @NotNull DataContext dataContext) {
|
||||
if (!(file instanceof PsiJavaFile)) return super.postProcessEnter(file, editor, dataContext);
|
||||
PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument());
|
||||
PsiLiteralExpressionImpl textBlock = getTextBlock(file, editor.getCaretModel().getOffset());
|
||||
if (textBlock == null) return super.postProcessEnter(file, editor, dataContext);
|
||||
public Result preprocessEnter(@NotNull PsiFile file,
|
||||
@NotNull Editor editor,
|
||||
@NotNull Ref<Integer> caretOffsetRef,
|
||||
@NotNull Ref<Integer> caretAdvanceRef,
|
||||
@NotNull DataContext dataContext,
|
||||
EditorActionHandler originalHandler) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
PsiLiteralExpressionImpl textBlock = getTextBlockAt(file, offset);
|
||||
if (textBlock == null) return Result.Continue;
|
||||
int textBlockOffset = textBlock.getTextOffset();
|
||||
String text = textBlock.getText();
|
||||
int offsetInTextBlock = offset - textBlockOffset;
|
||||
boolean isAtFirstLine = !text.substring(0, offsetInTextBlock).contains("\n");
|
||||
if (!isAtFirstLine) return Result.Continue;
|
||||
Document document = editor.getDocument();
|
||||
if (isContentAtTheEnd(textBlock)) {
|
||||
CodeStyleManager.getInstance(textBlock.getProject()).reformat(textBlock);
|
||||
offset = editor.getCaretModel().getOffset();
|
||||
Project project = textBlock.getProject();
|
||||
int secondLineStart = text.indexOf('\n');
|
||||
if (secondLineStart == -1) {
|
||||
document.insertString(offset, "\n");
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document);
|
||||
CodeStyleManager.getInstance(project).reformat(textBlock);
|
||||
text = textBlock.getText();
|
||||
int indent = getIndent(text, offsetInTextBlock + 1);
|
||||
if (indent == -1) return Result.Continue;
|
||||
editor.getCaretModel().moveToOffset(offset + 1 + indent);
|
||||
}
|
||||
else if (!isAtBlockStart(document, textBlock, offset)) {
|
||||
return super.postProcessEnter(file, editor, dataContext);
|
||||
else {
|
||||
int indent = getIndent(text, secondLineStart + 1);
|
||||
if (indent == -1) return Result.Continue;
|
||||
String newLine = '\n' + StringUtil.repeatSymbol(' ', indent);
|
||||
document.insertString(offset, newLine);
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document);
|
||||
editor.getCaretModel().moveToOffset(offset + newLine.length());
|
||||
}
|
||||
editor.getCaretModel().moveToOffset(findOffset(editor, document, textBlock, offset));
|
||||
return Result.Continue;
|
||||
return Result.Stop;
|
||||
}
|
||||
|
||||
private static boolean isContentAtTheEnd(@NotNull PsiLiteralExpressionImpl textBlock) {
|
||||
String text = textBlock.getTextBlockText();
|
||||
if (text == null) return false;
|
||||
boolean foundContent = false;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
if (!isWhitespaceOrNewLine(text.charAt(i))) {
|
||||
foundContent = true;
|
||||
}
|
||||
else if (foundContent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isAtBlockStart(@NotNull Document document, @NotNull PsiLiteralExpressionImpl textBlock, int offset) {
|
||||
String text = document.getText(new TextRange(textBlock.getTextOffset(), offset));
|
||||
if (!text.startsWith("\"\"\"")) return false;
|
||||
text = text.substring(3);
|
||||
return text.chars().allMatch(JavaEnterInTextBlockHandler::isWhitespaceOrNewLine);
|
||||
}
|
||||
|
||||
private static boolean isWhitespaceOrNewLine(int c) {
|
||||
return Character.isWhitespace(c) || c == '\n';
|
||||
}
|
||||
|
||||
private static int findOffset(@NotNull Editor editor,
|
||||
@NotNull Document document,
|
||||
@NotNull PsiLiteralExpressionImpl textBlock,
|
||||
int offset) {
|
||||
TextRange afterOffset = new TextRange(offset, textBlock.getTextRange().getEndOffset());
|
||||
String text = document.getText(afterOffset);
|
||||
int line = document.getLineNumber(offset);
|
||||
int lineStart = document.getLineStartOffset(line);
|
||||
int start = text.indexOf('\n') + 1;
|
||||
for (int i = start; i < text.length(); i++) {
|
||||
char c = text.charAt(i);
|
||||
if (isWhitespaceOrNewLine(c)) continue;
|
||||
int column = editor.offsetToLogicalPosition(offset + i).column;
|
||||
String indent = StringUtil.repeatSymbol(' ', column);
|
||||
document.replaceString(lineStart, offset, indent);
|
||||
return editor.logicalPositionToOffset(new LogicalPosition(line, column));
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLiteralExpressionImpl getTextBlock(@NotNull PsiFile file, int offset) {
|
||||
@Contract("null, _ -> null")
|
||||
private static PsiLiteralExpressionImpl getTextBlockAt(PsiFile file, int offset) {
|
||||
if (!(file instanceof PsiJavaFile)) return null;
|
||||
PsiJavaToken token = ObjectUtils.tryCast(file.findElementAt(offset), PsiJavaToken.class);
|
||||
if (token == null || token.getTokenType() != JavaTokenType.TEXT_BLOCK_LITERAL) return null;
|
||||
return ObjectUtils.tryCast(token.getParent(), PsiLiteralExpressionImpl.class);
|
||||
}
|
||||
|
||||
private static int getIndent(@NotNull String text, int start) {
|
||||
int indent = 0;
|
||||
for (int i = start; i < text.length(); i++) {
|
||||
char c = text.charAt(i);
|
||||
if (c == '\n') {
|
||||
indent = 0;
|
||||
continue;
|
||||
}
|
||||
if (Character.isWhitespace(c)) {
|
||||
indent++;
|
||||
continue;
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,14 @@ package com.intellij.codeInsight.editorActions;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -116,6 +119,14 @@ public class JavaQuoteHandler extends SimpleTokenSetQuoteHandler implements Java
|
||||
|
||||
@Override
|
||||
public void insertClosingQuote(@NotNull Editor editor, int offset, @NotNull PsiFile file, @NotNull CharSequence closingQuote) {
|
||||
editor.getDocument().insertString(offset, "\"\"\"");
|
||||
editor.getDocument().insertString(offset, "\n\"\"\"");
|
||||
Project project = file.getProject();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
PsiJavaToken token = ObjectUtils.tryCast(file.findElementAt(offset), PsiJavaToken.class);
|
||||
if (token == null) return;
|
||||
PsiLiteralExpression textBlock = ObjectUtils.tryCast(token.getParent(), PsiLiteralExpression.class);
|
||||
if (textBlock == null) return;
|
||||
CodeStyleManager.getInstance(project).reformat(textBlock);
|
||||
editor.getCaretModel().moveToOffset(textBlock.getTextRange().getEndOffset() - 3);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -2,8 +2,8 @@ class Test {
|
||||
|
||||
void test() {
|
||||
String block = """
|
||||
<caret>
|
||||
text""";
|
||||
<caret>
|
||||
text""";
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
class Test {
|
||||
void test() {
|
||||
String block = """
|
||||
<caret>
|
||||
<caret>
|
||||
|
||||
|
||||
|
||||
""";
|
||||
""";
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -23,7 +23,7 @@ class JavaQuoteTest extends LightJavaCodeInsightFixtureTestCase {
|
||||
void testSingleInComment() { doTest '/* <caret> */', '/* \'<caret> */', "'" as char }
|
||||
void testSingleInStringAfterEscape() { doTest ''' split(text, '\\<caret>); ''', ''' split(text, '\\'<caret>); ''', "'" as char }
|
||||
|
||||
void testTextBlock() { doTest ' ""<caret> ', ' """<caret>""" ' }
|
||||
void testTextBlock() { doTest '""<caret> ', ' """\n <caret>""" ' }
|
||||
void testDoubleQuoteInTextBlock() { doTest ' """ <caret> """ ', ' """ "<caret> """ ' }
|
||||
void testSingleQuoteInTextBlock() { doTest ' """ <caret> """ ', ' """ \'<caret> """ ', "'" as char }
|
||||
void testTextBlockClosing() {
|
||||
@@ -31,7 +31,7 @@ class JavaQuoteTest extends LightJavaCodeInsightFixtureTestCase {
|
||||
doTest ' """."<caret>"" ', ' """.""<caret>" '
|
||||
doTest ' """.""<caret>" ', ' """."""<caret> '
|
||||
}
|
||||
void testPrecedingTextBlock() { doTest 'f(""<caret> + """\n .""")', 'f("""<caret>""" + """\n .""")' }
|
||||
void testPrecedingTextBlock() { doTest 'f(""<caret> + """\n .""")', 'f("""\n <caret>""" + """\n .""")' }
|
||||
|
||||
private void doTest(String before, String after, char c = '"') {
|
||||
myFixture.configureByText("a.java", "class C {{\n ${before}\n}}")
|
||||
|
||||
Reference in New Issue
Block a user