diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java index 495155145a5e..31358cdc045f 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/TabPostFormatProcessor.java @@ -72,7 +72,7 @@ public class TabPostFormatProcessor implements PostFormatProcessor { if (!source.isValid()) return range; PsiFile file = source.getContainingFile(); - CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptionsByFile(file); + CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptionsByFile(file, range); boolean useTabs = indentOptions.USE_TAB_CHARACTER; boolean smartTabs = indentOptions.SMART_TABS; diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_after.java new file mode 100644 index 000000000000..2c4a5a27aa56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_after.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_before.java b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_before.java new file mode 100644 index 000000000000..288ed2b2cc3e --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatFileSupported_before.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java index 2c4a5a27aa56..4dca5f373a24 100644 --- a/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatFile_after.java @@ -1,8 +1,8 @@ class A { - private void foo(boolean b) { - int x; - if (b) { - System.out.println(x); - } - } + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } } diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_after.java new file mode 100644 index 000000000000..2c4a5a27aa56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_after.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_before.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_before.java new file mode 100644 index 000000000000..288ed2b2cc3e --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextFullSupported_before.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_after.java new file mode 100644 index 000000000000..2c4a5a27aa56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_after.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_before.java b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_before.java new file mode 100644 index 000000000000..288ed2b2cc3e --- /dev/null +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatTextRange_before.java @@ -0,0 +1,8 @@ +class A { + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } +} diff --git a/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java b/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java index 2c4a5a27aa56..4dca5f373a24 100644 --- a/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java +++ b/java/java-tests/testData/codeInsight/indentProvider/reformatText_after.java @@ -1,8 +1,8 @@ class A { - private void foo(boolean b) { - int x; - if (b) { - System.out.println(x); - } - } + private void foo(boolean b) { + int x; + if (b) { + System.out.println(x); + } + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java index c542f1a5a4e0..9ba42b9aaaa8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/indentOptionsProvider/FileIndentProviderTest.java @@ -38,6 +38,7 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC private final static FileIndentOptionsProvider TEST_FILE_INDENT_OPTIONS_PROVIDER = new TestIndentOptionsProvider(); private static CommonCodeStyleSettings.IndentOptions myTestIndentOptions; + private static boolean myUseOnFullReformat; @Override protected void setUp() throws Exception { @@ -54,6 +55,7 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC Extensions.getRootArea().getExtensionPoint(FileIndentOptionsProvider.EP_NAME); extensionPoint.unregisterExtension(TEST_FILE_INDENT_OPTIONS_PROVIDER); myTestIndentOptions = null; + myUseOnFullReformat = false; super.tearDown(); } @@ -80,6 +82,11 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC public CommonCodeStyleSettings.IndentOptions getIndentOptions(@NotNull PsiFile file) { return myTestIndentOptions; } + + @Override + public boolean useOnFullReformat() { + return myUseOnFullReformat; + } } public void testTypeEnter() { @@ -111,6 +118,16 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC myFixture.checkResultByFile(getTestName(true) + "_after.java"); } + public void testReformatFileSupported() { + myUseOnFullReformat = true; + myTestIndentOptions.INDENT_SIZE = 3; + myTestIndentOptions.TAB_SIZE = 2; + myTestIndentOptions.USE_TAB_CHARACTER = true; + PsiFile file = myFixture.configureByFile(getTestName(true) + "_before.java"); + CodeStyleManager.getInstance(getProject()).reformat(file); + myFixture.checkResultByFile(getTestName(true) + "_after.java"); + } + public void testReformatText() { myTestIndentOptions.INDENT_SIZE = 3; myTestIndentOptions.TAB_SIZE = 2; @@ -119,4 +136,27 @@ public class FileIndentProviderTest extends LightPlatformCodeInsightFixtureTestC CodeStyleManager.getInstance(getProject()).reformatText(file, 0, file.getTextRange().getEndOffset()); myFixture.checkResultByFile(getTestName(true) + "_after.java"); } + + /** + * Reformat using indent provider if a part of the file is selected. + */ + public void testReformatTextRange() { + myTestIndentOptions.INDENT_SIZE = 3; + myTestIndentOptions.TAB_SIZE = 2; + myTestIndentOptions.USE_TAB_CHARACTER = true; + PsiFile file = myFixture.configureByFile(getTestName(true) + "_before.java"); + // Just any range smaller than the file + CodeStyleManager.getInstance(getProject()).reformatText(file, 6, file.getTextRange().getEndOffset() - 1); + myFixture.checkResultByFile(getTestName(true) + "_after.java"); + } + + public void testReformatTextFullSupported() { + myUseOnFullReformat = true; + myTestIndentOptions.INDENT_SIZE = 3; + myTestIndentOptions.TAB_SIZE = 2; + myTestIndentOptions.USE_TAB_CHARACTER = true; + PsiFile file = myFixture.configureByFile(getTestName(true) + "_before.java"); + CodeStyleManager.getInstance(getProject()).reformatText(file, 0, file.getTextRange().getEndOffset()); + myFixture.checkResultByFile(getTestName(true) + "_after.java"); + } } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java index ae9f2f960640..eecdc4b6e937 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettings.java @@ -663,26 +663,65 @@ public class CodeStyleSettings extends CommonCodeStyleSettings implements Clonea @NotNull public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file) { - return getIndentOptionsByFile(file, false); + return getIndentOptionsByFile(file, null); } @NotNull - public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file, boolean ignoreDocOptions) { + public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file, @Nullable TextRange formatRange) { + return getIndentOptionsByFile(file, formatRange, false); + } + + /** + * Retrieves indent options for PSI file from an associated document or (if not defined in the document) from file indent options + * providers. + * @param file The PSI file to retrieve options for. + * @param formatRange The text range within the file for formatting purposes or null if there is either no specific range or multiple + * ranges. If the range covers the entire file (full reformat), options stored in the document are ignored and + * indent options are taken from file indent options providers. + * @param ignoreDocOptions Ignore options stored in the document and use file indent options providers even if there is no text range + * or the text range doesn't cover the entire file. + * @return Indent options from the associated document or file indent options providers. + * @see com.intellij.psi.codeStyle.FileIndentOptionsProvider + */ + @NotNull + public IndentOptions getIndentOptionsByFile(@Nullable PsiFile file, @Nullable TextRange formatRange, boolean ignoreDocOptions) { if (file != null && file.isValid()) { - if (!ignoreDocOptions) { + boolean isFullReformat = isFileFullyCoveredByRange(file, formatRange); + if (!ignoreDocOptions && !isFullReformat) { IndentOptions docOptions = IndentOptions.retrieveFromAssociatedDocument(file); if (docOptions != null) return docOptions; } FileIndentOptionsProvider[] providers = Extensions.getExtensions(FileIndentOptionsProvider.EP_NAME); for (FileIndentOptionsProvider provider : providers) { - IndentOptions indentOptions = provider.getIndentOptions(file); - if (indentOptions != null) return indentOptions; + if (!isFullReformat || provider.useOnFullReformat()) { + IndentOptions indentOptions = provider.getIndentOptions(file); + if (indentOptions != null) { + logIndentOptions(file, provider, indentOptions); + return indentOptions; + } + } } return getIndentOptions(file.getFileType()); } else return OTHER_INDENT_OPTIONS; } + + private static boolean isFileFullyCoveredByRange(@NotNull PsiFile file, @Nullable TextRange formatRange) { + return + formatRange != null && + file.getTextRange().equals(formatRange); + } + + private static void logIndentOptions(@NotNull PsiFile file, + @NotNull FileIndentOptionsProvider provider, + @NotNull IndentOptions options) { + LOG.info("Indent options returned by " + provider.getClass().getName() + + " for " + file.getName() + + ": indent size=" + options.INDENT_SIZE + + ", use tabs=" + options.USE_TAB_CHARACTER + + ", tab size=" + options.TAB_SIZE); + } @Nullable private IndentOptions getLanguageIndentOptions(@Nullable FileType fileType) { diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java index 9dd266a0b3aa..08b742beea04 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsManager.java @@ -139,7 +139,7 @@ public class CodeStyleSettingsManager implements PersistentStateComponent 0) { try { FormatterEx.getInstanceEx().format( - model, mySettings,mySettings.getIndentOptionsByFile(fileToFormat), new FormatTextRanges(range, true) + model, mySettings,mySettings.getIndentOptionsByFile(fileToFormat, range), new FormatTextRanges(range, true) ); wrapLongLinesIfNecessary(file, document, startOffset, endOffset); @@ -242,7 +242,7 @@ public class CodeFormatterFacade { indentOptions = ((FormattingModelBuilderEx)builder).getIndentOptionsToUse(file, ranges, mySettings); } if (indentOptions == null) { - indentOptions = mySettings.getIndentOptionsByFile(file); + indentOptions = mySettings.getIndentOptionsByFile(file, textRanges.size() == 1 ? textRanges.get(0).getTextRange() : null); } formatter.format(model, mySettings, indentOptions, ranges);