blob: 15136fca43810d941f35141c088ce9bcd6eb11ee [file] [log] [blame]
/*
* Copyright 2000-2013 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.jetbrains.python.console;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* @author traff
*/
public class PyConsoleIndentUtil {
private static final int TAB_INDENT = 4;
private static final Map<String, String> pythonBrackets = ImmutableMap.of(
"(", ")",
"[", "]",
"{", "}"
);
private PyConsoleIndentUtil() {
}
public static String normalize(@NotNull String codeFragment) {
return normalize(codeFragment, 0);
}
public static String normalize(@NotNull String codeFragment, int addIndent) {
Scanner s = new Scanner(codeFragment);
List<String> lines = Lists.newArrayList();
List<Integer> indents = Lists.newArrayList();
while (s.hasNextLine()) {
String line = s.nextLine();
int indent = 0;
for (char c : line.toCharArray()) {
if (c == ' ') {
indent++;
}
else if (c == '\t') {
indent += TAB_INDENT;
}
else {
break;
}
}
if (!StringUtil.isEmpty(line)) {
lines.add(line.trim());
indents.add(indent);
}
}
int[] indentArray = ArrayUtil.toIntArray(indents);
shiftLeftAll(indentArray, lines);
for (int i = 0; i < indentArray.length; i++) {
indentArray[i] += addIndent;
}
return padOutput(lines, indentArray);
}
private static void shiftLeftAll(int[] indentArray, List<String> lines) {
if (indentArray.length == 0) {
return;
}
int minpos = arrayMinPosition(indentArray, indentArray.length);
if (minpos == 0) {
int minIndent = indentArray[minpos];
shiftTailLeftOnLevel(indentArray, minIndent);
return;
}
int prevMinPosition = indentArray.length;
while (minpos != 0) {
shiftTailLeftOnLevel(indentArray, minpos, prevMinPosition, indentArray[minpos]);
prevMinPosition = minpos;
minpos = arrayMinPosition(indentArray, minpos);
}
int minIndent = indentArray[minpos];
for (int i = 0; indentArray[i] != 0; i++) {
indentArray[i] -= minIndent;
}
}
private static void shiftTailLeftOnLevel(int[] indentArray, int level) {
shiftTailLeftOnLevel(indentArray, 0, indentArray.length, level);
}
private static void shiftTailLeftOnLevel(int[] indentArray, int upper, int bottom, int level) {
for (int i = upper; i < bottom; i++) {
if (indentArray[i] < level) {
throw new IllegalStateException("Current indentation is less then subtracted level.");
}
indentArray[i] -= level;
}
}
private static int arrayMinPosition(int[] indentArray, int border) {
if (border < 1) {
return -1;
}
int minPosition = 0;
for (int i = 0; i < border; i++) {
if (indentArray[minPosition] > indentArray[i]) {
minPosition = i;
}
}
return minPosition;
}
private static String padOutput(List<String> lines, int[] indentArray) {
int i = 0;
StringBuilder result = new StringBuilder();
for (String line : lines) {
if (!StringUtil.isEmpty(line)) {
line = Strings.padStart(line, indentArray[i] + line.length(), ' ');
}
i++;
result.append(line);
if (i < lines.size()) {
result.append("\n");
}
}
return result.toString();
}
public static boolean shouldIndent(@NotNull String line) {
line = stripComments(line);
return line.endsWith(":");
}
private static String stripComments(String line) {
if (line.contains("#")) {
line = line.substring(0, line.indexOf("#")); //strip comments
line = line.trim();
}
return line;
}
}