From 98452b0387c338b87753ed0a7b6cbabf0e530499 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Wed, 4 May 2016 19:24:49 +0300 Subject: [PATCH] Move indent detection into background --- .../JavaDetectableIndentsTest.java | 2 +- .../AbstractNewLineBlocksIteratorTest.java | 6 +- .../autodetect/DetectIndentAndTypeTest.java | 1 + .../DetectedIndentNotificationTest.java | 1 + .../FormatterBasedLineInfoBuilderTest.java | 2 +- .../autodetect/JavaAutoDetectIndentTest.java | 2 +- .../java/AbstractJavaFormatterTest.java | 1 - .../autodetect/IndentOptionsAdjuster.java | 23 +++++ .../autodetect/IndentOptionsDetector.java | 7 +- .../DetectAndAdjustIndentOptionsTask.java | 92 +++++++++++++++++++ .../DetectableIndentOptionsProvider.java | 64 ++++++++++--- .../FormatterBasedLineIndentInfoBuilder.java | 15 ++- ...er.java => IndentOptionsAdjusterImpl.java} | 5 +- .../autodetect/IndentOptionsDetectorImpl.java | 24 +++-- .../psi/formatter/common/AbstractBlock.java | 7 ++ .../common/NewLineBlocksIterator.java | 17 +++- .../src/META-INF/LangExtensions.xml | 2 +- .../AbstractIndentAutoDetectionTest.java | 4 +- 18 files changed, 236 insertions(+), 39 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java create mode 100644 platform/lang-impl/src/com/intellij/psi/codeStyle/DetectAndAdjustIndentOptionsTask.java rename platform/lang-impl/src/com/intellij/psi/codeStyle/{autodetect => }/DetectableIndentOptionsProvider.java (74%) rename platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/{IndentOptionsAdjuster.java => IndentOptionsAdjusterImpl.java} (95%) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/JavaDetectableIndentsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/JavaDetectableIndentsTest.java index dffe7e3b462c..5df9e1598cf1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/JavaDetectableIndentsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/editorActions/JavaDetectableIndentsTest.java @@ -15,7 +15,7 @@ */ package com.intellij.codeInsight.editorActions; -import com.intellij.psi.codeStyle.autodetect.DetectableIndentOptionsProvider; +import com.intellij.psi.codeStyle.DetectableIndentOptionsProvider; import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.LightCodeInsightTestCase; diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java index 71fa8c72a04d..72e947d81af5 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/AbstractNewLineBlocksIteratorTest.java @@ -15,7 +15,9 @@ */ package com.intellij.psi.codeStyle.autodetect; -import com.intellij.formatting.*; +import com.intellij.formatting.Block; +import com.intellij.formatting.FormattingModel; +import com.intellij.formatting.FormattingModelBuilder; import com.intellij.lang.LanguageFormatting; import com.intellij.openapi.editor.Document; import com.intellij.psi.PsiDocumentManager; @@ -61,7 +63,7 @@ public abstract class AbstractNewLineBlocksIteratorTest extends LightPlatformCod Document document = PsiDocumentManager.getInstance(getProject()).getDocument(myFile); Assert.assertNotNull(document); - return new NewLineBlocksIterator(root, document); + return new NewLineBlocksIterator(root, document, null); } } diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java index cf85f1cd0fef..884a321e34ad 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.codeStyle.DetectableIndentOptionsProvider; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectedIndentNotificationTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectedIndentNotificationTest.java index 3830a7af82f1..5f946f59d8d4 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectedIndentNotificationTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/DetectedIndentNotificationTest.java @@ -19,6 +19,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.DetectableIndentOptionsProvider; import com.intellij.psi.codeStyle.FileIndentOptionsProvider; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java index 9e3a35d9291c..9bdd7590bb79 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineInfoBuilderTest.java @@ -65,7 +65,7 @@ public class FormatterBasedLineInfoBuilderTest extends LightPlatformCodeInsightT TestFormattingModel model = new TestFormattingModel(text); Document document = model.getDocument(); TestBlock block = new FormattingModelXmlReader(model).readTestBlock(getTestDataPath(), file); - FormatterBasedLineIndentInfoBuilder builder = new FormatterBasedLineIndentInfoBuilder(document, block); + FormatterBasedLineIndentInfoBuilder builder = new FormatterBasedLineIndentInfoBuilder(document, block, indicator); return builder.build(); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentTest.java index 7fd67d0623b3..d0eae512d718 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentTest.java @@ -153,7 +153,7 @@ public class JavaAutoDetectIndentTest extends AbstractIndentAutoDetectionTest { FormattingModel model = builder.createModel(myFile, CodeStyleSettingsManager.getSettings(getProject())); Block block = model.getRootBlock(); - List list = new FormatterBasedLineIndentInfoBuilder(document, block).build(); + List list = new FormatterBasedLineIndentInfoBuilder(document, block, null).build(); Assert.assertEquals(list.size(), spacesForLine.length); for (int i = 0; i < spacesForLine.length; i++) { diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java index fb227eef4e0e..c203240abd30 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/AbstractJavaFormatterTest.java @@ -32,7 +32,6 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.*; -import com.intellij.psi.codeStyle.autodetect.DetectableIndentOptionsProvider; import com.intellij.testFramework.LightIdeaTestCase; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java new file mode 100644 index 000000000000..5fea9077b91a --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java @@ -0,0 +1,23 @@ +/* + * 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; + +public interface IndentOptionsAdjuster { + void adjust(@NotNull CommonCodeStyleSettings.IndentOptions indentOptions); +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java index 5c083f7814c6..6cd70e73fe8b 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java @@ -15,12 +15,17 @@ */ package com.intellij.psi.codeStyle.autodetect; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface IndentOptionsDetector { + @Nullable + IndentOptionsAdjuster getIndentOptionsAdjuster(@Nullable ProgressIndicator indicator); + @NotNull - CommonCodeStyleSettings.IndentOptions getIndentOptions(); + CommonCodeStyleSettings.IndentOptions getIndentOptions(@Nullable ProgressIndicator indicator); } diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/DetectAndAdjustIndentOptionsTask.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/DetectAndAdjustIndentOptionsTask.java new file mode 100644 index 000000000000..38be39f4e573 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/DetectAndAdjustIndentOptionsTask.java @@ -0,0 +1,92 @@ +/* + * 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; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.util.ProgressIndicatorUtils; +import com.intellij.openapi.progress.util.ReadTask; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions; +import com.intellij.psi.codeStyle.autodetect.IndentOptionsAdjuster; +import com.intellij.psi.codeStyle.autodetect.IndentOptionsDetectorImpl; +import org.jetbrains.annotations.NotNull; + + +class TimeStampedIndentOptions extends IndentOptions { + private long myTimeStamp; + + public TimeStampedIndentOptions(IndentOptions toCopyFrom, long timeStamp) { + copyFrom(toCopyFrom); + myTimeStamp = timeStamp; + } + + void setTimeStamp(long timeStamp) { + myTimeStamp = timeStamp; + } + + long getTimeStamp() { + return myTimeStamp; + } + +} + +class DetectAndAdjustIndentOptionsTask extends ReadTask { + private final Document myDocument; + private final Project myProject; + private final IndentOptions myOptionsToAdjust; + + public DetectAndAdjustIndentOptionsTask(Project project, Document document, @NotNull IndentOptions toAdjust) { + myProject = project; + myDocument = document; + myOptionsToAdjust = toAdjust; + } + + private PsiFile getFile() { + if (myProject.isDisposed()) { + return null; + } + return PsiDocumentManager.getInstance(myProject).getPsiFile(myDocument); + } + + @Override + public void computeInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException { + PsiFile file = getFile(); + if (file == null) return; + + IndentOptionsDetectorImpl detector = new IndentOptionsDetectorImpl(file); + IndentOptionsAdjuster adjuster = detector.getIndentOptionsAdjuster(indicator); + if (adjuster != null) { + adjustOptions(adjuster); + } + } + + private void adjustOptions(IndentOptionsAdjuster adjuster) { + long stamp = myDocument.getModificationStamp(); + adjuster.adjust(myOptionsToAdjust); + if (myOptionsToAdjust instanceof TimeStampedIndentOptions) { + ((TimeStampedIndentOptions)myOptionsToAdjust).setTimeStamp(stamp); + } + } + + @Override + public void onCanceled(@NotNull ProgressIndicator indicator) { + ProgressIndicatorUtils.scheduleWithWriteActionPriority(this); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectableIndentOptionsProvider.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/DetectableIndentOptionsProvider.java similarity index 74% rename from platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectableIndentOptionsProvider.java rename to platform/lang-impl/src/com/intellij/psi/codeStyle/DetectableIndentOptionsProvider.java index 557fb388544d..c86485cd5bd5 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectableIndentOptionsProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/DetectableIndentOptionsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi.codeStyle.autodetect; +package com.intellij.psi.codeStyle; import com.intellij.ide.actions.ShowSettingsUtilImpl; import com.intellij.lang.LanguageFormatting; @@ -24,12 +24,12 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.TextEditor; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiCompiledFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.*; import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.WeakList; @@ -39,6 +39,8 @@ import org.jetbrains.annotations.TestOnly; import java.util.List; +import static com.intellij.openapi.progress.util.ProgressIndicatorUtils.scheduleWithWriteActionPriority; +import static com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions; import static com.intellij.psi.codeStyle.EditorNotificationInfo.ActionLabelData; /** @@ -51,16 +53,36 @@ public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider i @Nullable @Override - public CommonCodeStyleSettings.IndentOptions getIndentOptions(@NotNull CodeStyleSettings settings, @NotNull PsiFile file) { - return isDocumentCommitted(file) && isEnabled(settings, file) - ? new IndentOptionsDetectorImpl(file).getIndentOptions() - : null; + public IndentOptions getIndentOptions(@NotNull CodeStyleSettings settings, @NotNull PsiFile file) { + if (!isEnabled(settings, file)) { + return null; + } + + Project project = file.getProject(); + PsiDocumentManager psiManager = PsiDocumentManager.getInstance(project); + Document document = psiManager.getDocument(file); + if (document == null) { + return null; + } + + IndentOptions options = getValidCachedIndentOptions(file, document); + if (options != null) { + return options; + } + + TimeStampedIndentOptions indentOptions = getDefault(file.getFileType(), project, document.getModificationStamp()); + indentOptions.associateWithDocument(document); + + DetectAndAdjustIndentOptionsTask task = new DetectAndAdjustIndentOptionsTask(project, document, indentOptions); + psiManager.performForCommittedDocument(document, () -> scheduleWithWriteActionPriority(task)); + + return indentOptions; } - private static boolean isDocumentCommitted(@NotNull PsiFile file) { - PsiDocumentManager manager = PsiDocumentManager.getInstance(file.getProject()); - Document document = manager.getDocument(file); - return document != null && manager.isCommitted(document); + @NotNull + private static TimeStampedIndentOptions getDefault(@NotNull FileType fileType, Project project, long timeStamp) { + CodeStyleSettings manager = CodeStyleSettingsManager.getSettings(project); + return new TimeStampedIndentOptions(manager.getIndentOptions(fileType), timeStamp); } @Override @@ -94,8 +116,8 @@ public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider i public EditorNotificationInfo getNotificationInfo(@NotNull final Project project, @NotNull final VirtualFile file, @NotNull final FileEditor fileEditor, - @NotNull CommonCodeStyleSettings.IndentOptions userOptions, - @NotNull CommonCodeStyleSettings.IndentOptions detectedOptions) + @NotNull IndentOptions userOptions, + @NotNull IndentOptions detectedOptions) { final NotificationLabels labels = getNotificationLabels(userOptions, detectedOptions); final Editor editor = fileEditor instanceof TextEditor ? ((TextEditor)fileEditor).getEditor() : null; @@ -138,8 +160,8 @@ public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider i } @Nullable - private static NotificationLabels getNotificationLabels(@NotNull CommonCodeStyleSettings.IndentOptions userOptions, - @NotNull CommonCodeStyleSettings.IndentOptions detectedOptions) { + private static NotificationLabels getNotificationLabels(@NotNull IndentOptions userOptions, + @NotNull IndentOptions detectedOptions) { if (userOptions.USE_TAB_CHARACTER) { if (!detectedOptions.USE_TAB_CHARACTER) { return new NotificationLabels(ApplicationBundle.message("code.style.space.indent.detected", detectedOptions.INDENT_SIZE), @@ -174,6 +196,18 @@ public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider i return !FileIndentOptionsProvider.isShowNotification() || myAcceptedFiles.contains(file); } + public IndentOptions getValidCachedIndentOptions(PsiFile file, Document document) { + IndentOptions options = IndentOptions.retrieveFromAssociatedDocument(file); + long documentStamp = document.getModificationStamp(); + if (options instanceof TimeStampedIndentOptions) { + long optionsStamp = ((TimeStampedIndentOptions)options).getTimeStamp(); + if (optionsStamp == documentStamp) { + return options; + } + } + return null; + } + private static class NotificationLabels { public final String title; public final String revertToOldSettingsLabel; diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java index b1c70a08c18b..bf5aaffe1f26 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/FormatterBasedLineIndentInfoBuilder.java @@ -19,6 +19,7 @@ import com.intellij.formatting.ASTBlock; import com.intellij.formatting.Block; import com.intellij.formatting.Indent; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiComment; @@ -28,6 +29,7 @@ import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -35,14 +37,19 @@ import java.util.List; public class FormatterBasedLineIndentInfoBuilder { private static final int MAX_NEW_LINE_BLOCKS_TO_PROCESS = 500; + private final ProgressIndicator myProgressIndicator; private final Document myDocument; private final CharSequence myText; private final Block myRootBlock; - public FormatterBasedLineIndentInfoBuilder(@NotNull Document document, @NotNull Block rootBlock) { + public FormatterBasedLineIndentInfoBuilder(@NotNull Document document, + @NotNull Block rootBlock, + @Nullable ProgressIndicator indicator) + { myDocument = document; myText = myDocument.getCharsSequence(); myRootBlock = rootBlock; + myProgressIndicator = indicator; } public List build() { @@ -104,7 +111,7 @@ public class FormatterBasedLineIndentInfoBuilder { } private static List getIndentOnStartOffset(Block block, TextRange range, int startOffset) { - List indentsOnStartOffset = new ArrayList(); + List indentsOnStartOffset = new ArrayList<>(); while (block != null && range.getStartOffset() == startOffset) { Indent.Type type = block.getIndent() != null ? block.getIndent().getType() : Indent.Type.CONTINUATION_WITHOUT_FIRST; @@ -122,9 +129,9 @@ public class FormatterBasedLineIndentInfoBuilder { @NotNull private List getBlocksStartingNewLine() { - NewLineBlocksIterator newLineBlocksIterator = new NewLineBlocksIterator(myRootBlock, myDocument); + NewLineBlocksIterator newLineBlocksIterator = new NewLineBlocksIterator(myRootBlock, myDocument, myProgressIndicator); - List newLineBlocks = new ArrayList(); + List newLineBlocks = new ArrayList<>(); int currentLine = 0; while (newLineBlocksIterator.hasNext() && currentLine < MAX_NEW_LINE_BLOCKS_TO_PROCESS) { Block next = newLineBlocksIterator.next(); diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjusterImpl.java similarity index 95% rename from platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java rename to platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjusterImpl.java index 8f379598a3bb..43c76e02b4cf 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjuster.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsAdjusterImpl.java @@ -18,7 +18,7 @@ package com.intellij.psi.codeStyle.autodetect; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import org.jetbrains.annotations.NotNull; -class IndentOptionsAdjuster { +class IndentOptionsAdjusterImpl implements IndentOptionsAdjuster { private static final double RATE_THRESHOLD = 0.8; private static final int MAX_INDENT_TO_DETECT = 8; @@ -26,12 +26,13 @@ class IndentOptionsAdjuster { private final boolean isSpacesUsed; private final int newIndentSize; - public IndentOptionsAdjuster(IndentUsageStatistics stats) { + public IndentOptionsAdjusterImpl(IndentUsageStatistics stats) { isTabsUsed = isTabsUsed(stats); isSpacesUsed = isSpacesUsed(stats); newIndentSize = isSpacesUsed ? getPositiveIndentSize(stats) : 0; } + @Override public void adjust(@NotNull CommonCodeStyleSettings.IndentOptions indentOptions) { if (isTabsUsed) { adjustForTabUsage(indentOptions); 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 a3248fe22e93..bb5e33c20370 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 @@ -20,6 +20,7 @@ import com.intellij.formatting.FormattingModel; import com.intellij.formatting.FormattingModelBuilder; import com.intellij.lang.LanguageFormatting; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.VirtualFile; @@ -44,17 +45,28 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { myProject = file.getProject(); myDocument = PsiDocumentManager.getInstance(myProject).getDocument(myFile); } - + + @Override + @Nullable + public IndentOptionsAdjuster getIndentOptionsAdjuster(@Nullable ProgressIndicator indicator) { + List linesInfo = calcLineIndentInfo(indicator); + if (linesInfo != null) { + IndentUsageStatistics stats = new IndentUsageStatisticsImpl(linesInfo); + return new IndentOptionsAdjusterImpl(stats); + } + return null; + } + @Override @NotNull - public IndentOptions getIndentOptions() { + public IndentOptions getIndentOptions(@Nullable ProgressIndicator indicator) { IndentOptions indentOptions = (IndentOptions)CodeStyleSettingsManager.getSettings(myProject).getIndentOptions(myFile.getFileType()).clone(); - List linesInfo = calcLineIndentInfo(); + List linesInfo = calcLineIndentInfo(indicator); if (linesInfo != null) { IndentUsageStatistics stats = new IndentUsageStatisticsImpl(linesInfo); - IndentOptionsAdjuster adjuster = new IndentOptionsAdjuster(stats); + IndentOptionsAdjuster adjuster = new IndentOptionsAdjusterImpl(stats); adjuster.adjust(indentOptions); } @@ -62,7 +74,7 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { } @Nullable - private List calcLineIndentInfo() { + private List calcLineIndentInfo(@Nullable ProgressIndicator indicator) { if (myDocument == null || myDocument.getLineCount() < 3 || isFileBigToDetect()) { return null; } @@ -73,7 +85,7 @@ public class IndentOptionsDetectorImpl implements IndentOptionsDetector { FormattingModel model = modelBuilder.createModel(myFile, settings); Block rootBlock = model.getRootBlock(); - return new FormatterBasedLineIndentInfoBuilder(myDocument, rootBlock).build(); + return new FormatterBasedLineIndentInfoBuilder(myDocument, rootBlock, indicator).build(); } private boolean isFileBigToDetect() { diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java b/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java index f50b4481664e..f7337dc2554a 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/common/AbstractBlock.java @@ -59,6 +59,13 @@ public abstract class AbstractBlock implements ASTBlock { public List getSubBlocks() { if (mySubBlocks == null) { + try { + Thread.sleep(100); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + List list = buildChildren(); if (list.isEmpty()) { list = buildInjectedBlocks(); diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java b/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java index c03b079e3568..39d7b949312c 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/common/NewLineBlocksIterator.java @@ -17,8 +17,10 @@ package com.intellij.psi.formatter.common; import com.intellij.formatting.Block; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.TextRange; import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.Nullable; import java.util.Iterator; import java.util.List; @@ -26,20 +28,23 @@ import java.util.ListIterator; import java.util.Stack; public class NewLineBlocksIterator implements Iterator { + private final ProgressIndicator myIndicator; private final Document myDocument; private final int myTotalLines; private int myCurrentLineStartOffset; private int myCurrentDocumentLine; - private Stack myStack = new Stack(); + private Stack myStack = new Stack<>(); - public NewLineBlocksIterator(Block root, Document document) { + public NewLineBlocksIterator(Block root, Document document, @Nullable ProgressIndicator indicator) { myStack.add(root); myDocument = document; myTotalLines = myDocument.getLineCount(); myCurrentDocumentLine = 0; myCurrentLineStartOffset = 0; + + myIndicator = indicator; } @Override @@ -57,6 +62,7 @@ public class NewLineBlocksIterator implements Iterator { Block block = myStack.peek(); while (block != null && !isStartingNewLine(block)) { + checkCancelled(); myCurrentDocumentLine++; if (myCurrentDocumentLine >= myTotalLines) { myStack.clear(); @@ -68,6 +74,12 @@ public class NewLineBlocksIterator implements Iterator { } } + private void checkCancelled() { + if (myIndicator != null) { + myIndicator.checkCanceled(); + } + } + @Override public Block next() { popUntilTopBlockStartsNewLine(); @@ -92,6 +104,7 @@ public class NewLineBlocksIterator implements Iterator { private void popUntilTopBlockStartOffsetGreaterOrEqual(final int lineStartOffset) { while (!myStack.isEmpty()) { + checkCancelled(); Block current = myStack.peek(); TextRange range = current.getTextRange(); if (range.getStartOffset() < lineStartOffset) { diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index db6483407131..b9502b90b2be 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -936,7 +936,7 @@ - + diff --git a/platform/platform-tests/testSrc/com/intellij/psi/autodetect/AbstractIndentAutoDetectionTest.java b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/AbstractIndentAutoDetectionTest.java index f2807f466d99..505ca74b9446 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/autodetect/AbstractIndentAutoDetectionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/AbstractIndentAutoDetectionTest.java @@ -97,7 +97,7 @@ public abstract class AbstractIndentAutoDetectionTest extends LightPlatformCodeI Assert.assertNotNull(builder); FormattingModel model = builder.createModel(myFile, CodeStyleSettingsManager.getSettings(getProject())); - List lines = new FormatterBasedLineIndentInfoBuilder(document, model.getRootBlock()).build(); + List lines = new FormatterBasedLineIndentInfoBuilder(document, model.getRootBlock(), null).build(); IndentUsageStatistics statistics = new IndentUsageStatisticsImpl(lines); return statistics.getKMostUsedIndentInfo(0); @@ -106,6 +106,6 @@ public abstract class AbstractIndentAutoDetectionTest extends LightPlatformCodeI @NotNull public static CommonCodeStyleSettings.IndentOptions detectIndentOptions() { IndentOptionsDetector detector = new IndentOptionsDetectorImpl(myFile); - return detector.getIndentOptions(); + return detector.getIndentOptions(null); } }