From 86d8247ef9a82222ecda03435cbfc7d8b7871ad0 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 16 Mar 2016 12:54:47 +0100 Subject: [PATCH] wrap writing editor actions into transactions --- .../codeInsight/editorActions/EndHandler.java | 30 +++++++++-------- .../editorActions/FixDocCommentAction.java | 12 ++++++- .../editorActions/PasteHandler.java | 8 +++++ .../lookup/impl/BackspaceHandler.java | 9 ++++++ .../lookup/impl/actions/ChooseItemAction.java | 10 ++++-- .../impl/actions/NextVariableAction.java | 9 ++++++ .../impl/actions/PreviousVariableAction.java | 9 ++++++ .../impl/editorActions/EscapeHandler.java | 16 ++++++---- .../editor/actionSystem/EditorAction.java | 32 +++++++++---------- .../actionSystem/EditorActionHandler.java | 12 +++++++ .../EditorWriteActionHandler.java | 10 ++++++ .../editor/actions/KillRingSaveAction.java | 10 ++++++ 12 files changed, 126 insertions(+), 41 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EndHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EndHandler.java index dce7674debcf..1f035aa59e5e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EndHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EndHandler.java @@ -21,6 +21,8 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -90,10 +92,9 @@ public class EndHandler extends EditorActionHandler { // documents). Hence, we check that and don't finish processing in case we have such a situation. AtomicBoolean is used // here just as a boolean value holder due to requirement to declare variable used from inner class as final. final AtomicBoolean stopProcessing = new AtomicBoolean(true); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { + TransactionGuard.syncTransaction(TransactionKind.TEXT_EDITING, () -> { + PsiDocumentManager.getInstance(project).commitAllDocuments(); + ApplicationManager.getApplication().runWriteAction(() -> { CodeStyleManager styleManager = CodeStyleManager.getInstance(project); final String lineIndent = styleManager.getLineIndent(file, caretOffset); if (lineIndent != null) { @@ -115,16 +116,7 @@ public class EndHandler extends EditorActionHandler { editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); editor.getSelectionModel().removeSelection(); - } - - private int calcColumnNumber(final String lineIndent, final int tabSize) { - int result = 0; - for (char c : lineIndent.toCharArray()) { - if (c == ' ') result++; - if (c == '\t') result += tabSize; - } - return result; - } + }); }); if (stopProcessing.get()) { return; @@ -137,4 +129,14 @@ public class EndHandler extends EditorActionHandler { myOriginalHandler.execute(editor, caret, dataContext); } } + + private int calcColumnNumber(final String lineIndent, final int tabSize) { + int result = 0; + for (char c : lineIndent.toCharArray()) { + if (c == ' ') result++; + if (c == '\t') result += tabSize; + } + return result; + } + } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java index 813c3eadd718..e4ea17021568 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java @@ -20,8 +20,12 @@ import com.intellij.lang.*; import com.intellij.lang.documentation.CodeDocumentationProvider; import com.intellij.lang.documentation.CompositeDocumentationProvider; import com.intellij.lang.documentation.DocumentationProvider; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Document; @@ -56,6 +60,12 @@ public class FixDocCommentAction extends EditorAction { } private static final class MyHandler extends EditorActionHandler { + + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override public void execute(Editor editor, DataContext dataContext) { Project project = CommonDataKeys.PROJECT.getData(dataContext); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java index 3ba45f60dd24..05b499479c6f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java @@ -21,7 +21,10 @@ import com.intellij.ide.PasteProvider; import com.intellij.lang.LanguageFormatting; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; @@ -71,6 +74,11 @@ public class PasteHandler extends EditorActionHandler implements EditorTextInser myOriginalHandler = originalAction; } + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override public void doExecute(final Editor editor, Caret caret, final DataContext dataContext) { assert caret == null : "Invocation of 'paste' operation for specific caret is not supported"; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java index 470683227397..b351206b0465 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/BackspaceHandler.java @@ -20,9 +20,13 @@ import com.intellij.codeInsight.completion.CompletionProgressIndicator; import com.intellij.codeInsight.completion.impl.CompletionServiceImpl; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import org.jetbrains.annotations.NotNull; public class BackspaceHandler extends EditorActionHandler { private final EditorActionHandler myOriginalHandler; @@ -31,6 +35,11 @@ public class BackspaceHandler extends EditorActionHandler { myOriginalHandler = originalHandler; } + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override public void doExecute(final Editor editor, Caret caret, final DataContext dataContext){ LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java index 29219f2c185b..2d5014e66ecb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemAction.java @@ -26,11 +26,12 @@ import com.intellij.codeInsight.template.impl.*; import com.intellij.codeInsight.template.impl.editorActions.ExpandLiveTemplateCustomAction; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; -import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; -import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.util.containers.ContainerUtil; @@ -52,6 +53,11 @@ public abstract class ChooseItemAction extends EditorAction { this.finishingChar = finishingChar; } + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override public void execute(@NotNull final Editor editor, final DataContext dataContext) { final LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/NextVariableAction.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/NextVariableAction.java index 928de5e5b1bb..8d5f50bc7c07 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/NextVariableAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/NextVariableAction.java @@ -28,6 +28,9 @@ import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; @@ -43,6 +46,12 @@ public class NextVariableAction extends EditorAction { } private static class Handler extends EditorActionHandler { + + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override protected void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) { TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/PreviousVariableAction.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/PreviousVariableAction.java index df9fa2454b44..2127eebf1705 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/PreviousVariableAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/actions/PreviousVariableAction.java @@ -28,6 +28,9 @@ import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; @@ -43,6 +46,12 @@ public class PreviousVariableAction extends EditorAction { } private static class Handler extends EditorActionHandler { + + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override protected void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) { final TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java index a758fff17e90..2af20c95c3e9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java @@ -16,13 +16,15 @@ package com.intellij.codeInsight.template.impl.editorActions; -import com.intellij.openapi.editor.actionSystem.EditorActionHandler; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; public class EscapeHandler extends EditorActionHandler { private final EditorActionHandler myOriginalHandler; @@ -37,7 +39,7 @@ public class EscapeHandler extends EditorActionHandler { final TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); if (templateState != null && !templateState.isFinished()) { CommandProcessor.getInstance().setCurrentCommandName(CodeInsightBundle.message("finish.template.command")); - templateState.gotoEnd(true); + TransactionGuard.syncTransaction(TransactionKind.TEXT_EDITING, () -> templateState.gotoEnd(true)); return; } } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java index e5b6abde7bbb..7f6cc9b9d131 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java @@ -16,6 +16,7 @@ package com.intellij.openapi.editor.actionSystem; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.editor.Editor; @@ -92,26 +93,23 @@ public abstract class EditorAction extends AnAction implements DumbAware { if (editor == null) return; final EditorActionHandler handler = getHandler(); - Runnable command = new Runnable() { - @Override - public void run() { - handler.execute(editor, null, getProjectAwareDataContext(editor, dataContext)); + Runnable command = () -> handler.execute(editor, null, getProjectAwareDataContext(editor, dataContext)); + + try (AccessToken ignored = handler.startTransaction(editor)) { + if (!handler.executeInCommand(editor, dataContext)) { + command.run(); + return; } - }; - if (!handler.executeInCommand(editor, dataContext)) { - command.run(); - return; + String commandName = getTemplatePresentation().getText(); + if (commandName == null) commandName = ""; + CommandProcessor.getInstance().executeCommand(editor.getProject(), + command, + commandName, + handler.getCommandGroupId(editor), + UndoConfirmationPolicy.DEFAULT, + editor.getDocument()); } - - String commandName = getTemplatePresentation().getText(); - if (commandName == null) commandName = ""; - CommandProcessor.getInstance().executeCommand(editor.getProject(), - command, - commandName, - handler.getCommandGroupId(editor), - UndoConfirmationPolicy.DEFAULT, - editor.getDocument()); } public void update(Editor editor, Presentation presentation, DataContext dataContext) { diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java index 6b0ebd64dc6c..fd0e84fe8630 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java @@ -18,6 +18,9 @@ package com.intellij.openapi.editor.actionSystem; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.TransactionKind; +import com.intellij.openapi.application.WrapInTransaction; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.CaretAction; import com.intellij.openapi.editor.Editor; @@ -180,6 +183,15 @@ public abstract class EditorActionHandler { return true; } + /** + * @return the transaction access token that this action should be executed inside, or null if no transaction is required. + * @see com.intellij.openapi.application.TransactionGuard#startSynchronousTransaction(TransactionKind) + */ + @Nullable + public AccessToken startTransaction(@NotNull Editor editor) { + return null; + } + public boolean runForAllCarets() { return myRunForEachCaret; } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorWriteActionHandler.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorWriteActionHandler.java index 163f7cff058b..8aedfa7900b8 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorWriteActionHandler.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorWriteActionHandler.java @@ -17,11 +17,15 @@ package com.intellij.openapi.editor.actionSystem; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.textarea.TextComponentEditor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -38,6 +42,12 @@ public abstract class EditorWriteActionHandler extends EditorActionHandler { super(runForEachCaret); } + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + if (editor instanceof TextComponentEditor) return null; + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override public void doExecute(final Editor editor, @Nullable final Caret caret, final DataContext dataContext) { if (editor.isViewer()) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/KillRingSaveAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/KillRingSaveAction.java index f9a1b5ff4d39..7fbc5299b96b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/KillRingSaveAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/KillRingSaveAction.java @@ -16,13 +16,17 @@ package com.intellij.openapi.editor.actions; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.editor.DocumentRunnable; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.textarea.TextComponentEditor; import com.intellij.openapi.ide.KillRingTransferable; +import org.jetbrains.annotations.NotNull; /** * Stands for emacs kill-ring-save command. @@ -48,6 +52,12 @@ public class KillRingSaveAction extends TextComponentEditorAction { myRemove = remove; } + @Override + public AccessToken startTransaction(@NotNull Editor editor) { + if (editor instanceof TextComponentEditor || !myRemove) return null; + return TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING); + } + @Override public void execute(final Editor editor, final DataContext dataContext) { SelectionModel selectionModel = editor.getSelectionModel();