diff --git a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java index fc12f45a8a2d..a206e8310e23 100644 --- a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java +++ b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java @@ -19,7 +19,6 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.progress.ProcessCanceledException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * A service managing model transactions.

@@ -39,7 +38,7 @@ import org.jetbrains.annotations.Nullable; * outer transaction has shown a dialog with an editor, and typing into that editor (which requires a transaction for changing document) * should be allowed. For such cases, the framework should be notified which transaction kinds are allowed to merged into * the main transaction and executed immediately. Use {@link #acceptNestedTransactions(TransactionKind...)} for that. Inner transactions - * should be given a non-null kind in such circumstances: {@link #submitMergeableTransaction(TransactionKind, Runnable)}. + * should be given some kind in such circumstances: {@link #submitMergeableTransaction(TransactionKind, Runnable)}. * * @see Application#runReadAction(Runnable) * @see Application#runWriteAction(Runnable) @@ -47,6 +46,26 @@ import org.jetbrains.annotations.Nullable; * @author peter */ public abstract class TransactionGuard { + /** + * This kind represents document modifications via editor actions, code completion and document->PSI commit. + * @see com.intellij.psi.PsiDocumentManager#commitDocument(Document) + */ + public static final TransactionKind TEXT_EDITING = new TransactionKind("TEXT_EDITING"); + /** + * This kind represents any model modifications: + *

  • PSI or document changes + *
  • Virtual file system changes, e.g. files created/deleted/renamed/content-changed, + * caused by refresh process or explicit operations. + *
  • Project root set change + *
  • Dumb mode (reindexing) start/finish, (see {@link com.intellij.openapi.project.DumbService}). + */ + public static final TransactionKind ANY_CHANGE = new TransactionKind("ANY_CHANGE"); + + /** + * Transactions of this kind won't be merged into other transactions + */ + public static final TransactionKind NO_MERGE = new TransactionKind("NO_MERGE"); + public static TransactionGuard getInstance() { return ServiceManager.getService(TransactionGuard.class); } @@ -55,11 +74,13 @@ public abstract class TransactionGuard { * Ensures that some code will be run in a transaction. It's guaranteed that no other transactions are run at the same time. * The code will be run on Swing thread immediately or after all other queued transactions (if any) have been completed.

    * - * For more advanced version, see {@link #submitMergeableTransaction(TransactionKind, Runnable)} + * For more advanced version, see {@link #submitMergeableTransaction(TransactionKind, Runnable)}. + * Transactions submitted via this method use {@link #NO_MERGE} kind. + * * @param transaction code to execute inside a transaction. */ public static void submitTransaction(@NotNull Runnable transaction) { - getInstance().submitMergeableTransaction(null, transaction); + getInstance().submitMergeableTransaction(NO_MERGE, transaction); } /** @@ -69,14 +90,14 @@ public abstract class TransactionGuard { * @param transaction * @throws ProcessCanceledException if current thread is interrupted */ - public abstract void submitTransactionAndWait(@Nullable TransactionKind kind, @NotNull Runnable transaction) throws ProcessCanceledException; + public abstract void submitTransactionAndWait(@NotNull TransactionKind kind, @NotNull Runnable transaction) throws ProcessCanceledException; /** * A synchronous version of {@link #submitMergeableTransaction(TransactionKind, Runnable)}. * @return a token object for this transaction. Call {@link AccessToken#finish()} (inside finally) when the transaction is complete. */ @NotNull - public abstract AccessToken startSynchronousTransaction(@Nullable TransactionKind kind); + public abstract AccessToken startSynchronousTransaction(@NotNull TransactionKind kind); /** * @return whether there's a transaction currently running @@ -89,10 +110,10 @@ public abstract class TransactionGuard { * and executes the provided code immediately. Otherwise * adds the runnable to a queue. When all transactions scheduled before this one are finished, executes the given * runnable under a transaction. - * @param kind a kind object to enable transaction merging or null, if no merging is required. + * @param kind a kind object to enable transaction merging or {@link #NO_MERGE}, if no merging is required. * @param transaction code to execute inside a transaction. */ - public abstract void submitMergeableTransaction(@Nullable TransactionKind kind, @NotNull Runnable transaction); + public abstract void submitMergeableTransaction(@NotNull TransactionKind kind, @NotNull Runnable transaction); /** * Allow incoming transactions of the specified kinds to be executed immediately, instead of being queued until the current transaction is finished.

    @@ -106,23 +127,10 @@ public abstract class TransactionGuard { @NotNull public abstract AccessToken acceptNestedTransactions(TransactionKind... kinds); + /** + * A kind of transaction used in {@link #acceptNestedTransactions(TransactionKind...)} + */ public static final class TransactionKind { - /** - * This kind represents document modifications via editor actions, code completion and document->PSI commit. - * @see com.intellij.psi.PsiDocumentManager#commitDocument(Document) - */ - public static final TransactionKind TEXT_EDITING = new TransactionKind("TEXT_EDITING"); - - /** - * This kind represents any model modifications: - *

  • PSI or document changes - *
  • Virtual file system changes, e.g. files created/deleted/renamed/content-changed, - * caused by refresh process or explicit operations. - *
  • Project root set change - *
  • Dumb mode (reindexing) start/finish, (see {@link com.intellij.openapi.project.DumbService}). - */ - public static final TransactionKind ANY_CHANGE = new TransactionKind("ANY_CHANGE"); - private final String myName; public TransactionKind(@NotNull String name) { diff --git a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java index c445fd7357b0..beeef76cc522 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java @@ -19,7 +19,6 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Queue; @@ -36,9 +35,9 @@ public class TransactionGuardImpl extends TransactionGuard { @Override @NotNull - public AccessToken startSynchronousTransaction(@Nullable TransactionKind kind) throws IllegalStateException { + public AccessToken startSynchronousTransaction(@NotNull TransactionKind kind) throws IllegalStateException { ApplicationManager.getApplication().assertIsDispatchThread(); - if (kind != null && myMergeableKinds.contains(kind)) { + if (kind != NO_MERGE && myMergeableKinds.contains(kind)) { return AccessToken.EMPTY_ACCESS_TOKEN; } if (myInsideTransaction) { @@ -66,13 +65,13 @@ public class TransactionGuardImpl extends TransactionGuard { Runnable next = myQueue.poll(); if (next != null) { - runSyncTransaction(null, next); + runSyncTransaction(NO_MERGE, next); } } }, app.getDisposed()); } - private void runSyncTransaction(@Nullable TransactionKind kind, @NotNull Runnable code) { + private void runSyncTransaction(@NotNull TransactionKind kind, @NotNull Runnable code) { AccessToken token = startSynchronousTransaction(kind); try { code.run(); @@ -89,17 +88,17 @@ public class TransactionGuardImpl extends TransactionGuard { } @Override - public void submitMergeableTransaction(@Nullable final TransactionKind kind, @NotNull final Runnable transaction) { + public void submitMergeableTransaction(@NotNull final TransactionKind kind, @NotNull final Runnable transaction) { submitTransaction(kind, transaction, ModalityState.defaultModalityState()); } - public void submitTransaction(@Nullable final TransactionKind kind, - @NotNull final Runnable transaction, - ModalityState modalityState) { + public void submitTransaction(@NotNull final TransactionKind kind, + @NotNull final Runnable transaction, + ModalityState modalityState) { Runnable runnable = new Runnable() { @Override public void run() { - if (!myInsideTransaction || kind != null && myMergeableKinds.contains(kind)) { + if (!myInsideTransaction || kind != NO_MERGE && myMergeableKinds.contains(kind)) { runSyncTransaction(kind, transaction); } else { @@ -121,9 +120,12 @@ public class TransactionGuardImpl extends TransactionGuard { @Override @NotNull public AccessToken acceptNestedTransactions(TransactionKind... kinds) { + //todo enable when transactions are mandatory + /* if (!isInsideTransaction()) { throw new IllegalStateException("acceptNestedTransactions must be called inside a transaction"); } + */ final List toRemove = ContainerUtil.newArrayList(); for (TransactionKind kind : kinds) { if (myMergeableKinds.add(kind)) { @@ -139,11 +141,11 @@ public class TransactionGuardImpl extends TransactionGuard { } @Override - public void submitTransactionAndWait(@Nullable TransactionKind kind, @NotNull final Runnable transaction) throws ProcessCanceledException { + public void submitTransactionAndWait(@NotNull TransactionKind kind, @NotNull final Runnable transaction) throws ProcessCanceledException { submitTransactionAndWait(kind, transaction, ModalityState.defaultModalityState()); } - public void submitTransactionAndWait(@Nullable TransactionKind kind, + public void submitTransactionAndWait(@NotNull TransactionKind kind, @NotNull final Runnable transaction, ModalityState modalityState) { Application app = ApplicationManager.getApplication(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index c43de979179d..613f15b5df16 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -483,7 +483,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement void disposeIndicator() { // our offset map should be disposed under write action, so that duringCompletion (read action) won't access it after disposing - TransactionGuard.getInstance().submitMergeableTransaction(TransactionGuard.TransactionKind.TEXT_EDITING, () -> + TransactionGuard.getInstance().submitMergeableTransaction(TransactionGuard.TEXT_EDITING, () -> ApplicationManager.getApplication().runWriteAction(() -> Disposer.dispose(this))); } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index b00595645c10..f20f2ee88f84 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -500,7 +500,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App Runnable task = new Runnable() { @Override public void run() { - ApplicationImpl.super.createComponents(indicator); + try (AccessToken ignored = TransactionGuard.getInstance().startSynchronousTransaction(TransactionGuard.NO_MERGE)) { + ApplicationImpl.super.createComponents(indicator); + } } };