/* * 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; } }