* JavaLineIndentProvider introduced

* Fixes for indent calculation inside block after {
This commit is contained in:
Rustam Vishnyakov
2016-05-26 15:56:04 +03:00
parent c8a8807de8
commit e8f6bdb0a5
4 changed files with 154 additions and 22 deletions
@@ -0,0 +1,54 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.editorActions;
import com.intellij.lang.Language;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.TokenType;
import com.intellij.psi.impl.source.codeStyle.JavaLikeLangLineIndentProvider;
import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Rustam Vishnyakov
*/
public class JavaLineIndentProvider extends JavaLikeLangLineIndentProvider {
private final static HashMap<IElementType, SemanticEditorPosition.SyntaxElement> 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);
}
@Nullable
@Override
protected SemanticEditorPosition.SyntaxElement mapType(@NotNull IElementType tokenType) {
return SYNTAX_MAP.get(tokenType);
}
@Override
public boolean isSuitableFor(@Nullable Language language) {
return language != null && language.isKindOf(JavaLanguage.INSTANCE);
}
}
@@ -21,10 +21,12 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition.SyntaxElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
@@ -39,29 +41,30 @@ import static com.intellij.formatting.Indent.Type.*;
*/
public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineIndentProvider {
protected enum JavaLikeElement implements SemanticEditorPosition.SyntaxElement {
protected enum JavaLikeElement implements SyntaxElement {
Whitespace,
Semicolon,
BlockOpeningBrace,
BlockClosingBrace,
ArrayOpeningBracket
ArrayOpeningBracket,
RightParenthesis,
LeftParenthesis
}
@Nullable
@Override
public String getLineIndent(@NotNull Project project, @NotNull Editor editor, Language language, int offset) {
Type indent = getIndent(project, editor, language, offset);
if (indent != null){
return getIndentString(project, editor, offset, indent);
Pair<Type,SyntaxElement> indentData = getIndent(project, editor, language, offset);
if (indentData != null){
return getIndentString(project, editor, offset, indentData);
}
return super.getLineIndent(project, editor, language, offset);
}
@Nullable
protected Type getIndent(@NotNull Project project, @NotNull Editor editor, @Nullable Language language, int offset) {
protected Pair<Type,SyntaxElement> getIndent(@NotNull Project project, @NotNull Editor editor, @Nullable Language language, int offset) {
if (offset > 0) {
offset --;
offset--;
if (getPosition(editor, offset).matchesRule(
position -> position.isAt(JavaLikeElement.Whitespace) &&
position.isAtMultiline())) {
@@ -71,17 +74,17 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
.beforeOptional(JavaLikeElement.Semicolon)
.beforeOptional(JavaLikeElement.Whitespace)
.isAt(JavaLikeElement.BlockClosingBrace))) {
return getBlockIndentType(project, language);
return createIndentData(getBlockIndentType(project, language), JavaLikeElement.BlockClosingBrace);
}
else if (getPosition(editor, offset).matchesRule(
position -> position.before().isAt(JavaLikeElement.ArrayOpeningBracket)
position -> position.before().isAt(JavaLikeElement.ArrayOpeningBracket)
)) {
return CONTINUATION;
return createIndentData(CONTINUATION, JavaLikeElement.ArrayOpeningBracket);
}
else if (getPosition(editor, offset).matchesRule(
position -> position.before().isAt(JavaLikeElement.BlockOpeningBrace)
position -> position.before().isAt(JavaLikeElement.BlockOpeningBrace)
)) {
return getIndentTypeInBlock(project, language);
return createIndentData(getIndentTypeInBlock(project, language), JavaLikeElement.BlockOpeningBrace);
}
}
}
@@ -98,17 +101,20 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
}
@Nullable
protected abstract SemanticEditorPosition.SyntaxElement mapType(@NotNull IElementType tokenType);
protected abstract SyntaxElement mapType(@NotNull IElementType tokenType);
@Nullable
private static String getIndentString(@NotNull Project project, @NotNull Editor editor, int offset, Type indentType) {
private String getIndentString(@NotNull Project project,
@NotNull Editor editor,
int offset,
@NotNull Pair<Type, SyntaxElement> indentData) {
Document document = editor.getDocument();
String lastLineIndent = getLastLineIndent(document.getCharsSequence(), offset);
String baseIndent = getBaseIndent(editor, indentData.second, offset);
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file != null) {
CommonCodeStyleSettings.IndentOptions options = CodeStyleSettingsManager.getSettings(project).getIndentOptionsByFile(file);
return
lastLineIndent + new IndentInfo(0, indentTypeToSize(indentType, options), 0, false).generateNewWhiteSpace(options);
return
baseIndent + new IndentInfo(0, indentTypeToSize(indentData.first, options), 0, false).generateNewWhiteSpace(options);
}
return null;
}
@@ -124,11 +130,12 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
}
@NotNull
private static String getLastLineIndent(@NotNull CharSequence docChars, int offset) {
private String getBaseIndent(@NotNull Editor editor, @NotNull SyntaxElement afterElement, int offset) {
CharSequence docChars = editor.getDocument().getCharsSequence();
if (offset > 0) {
int indentStart = CharArrayUtil.shiftBackward(docChars, offset - 1, " \t\n\r");
if (indentStart > 0) {
indentStart = CharArrayUtil.shiftBackwardUntil(docChars, indentStart, "\n") + 1;
int indentLineOffset = getOffsetInBaseIndentLine(editor, docChars, afterElement, offset - 1);
if (indentLineOffset > 0) {
int indentStart = CharArrayUtil.shiftBackwardUntil(docChars, indentLineOffset, "\n") + 1;
if (indentStart >= 0) {
int indentEnd = CharArrayUtil.shiftForward(docChars, indentStart, " \t");
if (indentEnd > indentStart) {
@@ -139,6 +146,38 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
}
return "";
}
private int getOffsetInBaseIndentLine(@NotNull Editor editor,
@NotNull CharSequence docChars,
@NotNull SyntaxElement afterElement,
int offset) {
if (JavaLikeElement.BlockOpeningBrace.equals(afterElement)) {
return findStatementStart(editor, afterElement, offset);
}
else {
return CharArrayUtil.shiftBackward(docChars, offset, " \t\n\r");
}
}
private int findStatementStart(@NotNull Editor editor, @NotNull SyntaxElement afterElement, int offset) {
SemanticEditorPosition position = getPosition(editor, offset);
position
.beforeOptional(JavaLikeElement.Whitespace)
.beforeOptional(afterElement)
.beforeOptional(JavaLikeElement.Whitespace);
if (position.isAt(JavaLikeElement.RightParenthesis)) {
position.beforeParentheses(JavaLikeElement.LeftParenthesis, JavaLikeElement.RightParenthesis);
}
while (!position.isAtEnd()) {
if (position.isAt(JavaLikeElement.Whitespace) && position.isAtMultiline()) {
return position.after().getStartOffset();
}
position.before();
}
return -1;
}
@Nullable
private static Type getIndentTypeInBlock(@NotNull Project project, @Nullable Language language) {
@@ -161,4 +200,9 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
}
return null;
}
@Nullable
private static Pair<Type,SyntaxElement> createIndentData(@Nullable Type type, @NotNull SyntaxElement element) {
return type != null ? Pair.create(type, element) : null;
}
}
@@ -56,10 +56,43 @@ public abstract class SemanticEditorPosition {
return this;
}
public SemanticEditorPosition after() {
if (!myIterator.atEnd()) {
myIterator.advance();
}
return this;
}
public SemanticEditorPosition beforeParentheses(@NotNull SyntaxElement leftParenthesis, @NotNull SyntaxElement rightParenthesis) {
int parenLevel = 0;
while (!myIterator.atEnd()) {
SyntaxElement currElement = map(myIterator.getTokenType());
myIterator.retreat();
if (rightParenthesis.equals(currElement)) {
parenLevel++;
}
else if (leftParenthesis.equals(currElement)) {
parenLevel--;
if (parenLevel < 1) {
break;
}
}
}
return this;
}
public boolean isAt(@NotNull SyntaxElement syntaxElement) {
return !myIterator.atEnd() && syntaxElement.equals(map(myIterator.getTokenType()));
}
public boolean isAtEnd() {
return myIterator.atEnd();
}
public int getStartOffset() {
return myIterator.getStart();
}
@SuppressWarnings("unused")
public boolean isAtAnyOf(@NotNull SyntaxElement... syntaxElements) {
if (!myIterator.atEnd()) {
+1
View File
@@ -1320,6 +1320,7 @@
implementationClass="com.intellij.codeInsight.hint.ClassInitializerDeclarationRangeHandler"/>
<backspaceHandlerDelegate implementation="com.intellij.codeInsight.editorActions.JavaBackspaceHandler"/>
<lineIndentProvider implementation="com.intellij.codeInsight.editorActions.JavaLineIndentProvider"/>
<usageTargetProvider implementation="com.intellij.find.findUsages.ThrowsUsageTargetProvider"/>