From 1b198a33337c00626927aa42062c9263b06bdb7f Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Fri, 18 Feb 2011 16:31:05 +0300 Subject: [PATCH] Don't perform 'sequential formatting' if dummy special text is inserted to the document --- .../codeInsight/template/ExpressionUtil.java | 2 + .../psi/codeStyle/CodeStyleManager.java | 16 +++++ .../source/codeStyle/CodeFormatterFacade.java | 5 +- .../codeStyle/CodeStyleManagerImpl.java | 62 +++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/template/ExpressionUtil.java b/java/java-impl/src/com/intellij/codeInsight/template/ExpressionUtil.java index de5d85de8356..f02d511da866 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/ExpressionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/ExpressionUtil.java @@ -23,6 +23,7 @@ package com.intellij.codeInsight.template; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; + import com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl; import com.intellij.psi.text.BlockSupport; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nullable; @@ -54,6 +55,7 @@ package com.intellij.codeInsight.template; ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { BlockSupport blockSupport = ServiceManager.getService(project, BlockSupport.class); + CodeStyleManagerImpl.setSequentialProcessingAllowed(false); try{ blockSupport.reparseRange(fileCopy, offset, offset, "xxx"); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java index 4c0055ceb905..e79ff8eedfc3 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleManager.java @@ -216,4 +216,20 @@ public abstract class CodeStyleManager { * the file is read-only). */ public abstract void reformatNewlyAddedElement(@NotNull final ASTNode block, @NotNull final ASTNode addedElement) throws IncorrectOperationException; + + /** + * Formatting may be executed sequentially, i.e. the whole (re)formatting task is split into a number of smaller sub-tasks + * that are executed sequentially. That is done primarily for ability to show progress dialog during formatting (formatting + * is always performed from EDT, hence, the GUI freezes if we perform formatting as a single big iteration). + *

+ * However, there are situation when we don't want to use such an approach - for example, IntelliJ IDEA sometimes inserts dummy + * text into file in order to calculate formatting-specific data and removes it after that. We don't want to allow Swing events + * dispatching during that in order to not show that dummy text to the end-user. + *

+ * It's possible to configure that (implementation details are insignificant here) and current method serves as a read-only + * facade for obtaining information if 'sequential' processing is allowed at the moment. + * + * @return true if 'sequential' formatting is allowed now; false otherwise + */ + public abstract boolean isSequentialProcessingAllowed(); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java index 4708ab4c5307..b765cb3f1a90 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java @@ -36,6 +36,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.DocumentBasedFormattingModel; import com.intellij.psi.impl.source.PostprocessReformattingAspect; @@ -188,7 +189,9 @@ public class CodeFormatterFacade { project, mySettings, file.getFileType(), file); FormatterEx formatter = FormatterEx.getInstanceEx(); - formatter.setProgressIndicator(new FormattingProgressIndicatorImpl(project, file, document)); + if (CodeStyleManager.getInstance(project).isSequentialProcessingAllowed()) { + formatter.setProgressIndicator(new FormattingProgressIndicatorImpl(project, file, document)); + } formatter.format(model, mySettings, mySettings.getIndentOptions(file.getFileType()), ranges); for (FormatTextRanges.FormatTextRange range : textRanges) { TextRange textRange = range.getTextRange(); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java index a8ab933f8d24..613654cd87fb 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java @@ -48,8 +48,20 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.concurrent.TimeUnit; + public class CodeStyleManagerImpl extends CodeStyleManager { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl"); + private static final ThreadLocal SEQUENTIAL_PROCESSING_ALLOWED + = new ThreadLocal() + { + @Override + protected ProcessingUnderProgressInfo initialValue() { + return new ProcessingUnderProgressInfo(); + } + }; + private final Project myProject; @NonNls private static final String DUMMY_IDENTIFIER = "xxx"; @@ -478,6 +490,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager { document.deleteString(start, end); document.insertString(start, buffer); + setSequentialProcessingAllowed(false); document.insertString(offset, DUMMY_IDENTIFIER); return new TextRange(offset, offset + DUMMY_IDENTIFIER.length()); } @@ -506,6 +519,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager { ASTNode space1 = splitSpaceElement((TreeElement)element, offset - elementStart, charTable); ASTNode marker = Factory.createSingleLeafElement(TokenType.NEW_LINE_INDENT, DUMMY_IDENTIFIER, charTable, file.getManager()); + setSequentialProcessingAllowed(false); parent.addChild(marker, space1.getTreeNext()); PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(marker); return psiElement == null ? null : psiElement.getTextRange(); @@ -561,4 +575,52 @@ public class CodeStyleManagerImpl extends CodeStyleManager { private CodeStyleSettings getSettings() { return CodeStyleSettingsManager.getSettings(myProject); } + + @Override + public boolean isSequentialProcessingAllowed() { + return SEQUENTIAL_PROCESSING_ALLOWED.get().isAllowed(); + } + + /** + * Allows to define if {@link #isSequentialProcessingAllowed() sequential processing} should be allowed. + *

+ * Current approach is not allow to stop sequential processing for more than predefine amount of time (couple of seconds). + * That means that call to this method with 'true' argument is not mandatory for successful processing even + * if this method is called with 'false' argument before. + * + * @param allowed flag that defines if {@link #isSequentialProcessingAllowed() sequential processing} should be allowed + */ + public static void setSequentialProcessingAllowed(boolean allowed) { + ProcessingUnderProgressInfo info = SEQUENTIAL_PROCESSING_ALLOWED.get(); + if (allowed) { + info.decrement(); + } + else { + info.increment(); + } + } + + private static class ProcessingUnderProgressInfo { + + private static final long DURATION_TIME = TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS); + + private int myCount; + private long myEndTime; + + public void increment() { + myCount++; + myEndTime = System.currentTimeMillis() + DURATION_TIME; + } + + public void decrement() { + if (myCount <= 0) { + return; + } + myCount--; + } + + public boolean isAllowed() { + return myCount <= 0 || System.currentTimeMillis() >= myEndTime; + } + } }