From 10271291ebea3384e8d42b4a3857a2ff957408e1 Mon Sep 17 00:00:00 2001 From: Alexey Utkin Date: Tue, 24 Apr 2018 15:04:24 +0300 Subject: [PATCH] CPP-12350 Implement calculation of indentation in line from the information of the lexer * SO inside indent calculation * line-wide comment as indent anchor * indent in pure blocks * improvements in shared indent calculator for enclosed statements --- .../editorActions/JavaLineIndentProvider.java | 4 +- .../formatter/java/JavaEnterActionTest.java | 49 +++++++++++++++++++ .../codeStyle/SemanticEditorPosition.java | 8 ++- .../JavaLikeLangLineIndentProvider.java | 20 +++++++- 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java index f3cb8622e9ae..7a9d64c74c0f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java @@ -26,10 +26,11 @@ import com.intellij.psi.TokenType; import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition; import com.intellij.psi.impl.source.codeStyle.lineIndent.JavaLikeLangLineIndentProvider; import com.intellij.psi.tree.IElementType; -import java.util.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; + import static com.intellij.formatting.Indent.Type.CONTINUATION; import static com.intellij.psi.impl.source.codeStyle.lineIndent.JavaLikeLangLineIndentProvider.JavaLikeElement.*; @@ -51,6 +52,7 @@ public class JavaLineIndentProvider extends JavaLikeLangLineIndentProvider { SYNTAX_MAP.put(JavaTokenType.CASE_KEYWORD, SwitchCase); SYNTAX_MAP.put(JavaTokenType.DEFAULT_KEYWORD, SwitchDefault); SYNTAX_MAP.put(JavaTokenType.IF_KEYWORD, IfKeyword); + SYNTAX_MAP.put(JavaTokenType.WHILE_KEYWORD, IfKeyword); SYNTAX_MAP.put(JavaTokenType.ELSE_KEYWORD, ElseKeyword); SYNTAX_MAP.put(JavaTokenType.FOR_KEYWORD, ForKeyword); SYNTAX_MAP.put(JavaTokenType.DO_KEYWORD, DoKeyword); diff --git a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaEnterActionTest.java b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaEnterActionTest.java index 4e9c80cbc108..d164a4bfdb13 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaEnterActionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/formatter/java/JavaEnterActionTest.java @@ -215,6 +215,55 @@ public class JavaEnterActionTest extends AbstractEnterActionTestCase { ") {}"); } + public void testEnter_AfterStatementWithoutBlock() throws IOException { + doTextTest("java", + "class T {\n" + + " void test() {\n" + + " if (true)\n" + + " while (true) \n" + + " }\n" + + "}\n", + "class T {\n" + + " void test() {\n" + + " if (true)\n" + + " while (true) \n" + + " \n" + + " }\n" + + "}\n"); + + doTextTest("java", + "class T {\n" + + " void test() {\n" + + " if (true)\n" + + " while (true) {\n" + + " }\n" + + "}\n", + "class T {\n" + + " void test() {\n" + + " if (true)\n" + + " while (true) {\n" + + " \n" + + " }\n" + + " }\n" + + "}\n"); + + doTextTest("java", + "class T {\n" + + " void test() {\n" + + " if (true)\n" + + " try {\n" + + " }\n" + + "}\n", + "class T {\n" + + " void test() {\n" + + " if (true)\n" + + " try {\n" + + " \n" + + " }\n" + + " }\n" + + "}\n"); + } + public void testEnter_AfterStatementWithLabel() throws IOException { // as prev doTextTest("java", diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/SemanticEditorPosition.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/SemanticEditorPosition.java index 6be9a730f4d8..69462cbcfc5f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/SemanticEditorPosition.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/SemanticEditorPosition.java @@ -30,6 +30,8 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; +import static java.lang.Integer.min; + /** * @author Rustam Vishnyakov */ @@ -305,7 +307,11 @@ public class SemanticEditorPosition { @Override public String toString() { - return myIterator.getTokenType().toString(); + return myIterator.atEnd() + ? "atEnd" + : myIterator.getTokenType().toString() + + "=>" + + getChars().subSequence(getStartOffset(), min(getStartOffset() + 255, getChars().length())); } public SemanticEditorPosition copy() { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java index e507378dafdf..e148304c79b9 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java @@ -287,6 +287,9 @@ public abstract class JavaLikeLangLineIndentProvider implements LineIndentProvid position.moveBeforeParentheses(ArrayOpeningBracket, ArrayClosingBracket); continue; } + else if (isStartOfStatementWithOptionalBlock(position)) { + return position.getStartOffset(); + } else if (position.isAtAnyOf(Semicolon, BlockOpeningBrace, BlockComment, @@ -294,7 +297,7 @@ public abstract class JavaLikeLangLineIndentProvider implements LineIndentProvid LeftParenthesis, LanguageStartDelimiter) || (position.getLanguage() != Language.ANY) && !position.isAtLanguage(currLanguage)) { - SemanticEditorPosition statementStart = getPosition(position.getEditor(), position.getStartOffset()); + SemanticEditorPosition statementStart = position.copy(); statementStart = statementStart.after().afterOptionalMix(Whitespace, LineComment); if (!isIndentProvider(statementStart, ignoreLabels)) { final SemanticEditorPosition maybeColon = statementStart.afterOptionalMix(Whitespace, BlockComment).after(); @@ -315,6 +318,21 @@ public abstract class JavaLikeLangLineIndentProvider implements LineIndentProvid return 0; } + /** + * Returns {@code true} if the {@code position} starts the statement that can have a code block. + * In C-kile languages it is one of {@code if, else, for, while, do, try}. + * + * @param position + */ + protected boolean isStartOfStatementWithOptionalBlock(@NotNull SemanticEditorPosition position) { + return position.isAtAnyOf( + ElseKeyword, + IfKeyword, + ForKeyword, + TryKeyword, + DoKeyword); + } + private static boolean atBlockStartAndNeedBlockIndent(@NotNull SemanticEditorPosition position) { return position.isAt(BlockOpeningBrace); }