diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java new file mode 100644 index 000000000000..8f379598a3bb --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java @@ -0,0 +1,90 @@ +/* + * 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.codeStyle.autodetect; + +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import org.jetbrains.annotations.NotNull; + +class IndentOptionsAdjuster { + private static final double RATE_THRESHOLD = 0.8; + private static final int MAX_INDENT_TO_DETECT = 8; + + private final boolean isTabsUsed; + private final boolean isSpacesUsed; + private final int newIndentSize; + + public IndentOptionsAdjuster(IndentUsageStatistics stats) { + isTabsUsed = isTabsUsed(stats); + isSpacesUsed = isSpacesUsed(stats); + newIndentSize = isSpacesUsed ? getPositiveIndentSize(stats) : 0; + } + + public void adjust(@NotNull CommonCodeStyleSettings.IndentOptions indentOptions) { + if (isTabsUsed) { + adjustForTabUsage(indentOptions); + } + else if (isSpacesUsed) { + indentOptions.USE_TAB_CHARACTER = false; + if (newIndentSize > 0 && indentOptions.INDENT_SIZE != newIndentSize) { + indentOptions.INDENT_SIZE = newIndentSize; + } + } + } + + private static void adjustForTabUsage(@NotNull CommonCodeStyleSettings.IndentOptions indentOptions) { + if (indentOptions.USE_TAB_CHARACTER) return; + + int continuationRatio = indentOptions.INDENT_SIZE == 0 ? 1 : indentOptions.CONTINUATION_INDENT_SIZE / indentOptions.INDENT_SIZE; + + indentOptions.USE_TAB_CHARACTER = true; + indentOptions.INDENT_SIZE = indentOptions.TAB_SIZE; + indentOptions.CONTINUATION_INDENT_SIZE = indentOptions.TAB_SIZE * continuationRatio; + } + + private static boolean isSpacesUsed(IndentUsageStatistics stats) { + int spaces = stats.getTotalLinesWithLeadingSpaces(); + int total = stats.getTotalLinesWithLeadingSpaces() + stats.getTotalLinesWithLeadingTabs(); + return (double)spaces / total > RATE_THRESHOLD; + } + + private static boolean isTabsUsed(IndentUsageStatistics stats) { + return stats.getTotalLinesWithLeadingTabs() > stats.getTotalLinesWithLeadingSpaces(); + } + + private static int getPositiveIndentSize(@NotNull IndentUsageStatistics stats) { + int totalIndentSizesDetected = stats.getTotalIndentSizesDetected(); + if (totalIndentSizesDetected == 0) return -1; + + IndentUsageInfo maxUsedIndentInfo = stats.getKMostUsedIndentInfo(0); + int maxUsedIndentSize = maxUsedIndentInfo.getIndentSize(); + + if (maxUsedIndentSize == 0) { + if (totalIndentSizesDetected < 2) return -1; + + maxUsedIndentInfo = stats.getKMostUsedIndentInfo(1); + maxUsedIndentSize = maxUsedIndentInfo.getIndentSize(); + } + + if (maxUsedIndentSize <= MAX_INDENT_TO_DETECT) { + double usageRate = (double)maxUsedIndentInfo.getTimesUsed() / stats.getTotalLinesWithLeadingSpaces(); + if (usageRate > RATE_THRESHOLD) { + return maxUsedIndentSize; + } + } + + return -1; + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java index 03dac579d26e..a3248fe22e93 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetectorImpl.java @@ -19,7 +19,6 @@ import com.intellij.formatting.Block; import com.intellij.formatting.FormattingModel; import com.intellij.formatting.FormattingModelBuilder; import com.intellij.lang.LanguageFormatting; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtilRt; @@ -36,11 +35,6 @@ import java.util.List; import static com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions; public class IndentOptionsDetectorImpl implements IndentOptionsDetector { - private static Logger LOG = Logger.getInstance("#com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptionsDetector"); - - private static final double RATE_THRESHOLD = 0.8; - private static final int MAX_INDENT_TO_DETECT = 8; - private final PsiFile myFile; private final Project myProject; private final Document myDocument; @@ -54,12 +48,14 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { @Override @NotNull public IndentOptions getIndentOptions() { - IndentOptions indentOptions = (IndentOptions)CodeStyleSettingsManager.getSettings(myProject).getIndentOptions(myFile.getFileType()).clone(); + IndentOptions indentOptions = + (IndentOptions)CodeStyleSettingsManager.getSettings(myProject).getIndentOptions(myFile.getFileType()).clone(); List linesInfo = calcLineIndentInfo(); if (linesInfo != null) { IndentUsageStatistics stats = new IndentUsageStatisticsImpl(linesInfo); - adjustIndentOptions(indentOptions, stats); + IndentOptionsAdjuster adjuster = new IndentOptionsAdjuster(stats); + adjuster.adjust(indentOptions); } return indentOptions; @@ -70,11 +66,11 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { if (myDocument == null || myDocument.getLineCount() < 3 || isFileBigToDetect()) { return null; } - + CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myProject); FormattingModelBuilder modelBuilder = LanguageFormatting.INSTANCE.forContext(myFile); if (modelBuilder == null) return null; - + FormattingModel model = modelBuilder.createModel(myFile, settings); Block rootBlock = model.getRootBlock(); return new FormatterBasedLineIndentInfoBuilder(myDocument, rootBlock).build(); @@ -83,72 +79,9 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { private boolean isFileBigToDetect() { VirtualFile file = myFile.getVirtualFile(); if (file != null && file.getLength() > FileUtilRt.MEGABYTE) { - LOG.debug("Indent detector disabled for this file"); return true; } return false; } - - private void adjustIndentOptions(@NotNull IndentOptions indentOptions, @NotNull IndentUsageStatistics stats) { - if (isTabsUsed(stats)) { - adjustForTabUsage(indentOptions); - } - else if (isSpacesUsed(stats)) { - indentOptions.USE_TAB_CHARACTER = false; - - int newIndentSize = getPositiveIndentSize(stats); - if (newIndentSize > 0) { - if (indentOptions.INDENT_SIZE != newIndentSize) { - indentOptions.INDENT_SIZE = newIndentSize; - LOG.debug("Detected indent size: " + newIndentSize + " for file " + myFile); - } - } - } - } - - private static boolean isSpacesUsed(IndentUsageStatistics stats) { - int spaces = stats.getTotalLinesWithLeadingSpaces(); - int total = stats.getTotalLinesWithLeadingSpaces() + stats.getTotalLinesWithLeadingTabs(); - return (double)spaces / total > RATE_THRESHOLD; - } - - private static boolean isTabsUsed(IndentUsageStatistics stats) { - return stats.getTotalLinesWithLeadingTabs() > stats.getTotalLinesWithLeadingSpaces(); - } - - private void adjustForTabUsage(@NotNull IndentOptions indentOptions) { - if (indentOptions.USE_TAB_CHARACTER) return; - - int continuationRatio = indentOptions.INDENT_SIZE == 0 ? 1 : indentOptions.CONTINUATION_INDENT_SIZE / indentOptions.INDENT_SIZE; - - indentOptions.USE_TAB_CHARACTER = true; - indentOptions.INDENT_SIZE = indentOptions.TAB_SIZE; - indentOptions.CONTINUATION_INDENT_SIZE = indentOptions.TAB_SIZE * continuationRatio; - - LOG.debug("Using tabs for: " + myFile); - } - - private static int getPositiveIndentSize(@NotNull IndentUsageStatistics stats) { - int totalIndentSizesDetected = stats.getTotalIndentSizesDetected(); - if (totalIndentSizesDetected == 0) return -1; - - IndentUsageInfo maxUsedIndentInfo = stats.getKMostUsedIndentInfo(0); - int maxUsedIndentSize = maxUsedIndentInfo.getIndentSize(); - - if (maxUsedIndentSize == 0) { - if (totalIndentSizesDetected < 2) return -1; - - maxUsedIndentInfo = stats.getKMostUsedIndentInfo(1); - maxUsedIndentSize = maxUsedIndentInfo.getIndentSize(); - } - - if (maxUsedIndentSize <= MAX_INDENT_TO_DETECT) { - double usageRate = (double)maxUsedIndentInfo.getTimesUsed() / stats.getTotalLinesWithLeadingSpaces(); - if (usageRate > RATE_THRESHOLD) { - return maxUsedIndentSize; - } - } - - return -1; - } } +