/* * 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.lang.Language; 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.CodeStyleSettings; 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; public 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"); } }; public final static BaseLineOffsetCalculator LINE_AFTER = new BaseLineOffsetCalculator() { @Override public int getOffsetInBaseIndentLine(@NotNull SemanticEditorPosition currPosition) { return CharArrayUtil.shiftForward(currPosition.getChars(), currPosition.getStartOffset(), " \t\n\r"); } }; @Nullable String getIndentString(@Nullable Language language, @NotNull SemanticEditorPosition currPosition) { String baseIndent = getBaseIndent(currPosition); Document document = myEditor.getDocument(); PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document); if (file != null) { CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(myProject); CommonCodeStyleSettings.IndentOptions fileOptions = codeStyleSettings.getIndentOptionsByFile(file); CommonCodeStyleSettings.IndentOptions options = !fileOptions.isOverrideLanguageOptions() && language != null && !(language.is(file.getLanguage()) || language.is(Language.ANY)) ? codeStyleSettings.getCommonSettings(language).getIndentOptions() : fileOptions; 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); } }