From 972a88c2976dad334e6a00d75ef7f8eba455267c Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Fri, 27 May 2016 12:32:20 +0300 Subject: [PATCH] Support line indent calculation after case/default --- .../editorActions/JavaLineIndentProvider.java | 19 +++++--- .../JavaLikeLangLineIndentProvider.java | 47 +++++++++++-------- .../codeStyle/SemanticEditorPosition.java | 12 +++++ 3 files changed, 52 insertions(+), 26 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 008078f605b8..1205ae568e03 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java @@ -26,19 +26,24 @@ import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.psi.impl.source.codeStyle.JavaLikeLangLineIndentProvider.JavaLikeElement.*; + /** * @author Rustam Vishnyakov */ public class JavaLineIndentProvider extends JavaLikeLangLineIndentProvider { private final static HashMap SYNTAX_MAP = new HashMap<>(); static { - SYNTAX_MAP.put(TokenType.WHITE_SPACE, JavaLikeElement.Whitespace); - SYNTAX_MAP.put(JavaTokenType.SEMICOLON, JavaLikeElement.Semicolon); - SYNTAX_MAP.put(JavaTokenType.LBRACE, JavaLikeElement.BlockOpeningBrace); - SYNTAX_MAP.put(JavaTokenType.RBRACE, JavaLikeElement.BlockClosingBrace); - SYNTAX_MAP.put(JavaTokenType.LBRACKET, JavaLikeElement.ArrayOpeningBracket); - SYNTAX_MAP.put(JavaTokenType.RPARENTH, JavaLikeElement.RightParenthesis); - SYNTAX_MAP.put(JavaTokenType.LPARENTH, JavaLikeElement.LeftParenthesis); + SYNTAX_MAP.put(TokenType.WHITE_SPACE, Whitespace); + SYNTAX_MAP.put(JavaTokenType.SEMICOLON, Semicolon); + SYNTAX_MAP.put(JavaTokenType.LBRACE, BlockOpeningBrace); + SYNTAX_MAP.put(JavaTokenType.RBRACE, BlockClosingBrace); + SYNTAX_MAP.put(JavaTokenType.LBRACKET, ArrayOpeningBracket); + SYNTAX_MAP.put(JavaTokenType.RPARENTH, RightParenthesis); + SYNTAX_MAP.put(JavaTokenType.LPARENTH, LeftParenthesis); + SYNTAX_MAP.put(JavaTokenType.COLON, Colon); + SYNTAX_MAP.put(JavaTokenType.CASE_KEYWORD, SwitchCase); + SYNTAX_MAP.put(JavaTokenType.DEFAULT_KEYWORD, SwitchDefault); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/JavaLikeLangLineIndentProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/JavaLikeLangLineIndentProvider.java index 6cae272e09b2..4f50aa2a45cb 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/JavaLikeLangLineIndentProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/JavaLikeLangLineIndentProvider.java @@ -34,6 +34,7 @@ import org.jetbrains.annotations.Nullable; import static com.intellij.formatting.Indent.Type; import static com.intellij.formatting.Indent.Type.*; +import static com.intellij.psi.impl.source.codeStyle.JavaLikeLangLineIndentProvider.JavaLikeElement.*; /** * A base class Java-like language line indent provider. If JavaLikeLangLineIndentProvider is unable to calculate @@ -41,14 +42,17 @@ import static com.intellij.formatting.Indent.Type.*; */ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineIndentProvider { - protected enum JavaLikeElement implements SyntaxElement { + public enum JavaLikeElement implements SyntaxElement { Whitespace, Semicolon, BlockOpeningBrace, BlockClosingBrace, ArrayOpeningBracket, RightParenthesis, - LeftParenthesis + LeftParenthesis, + Colon, + SwitchCase, + SwitchDefault } @Nullable @@ -66,25 +70,30 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI if (offset > 0) { offset--; if (getPosition(editor, offset).matchesRule( - position -> position.isAt(JavaLikeElement.Whitespace) && + position -> position.isAt(Whitespace) && position.isAtMultiline())) { if (getPosition(editor, offset).matchesRule( position -> position .before() - .beforeOptional(JavaLikeElement.Semicolon) - .beforeOptional(JavaLikeElement.Whitespace) - .isAt(JavaLikeElement.BlockClosingBrace))) { - return createIndentData(getBlockIndentType(project, language), JavaLikeElement.BlockClosingBrace); + .beforeOptional(Semicolon) + .beforeOptional(Whitespace) + .isAt(BlockClosingBrace))) { + return createIndentData(getBlockIndentType(project, language), BlockClosingBrace); } else if (getPosition(editor, offset).matchesRule( - position -> position.before().isAt(JavaLikeElement.ArrayOpeningBracket) + position -> position.before().isAt(ArrayOpeningBracket) )) { - return createIndentData(CONTINUATION, JavaLikeElement.ArrayOpeningBracket); + return createIndentData(CONTINUATION, ArrayOpeningBracket); } else if (getPosition(editor, offset).matchesRule( - position -> position.before().isAt(JavaLikeElement.BlockOpeningBrace) + position -> position.before().isAt(BlockOpeningBrace) )) { - return createIndentData(getIndentTypeInBlock(project, language), JavaLikeElement.BlockOpeningBrace); + return createIndentData(getIndentTypeInBlock(project, language), BlockOpeningBrace); + } + else if (getPosition(editor, offset).matchesRule( + position -> position.before().isAt(Colon) && position.isAfterOnSameLine(SwitchCase, SwitchDefault) + )) { + return createIndentData(NORMAL, SwitchCase); } } } @@ -152,7 +161,7 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI @NotNull CharSequence docChars, @NotNull SyntaxElement afterElement, int offset) { - if (JavaLikeElement.BlockOpeningBrace.equals(afterElement) && !isOnSeparateLine(editor, afterElement, offset)) { + if (BlockOpeningBrace.equals(afterElement) && !isOnSeparateLine(editor, afterElement, offset)) { return findStatementStart(editor, afterElement, offset); } return CharArrayUtil.shiftBackward(docChars, offset, " \t\n\r"); @@ -161,10 +170,10 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI private boolean isOnSeparateLine(@NotNull Editor editor, @NotNull SyntaxElement element, int offset) { SemanticEditorPosition position = getPosition(editor, offset); - position.beforeOptional(JavaLikeElement.Whitespace); + position.beforeOptional(Whitespace); if (position.isAt(element)) { position.before(); - if (position.isAtEnd() || position.isAt(JavaLikeElement.Whitespace) && position.isAtMultiline()) return true; + if (position.isAtEnd() || position.isAt(Whitespace) && position.isAtMultiline()) return true; } return false; } @@ -173,14 +182,14 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI private int findStatementStart(@NotNull Editor editor, @NotNull SyntaxElement afterElement, int offset) { SemanticEditorPosition position = getPosition(editor, offset); position - .beforeOptional(JavaLikeElement.Whitespace) + .beforeOptional(Whitespace) .beforeOptional(afterElement) - .beforeOptional(JavaLikeElement.Whitespace); - if (position.isAt(JavaLikeElement.RightParenthesis)) { - position.beforeParentheses(JavaLikeElement.LeftParenthesis, JavaLikeElement.RightParenthesis); + .beforeOptional(Whitespace); + if (position.isAt(RightParenthesis)) { + position.beforeParentheses(LeftParenthesis, RightParenthesis); } while (!position.isAtEnd()) { - if (position.isAt(JavaLikeElement.Whitespace) && position.isAtMultiline()) { + if (position.isAt(Whitespace) && position.isAtMultiline()) { return position.after().getStartOffset(); } position.before(); 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 c194a286d538..4c8f40981770 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 @@ -81,6 +81,18 @@ public abstract class SemanticEditorPosition { return this; } + public boolean isAfterOnSameLine(@NotNull SyntaxElement... syntaxElements) { + myIterator.retreat(); + while (!myIterator.atEnd() && !isAtMultiline()) { + SyntaxElement currElement = map(myIterator.getTokenType()); + for (SyntaxElement element : syntaxElements) { + if (element.equals(currElement)) return true; + } + myIterator.retreat(); + } + return false; + } + public boolean isAt(@NotNull SyntaxElement syntaxElement) { return !myIterator.atEnd() && syntaxElement.equals(map(myIterator.getTokenType())); }