From 4e62926d4caefd6985857416b0a48e0262b375f9 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 6 Jul 2011 14:20:57 +0400 Subject: [PATCH] fixed completion disappear, clearer API --- .../CompletionAutoPopupTestCase.groovy | 2 +- .../com/intellij/psi/PsiDocumentManager.java | 3 +- .../daemon/impl/DaemonCodeAnalyzerImpl.java | 2 +- .../CompletionAutoPopupHandler.java | 42 +++++++-------- .../psi/impl/PsiDocumentManagerImpl.java | 54 ++++++++++++++----- 5 files changed, 64 insertions(+), 39 deletions(-) diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy index 671d253fd4af..4a392cd22b92 100644 --- a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy +++ b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy @@ -103,7 +103,7 @@ abstract class CompletionAutoPopupTestCase extends LightCodeInsightFixtureTestCa } edt { PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); - manager.performWhenAllDocumentsAreCommitted("wait for all comm", runnable); + manager.cancelAndRunWhenAllCommitted("wait for all comm", runnable); } while (!committed.get()) { UIUtil.pump(); diff --git a/platform/lang-api/src/com/intellij/psi/PsiDocumentManager.java b/platform/lang-api/src/com/intellij/psi/PsiDocumentManager.java index f5fc91fdfa33..eaf7ebfcd2b5 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiDocumentManager.java +++ b/platform/lang-api/src/com/intellij/psi/PsiDocumentManager.java @@ -18,6 +18,7 @@ package com.intellij.psi; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,7 +38,7 @@ public abstract class PsiDocumentManager { * @param action to run when all documents committed * @return true if action was run immediately (i.e. all documents are already committed) */ - public abstract boolean performWhenAllDocumentsAreCommitted(@NotNull Object key, @NotNull Runnable action); + public abstract boolean cancelAndRunWhenAllCommitted(@NonNls @NotNull Object key, @NotNull Runnable action); /** * Returns the document manager instance for the specified project. diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index 0e27ecd04bee..1b1441d41e31 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -708,7 +708,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx runnable.run(); } else { - PsiDocumentManager.getInstance(myProject).performWhenAllDocumentsAreCommitted("start daemon when all committed", runnable); + PsiDocumentManager.getInstance(myProject).cancelAndRunWhenAllCommitted("start daemon when all committed", runnable); } } }; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java index 04680a5cd032..f1e32577e9e2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; @@ -127,15 +128,10 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { final int time, final boolean hasModifiers, final Condition condition) { - //if (true) { - // new CodeCompletionHandlerBase(completionType, invokedExplicitly, autopopup) - // .invokeCompletion(project, editor, time, hasModifiers); - // return; - //} final Document document = editor.getDocument(); final long beforeStamp = document.getModificationStamp(); final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); - documentManager.performWhenAllDocumentsAreCommitted("start completion when all docs committed", new Runnable() { + documentManager.cancelAndRunWhenAllCommitted("start completion when all docs committed", new Runnable() { @Override public void run() { long afterStamp = document.getModificationStamp(); @@ -182,23 +178,23 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { public static void runLaterWithCommitted(@NotNull final Project project, final Document document, final Runnable runnable) { final long beforeStamp = document.getModificationStamp(); - PsiDocumentManager.getInstance(project).performWhenAllDocumentsAreCommitted("run later when committed", new Runnable() { - @Override - public void run() { - // later because we may end up in write action here if there was a synchronous commit - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (beforeStamp != document.getModificationStamp()) { - // no luck, will try later - runLaterWithCommitted(project, document, runnable); + ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).performWhenAllCommitted(new Runnable() { + @Override + public void run() { + // later because we may end up in write action here if there was a synchronous commit + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (beforeStamp != document.getModificationStamp()) { + // no luck, will try later + runLaterWithCommitted(project, document, runnable); + } + else { + runnable.run(); + } } - else { - runnable.run(); - } - } - }, project.getDisposed()); - } - }); + }, project.getDisposed()); + } + }); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index 9627f6089ec3..c5a074995d97 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -38,10 +38,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectLocator; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.UserDataHolderEx; +import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl; @@ -245,23 +242,54 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec } private final Map actionsWhenAllDocumentsAreCommitted = new LinkedHashMap(); //accessed from EDT only + private static final Object PERFORM_ALWAYS_KEY = new Object(); - // returns true if action has been run immediately + /** Schedules action to be executed when all documents are committed. + * @return true if action has been run immediately, or false if action was scheduled for execution later. + */ + public boolean performWhenAllCommitted(@NotNull final Runnable action) { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (myUncommittedDocuments.isEmpty()) { + action.run(); + return true; + } + CompositeRunnable actions = (CompositeRunnable)actionsWhenAllDocumentsAreCommitted.get(PERFORM_ALWAYS_KEY); + if (actions == null) { + actions = new CompositeRunnable(); + actionsWhenAllDocumentsAreCommitted.put(PERFORM_ALWAYS_KEY, actions); + } + actions.add(action); + return false; + } + + private static class CompositeRunnable extends ArrayList implements Runnable { + @Override + public void run() { + for (Runnable runnable : this) { + runnable.run(); + } + } + } + + /** + * Cancel previously registered action and schedules (new) action to be executed when all documents are committed. + * @param key the (unique) name of the action. This action will overwrite any action which was registered under this key earlier. + * @return true if action has been run immediately, or false if action was scheduled for execution later. + */ @Override - public boolean performWhenAllDocumentsAreCommitted(@NotNull Object key, @NotNull final Runnable action) { + public boolean cancelAndRunWhenAllCommitted(@NotNull Object key, @NotNull final Runnable action) { ApplicationManager.getApplication().assertIsDispatchThread(); if (myProject.isDisposed()) { action.run(); return true; } - if (!myUncommittedDocuments.isEmpty()) { - actionsWhenAllDocumentsAreCommitted.put(key, action); - return false; + if (myUncommittedDocuments.isEmpty()) { + action.run(); + assert actionsWhenAllDocumentsAreCommitted.isEmpty() : actionsWhenAllDocumentsAreCommitted; + return true; } - - action.run(); - assert actionsWhenAllDocumentsAreCommitted.isEmpty() : actionsWhenAllDocumentsAreCommitted; - return true; + actionsWhenAllDocumentsAreCommitted.put(key, action); + return false; } public static void addRunOnCommit(@NotNull Document document, @NotNull Runnable action) {