mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
JavaLikeLangIndentProvider refactoring
This commit is contained in:
+13
@@ -123,7 +123,20 @@ public abstract class SemanticEditorPosition {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public CharSequence getChars() {
|
||||
return myChars;
|
||||
}
|
||||
|
||||
|
||||
public int findStartOf(@NotNull SyntaxElement element) {
|
||||
while (!myIterator.atEnd()) {
|
||||
if (element.equals(map(myIterator.getTokenType()))) return myIterator.getStart();
|
||||
myIterator.retreat();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SyntaxElement getCurrElement() {
|
||||
return !myIterator.atEnd() ? map(myIterator.getTokenType()) : null;
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.psi.impl.source.codeStyle.lineIndent;
|
||||
|
||||
import com.intellij.formatting.Indent;
|
||||
import com.intellij.formatting.IndentInfo;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
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;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.formatting.Indent.Type.CONTINUATION;
|
||||
import static com.intellij.formatting.Indent.Type.NORMAL;
|
||||
|
||||
class IndentCalculator {
|
||||
|
||||
private @NotNull final Project myProject;
|
||||
private @NotNull final Editor myEditor;
|
||||
private @NotNull BaseLineOffsetCalculator myBaseLineOffsetCalculator;
|
||||
private @NotNull final Indent.Type myIndentType;
|
||||
|
||||
public IndentCalculator(@NotNull Project project,
|
||||
@NotNull Editor editor,
|
||||
@NotNull BaseLineOffsetCalculator baseLineOffsetCalculator,
|
||||
@NotNull Indent.Type type) {
|
||||
myProject = project;
|
||||
myEditor = editor;
|
||||
myBaseLineOffsetCalculator = baseLineOffsetCalculator;
|
||||
myIndentType = type;
|
||||
}
|
||||
|
||||
public final static BaseLineOffsetCalculator LINE_BEFORE = new BaseLineOffsetCalculator() {
|
||||
@Override
|
||||
public int getOffsetInBaseIndentLine(@NotNull SemanticEditorPosition currPosition) {
|
||||
return CharArrayUtil.shiftBackward(currPosition.getChars(), currPosition.getStartOffset(), " \t\n\r");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Nullable
|
||||
String getIndentString(@NotNull SemanticEditorPosition currPosition) {
|
||||
Document document = myEditor.getDocument();
|
||||
String baseIndent = getBaseIndent(currPosition);
|
||||
PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
|
||||
if (file != null) {
|
||||
CommonCodeStyleSettings.IndentOptions options = CodeStyleSettingsManager.getSettings(myProject).getIndentOptionsByFile(file);
|
||||
return
|
||||
baseIndent + new IndentInfo(0, indentTypeToSize(myIndentType, options), 0, false).generateNewWhiteSpace(options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private String getBaseIndent(@NotNull SemanticEditorPosition currPosition) {
|
||||
CharSequence docChars = myEditor.getDocument().getCharsSequence();
|
||||
int offset = currPosition.getStartOffset();
|
||||
if (offset > 0) {
|
||||
int indentLineOffset = myBaseLineOffsetCalculator.getOffsetInBaseIndentLine(currPosition);
|
||||
if (indentLineOffset > 0) {
|
||||
int indentStart = CharArrayUtil.shiftBackwardUntil(docChars, indentLineOffset, "\n") + 1;
|
||||
if (indentStart >= 0) {
|
||||
int indentEnd = CharArrayUtil.shiftForward(docChars, indentStart, " \t");
|
||||
if (indentEnd > indentStart) {
|
||||
return docChars.subSequence(indentStart, indentEnd).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static int indentTypeToSize(@NotNull Indent.Type indentType, @NotNull CommonCodeStyleSettings.IndentOptions options) {
|
||||
if (indentType == NORMAL) {
|
||||
return options.INDENT_SIZE;
|
||||
}
|
||||
else if (indentType == CONTINUATION) {
|
||||
return options.CONTINUATION_INDENT_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public interface BaseLineOffsetCalculator {
|
||||
int getOffsetInBaseIndentLine(@NotNull SemanticEditorPosition position);
|
||||
}
|
||||
}
|
||||
+54
-131
@@ -15,21 +15,16 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.codeStyle.lineIndent;
|
||||
|
||||
import com.intellij.formatting.IndentInfo;
|
||||
import com.intellij.lang.Language;
|
||||
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;
|
||||
import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition.SyntaxElement;
|
||||
import com.intellij.psi.impl.source.codeStyle.lineIndent.IndentCalculator.BaseLineOffsetCalculator;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -62,65 +57,62 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
|
||||
DocBlockEnd
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getLineIndent(@NotNull Project project, @NotNull Editor editor, Language language, int offset) {
|
||||
Pair<Type,SyntaxElement> indentData = getIndent(project, editor, language, offset);
|
||||
if (indentData != null){
|
||||
return getIndentString(project, editor, offset, indentData);
|
||||
IndentCalculator indentCalculator = getIndent(project, editor, language, offset);
|
||||
if (indentCalculator != null){
|
||||
return indentCalculator.getIndentString(getPosition(editor, offset));
|
||||
}
|
||||
return super.getLineIndent(project, editor, language, offset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Pair<Type,SyntaxElement> getIndent(@NotNull Project project, @NotNull Editor editor, @Nullable Language language, int offset) {
|
||||
protected IndentCalculator getIndent(@NotNull Project project, @NotNull Editor editor, @Nullable Language language, int offset) {
|
||||
if (offset > 0) {
|
||||
offset--;
|
||||
if (getPosition(editor, offset).matchesRule(
|
||||
position -> position.isAt(Whitespace) &&
|
||||
position.isAtMultiline())) {
|
||||
IndentCalculatorFactory myFactory = new IndentCalculatorFactory(project, editor);
|
||||
if (getPosition(editor, offset).matchesRule(
|
||||
position -> position
|
||||
.before()
|
||||
.beforeOptional(Semicolon)
|
||||
.beforeOptional(Whitespace)
|
||||
.isAt(BlockClosingBrace))) {
|
||||
return createIndentData(getBlockIndentType(project, language), BlockClosingBrace);
|
||||
return myFactory.createIndentCalculator(getBlockIndentType(project, language), IndentCalculator.LINE_BEFORE);
|
||||
}
|
||||
else if (getPosition(editor, offset).matchesRule(
|
||||
position -> position.before().isAt(ArrayOpeningBracket)
|
||||
position -> position.before().isAt(ArrayOpeningBracket) || position.isAt(LeftParenthesis)
|
||||
)) {
|
||||
return createIndentData(CONTINUATION, ArrayOpeningBracket);
|
||||
}
|
||||
else if (getPosition(editor, offset).matchesRule(
|
||||
position -> position.before().isAt(LeftParenthesis)
|
||||
)) {
|
||||
return createIndentData(CONTINUATION, LeftParenthesis);
|
||||
return myFactory.createIndentCalculator(CONTINUATION, IndentCalculator.LINE_BEFORE);
|
||||
}
|
||||
else if (getPosition(editor, offset).matchesRule(
|
||||
position -> position.before().isAt(BlockOpeningBrace)
|
||||
)) {
|
||||
return createIndentData(getIndentTypeInBlock(project, language), BlockOpeningBrace);
|
||||
return myFactory.createIndentCalculator(getIndentTypeInBlock(project, language), position -> {
|
||||
position.before().beforeOptional(Whitespace);
|
||||
return getOffsetBeforeOptionalParentheses(position);
|
||||
});
|
||||
}
|
||||
else if (getPosition(editor, offset).matchesRule(
|
||||
position -> position.before().isAt(Colon) && position.isAfterOnSameLine(SwitchCase, SwitchDefault)
|
||||
)) {
|
||||
return createIndentData(NORMAL, SwitchCase);
|
||||
}
|
||||
else if (getPosition(editor, offset).matchesRule(
|
||||
) || getPosition(editor, offset).matchesRule(
|
||||
position -> position.before().isAt(ElseKeyword)
|
||||
)) {
|
||||
return createIndentData(NORMAL, ElseKeyword);
|
||||
return myFactory.createIndentCalculator(NORMAL, IndentCalculator.LINE_BEFORE);
|
||||
}
|
||||
else if (getPosition(editor, offset).matchesRule(
|
||||
position -> position.before().isAt(BlockComment)
|
||||
)) {
|
||||
return createIndentData(NONE, BlockComment);
|
||||
return myFactory.createIndentCalculator(NONE, position -> position.findStartOf(BlockComment));
|
||||
}
|
||||
else if (getPosition(editor, offset).matchesRule(
|
||||
position -> position.before().isAt(DocBlockEnd)
|
||||
)) {
|
||||
return createIndentData(NONE, DocBlockEnd);
|
||||
return myFactory.createIndentCalculator(NONE, position -> position.findStartOf(DocBlockStart));
|
||||
}
|
||||
else {
|
||||
SemanticEditorPosition position = getPosition(editor, offset);
|
||||
@@ -132,8 +124,9 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
|
||||
if (position.isAt(IfKeyword) || position.isAt(ForKeyword)) {
|
||||
SyntaxElement element = position.getCurrElement();
|
||||
assert element != null;
|
||||
final int controlKeywordOffset = position.getStartOffset();
|
||||
Type indentType = getPosition(editor, offsetAfterParen).afterOptional(Whitespace).isAt(BlockOpeningBrace) ? NONE : NORMAL;
|
||||
return createIndentData(indentType, element);
|
||||
return myFactory.createIndentCalculator(indentType, baseLineOffset -> controlKeywordOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,6 +135,22 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static int getOffsetBeforeOptionalParentheses(@NotNull SemanticEditorPosition position) {
|
||||
position.beforeOptional(Whitespace);
|
||||
if (position.isAt(RightParenthesis)) {
|
||||
position.beforeParentheses(LeftParenthesis, RightParenthesis);
|
||||
}
|
||||
while (!position.isAtEnd()) {
|
||||
if (position.isAt(Whitespace) && position.isAtMultiline()) {
|
||||
return position.after().getStartOffset();
|
||||
}
|
||||
position.before();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
protected SemanticEditorPosition getPosition(@NotNull Editor editor, int offset) {
|
||||
return new SemanticEditorPosition((EditorEx)editor, offset) {
|
||||
@@ -154,90 +163,7 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
|
||||
|
||||
@Nullable
|
||||
protected abstract SyntaxElement mapType(@NotNull IElementType tokenType);
|
||||
|
||||
@Nullable
|
||||
private String getIndentString(@NotNull Project project,
|
||||
@NotNull Editor editor,
|
||||
int offset,
|
||||
@NotNull Pair<Type, SyntaxElement> indentData) {
|
||||
Document document = editor.getDocument();
|
||||
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
|
||||
baseIndent + new IndentInfo(0, indentTypeToSize(indentData.first, options), 0, false).generateNewWhiteSpace(options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int indentTypeToSize(@NotNull Type indentType, @NotNull CommonCodeStyleSettings.IndentOptions options) {
|
||||
if (indentType == NORMAL) {
|
||||
return options.INDENT_SIZE;
|
||||
}
|
||||
else if (indentType == CONTINUATION) {
|
||||
return options.CONTINUATION_INDENT_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getBaseIndent(@NotNull Editor editor, @NotNull SyntaxElement afterElement, int offset) {
|
||||
CharSequence docChars = editor.getDocument().getCharsSequence();
|
||||
if (offset > 0) {
|
||||
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) {
|
||||
return docChars.subSequence(indentStart, indentEnd).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
private int getOffsetInBaseIndentLine(@NotNull Editor editor,
|
||||
@NotNull CharSequence docChars,
|
||||
@NotNull SyntaxElement afterElement,
|
||||
int offset) {
|
||||
if (BlockOpeningBrace.equals(afterElement) && !isOnSeparateLine(editor, afterElement, offset)) {
|
||||
return findStatementStart(editor, afterElement, offset);
|
||||
}
|
||||
else if (IfKeyword.equals(afterElement) || ForKeyword.equals(afterElement)) {
|
||||
return findStatementStart(editor, null, offset);
|
||||
}
|
||||
else if (BlockComment.equals(afterElement)) {
|
||||
return findStartOfBlockComment(editor, offset);
|
||||
}
|
||||
else if (DocBlockEnd.equals(afterElement)) {
|
||||
return findStartOfDocComment(editor, offset);
|
||||
}
|
||||
return CharArrayUtil.shiftBackward(docChars, offset, " \t\n\r");
|
||||
}
|
||||
|
||||
private int findStartOfDocComment(Editor editor, int offset) {
|
||||
SemanticEditorPosition position = getPosition(editor, offset);
|
||||
while (!position.isAtEnd()) {
|
||||
if (position.isAt(DocBlockStart)) return position.getStartOffset();
|
||||
position.before();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private int findStartOfBlockComment(@NotNull Editor editor, int offset) {
|
||||
SemanticEditorPosition position = getPosition(editor, offset);
|
||||
while (!position.isAtEnd()) {
|
||||
if (position.isAt(BlockComment)) return position.getStartOffset();
|
||||
position.before();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private boolean isOnSeparateLine(@NotNull Editor editor, @NotNull SyntaxElement element, int offset) {
|
||||
SemanticEditorPosition position = getPosition(editor, offset);
|
||||
@@ -250,24 +176,6 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
|
||||
}
|
||||
|
||||
|
||||
private int findStatementStart(@NotNull Editor editor, @Nullable SyntaxElement afterElement, int offset) {
|
||||
SemanticEditorPosition position = getPosition(editor, offset);
|
||||
position.beforeOptional(Whitespace);
|
||||
if (afterElement != null) {
|
||||
position.beforeOptional(afterElement).beforeOptional(Whitespace);
|
||||
}
|
||||
if (position.isAt(RightParenthesis)) {
|
||||
position.beforeParentheses(LeftParenthesis, RightParenthesis);
|
||||
}
|
||||
while (!position.isAtEnd()) {
|
||||
if (position.isAt(Whitespace) && position.isAtMultiline()) {
|
||||
return position.after().getStartOffset();
|
||||
}
|
||||
position.before();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Type getIndentTypeInBlock(@NotNull Project project, @Nullable Language language) {
|
||||
if (language != null) {
|
||||
@@ -290,9 +198,24 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static Pair<Type,SyntaxElement> createIndentData(@Nullable Type type, @NotNull SyntaxElement element) {
|
||||
return type != null ? Pair.create(type, element) : null;
|
||||
|
||||
|
||||
public static class IndentCalculatorFactory {
|
||||
private Project myProject;
|
||||
private Editor myEditor;
|
||||
|
||||
public IndentCalculatorFactory(Project project, Editor editor) {
|
||||
myProject = project;
|
||||
myEditor = editor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IndentCalculator createIndentCalculator(@Nullable Type indentType, @Nullable BaseLineOffsetCalculator baseLineOffsetCalculator) {
|
||||
return indentType != null ?
|
||||
new IndentCalculator(myProject, myEditor,
|
||||
baseLineOffsetCalculator != null ? baseLineOffsetCalculator : IndentCalculator.LINE_BEFORE, indentType)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user