| /* |
| * Copyright 2000-2012 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; |
| |
| import com.intellij.lang.ASTNode; |
| import com.intellij.openapi.fileTypes.FileType; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.psi.codeStyle.CodeStyleSettings; |
| import com.intellij.psi.codeStyle.CodeStyleSettingsManager; |
| import com.intellij.psi.impl.source.tree.CompositeElement; |
| import com.intellij.psi.impl.source.tree.TreeUtil; |
| |
| public class IndentHelperImpl extends IndentHelper { |
| //---------------------------------------------------------------------------------------------------- |
| |
| public static final int INDENT_FACTOR = 10000; // "indent" is indent_level * INDENT_FACTOR + spaces |
| |
| @Override |
| public int getIndent(Project project, FileType fileType, ASTNode element) { |
| return getIndent(project, fileType, element, false); |
| } |
| |
| @Override |
| public int getIndent(Project project, FileType fileType, final ASTNode element, boolean includeNonSpace) { |
| return getIndentInner(project, fileType, element, includeNonSpace, 0); |
| } |
| |
| public static final int TOO_BIG_WALK_THRESHOLD = 450; |
| |
| protected int getIndentInner(Project project, FileType fileType, final ASTNode element, boolean includeNonSpace, int recursionLevel) { |
| if (recursionLevel > TOO_BIG_WALK_THRESHOLD) return 0; |
| |
| if (element.getTreePrev() != null) { |
| ASTNode prev = element.getTreePrev(); |
| ASTNode lastCompositePrev; |
| while (prev instanceof CompositeElement && !TreeUtil.isStrongWhitespaceHolder(prev.getElementType())) { |
| lastCompositePrev = prev; |
| prev = prev.getLastChildNode(); |
| if (prev == null) { // element.prev is "empty composite" |
| return getIndentInner(project, fileType, lastCompositePrev, includeNonSpace, recursionLevel + 1); |
| } |
| } |
| |
| String text = prev.getText(); |
| int index = Math.max(text.lastIndexOf('\n'), text.lastIndexOf('\r')); |
| |
| if (index >= 0) { |
| return getIndent(project, fileType, text.substring(index + 1), includeNonSpace); |
| } |
| |
| if (includeNonSpace) { |
| return getIndentInner(project, fileType, prev, includeNonSpace, recursionLevel + 1) + getIndent(project, fileType, text, includeNonSpace); |
| } |
| |
| |
| ASTNode parent = prev.getTreeParent(); |
| ASTNode child = prev; |
| while (parent != null) { |
| if (child.getTreePrev() != null) break; |
| child = parent; |
| parent = parent.getTreeParent(); |
| } |
| |
| if (parent == null) { |
| return getIndent(project, fileType, text, includeNonSpace); |
| } |
| else { |
| return getIndentInner(project, fileType, prev, includeNonSpace, recursionLevel + 1); |
| } |
| } |
| else { |
| if (element.getTreeParent() == null) { |
| return 0; |
| } |
| return getIndentInner(project, fileType, element.getTreeParent(), includeNonSpace, recursionLevel + 1); |
| } |
| } |
| |
| public static String fillIndent(Project project, FileType fileType, int indent) { |
| final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); |
| int indentLevel = (indent + INDENT_FACTOR / 2) / INDENT_FACTOR; |
| int spaceCount = indent - indentLevel * INDENT_FACTOR; |
| int indentLevelSize = indentLevel * settings.getIndentSize(fileType); |
| int totalSize = indentLevelSize + spaceCount; |
| |
| StringBuilder buffer = new StringBuilder(); |
| if (settings.useTabCharacter(fileType)) { |
| if (settings.isSmartTabs(fileType)) { |
| int tabCount = indentLevelSize / settings.getTabSize(fileType); |
| int leftSpaces = indentLevelSize - tabCount * settings.getTabSize(fileType); |
| for (int i = 0; i < tabCount; i++) { |
| buffer.append('\t'); |
| } |
| for (int i = 0; i < leftSpaces + spaceCount; i++) { |
| buffer.append(' '); |
| } |
| } |
| else { |
| int size = totalSize; |
| while (size > 0) { |
| if (size >= settings.getTabSize(fileType)) { |
| buffer.append('\t'); |
| size -= settings.getTabSize(fileType); |
| } |
| else { |
| buffer.append(' '); |
| size--; |
| } |
| } |
| } |
| } |
| else { |
| for (int i = 0; i < totalSize; i++) { |
| buffer.append(' '); |
| } |
| } |
| |
| return buffer.toString(); |
| } |
| |
| public static int getIndent(Project project, FileType fileType, String text, boolean includeNonSpace) { |
| final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); |
| int i; |
| for (i = text.length() - 1; i >= 0; i--) { |
| char c = text.charAt(i); |
| if (c == '\n' || c == '\r') break; |
| } |
| i++; |
| |
| int spaceCount = 0; |
| int tabCount = 0; |
| for (int j = i; j < text.length(); j++) { |
| char c = text.charAt(j); |
| if (c != '\t') { |
| if (!includeNonSpace && c != ' ') break; |
| spaceCount++; |
| } |
| else { |
| tabCount++; |
| } |
| } |
| |
| if (tabCount == 0) return spaceCount; |
| |
| int tabSize = settings.getTabSize(fileType); |
| int indentSize = settings.getIndentSize(fileType); |
| if (indentSize <= 0) { |
| indentSize = 1; |
| } |
| int indentLevel = tabCount * tabSize / indentSize; |
| return indentLevel * INDENT_FACTOR + spaceCount; |
| } |
| } |