From 7bcb30a56ff31c4b6c00453e171d03f9ebb03b1a Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 9 Feb 2011 18:39:53 +0300 Subject: [PATCH] perform massive undo in one big bulkmode --- .../command/impl/EditorChangeAction.java | 7 -- .../command/impl/NonUndoableAction.java | 11 ++- .../openapi/command/impl/UndoableGroup.java | 83 ++++++++++++++----- 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java index ae10ed909023..2a9daed30f38 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java @@ -31,7 +31,6 @@ class EditorChangeAction extends BasicUndoableAction { private final CharSequence myNewString; private final long myOldTimeStamp; private final long myNewTimeStamp; - private final boolean myBulkUpdate; public EditorChangeAction(DocumentEx document, int offset, @@ -45,8 +44,6 @@ class EditorChangeAction extends BasicUndoableAction { myNewString = newString == null ? "" : newString; myOldTimeStamp = oldTimeStamp; myNewTimeStamp = document.getModificationStamp(); - - myBulkUpdate = document.isInBulkUpdate(); } public void undo() { @@ -64,8 +61,6 @@ class EditorChangeAction extends BasicUndoableAction { private void exchangeStrings(CharSequence newString, CharSequence oldString) { DocumentEx d = getDocument(); - if (myBulkUpdate) d.setInBulkUpdate(true); - if (newString.length() > 0 && oldString.length() == 0) { d.deleteString(myOffset, myOffset + newString.length()); } @@ -75,8 +70,6 @@ class EditorChangeAction extends BasicUndoableAction { else if (oldString.length() > 0 && newString.length() > 0) { d.replaceString(myOffset, myOffset + newString.length(), oldString); } - - if (myBulkUpdate) d.setInBulkUpdate(false); } private void refreshFileStatus() { diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java index c315d1165cfd..0d829ef33064 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java @@ -17,7 +17,6 @@ package com.intellij.openapi.command.impl; import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.command.undo.UndoableAction; -import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.diagnostic.Logger; class NonUndoableAction implements UndoableAction { @@ -31,12 +30,12 @@ class NonUndoableAction implements UndoableAction { myRefs = new DocumentReference[]{ref}; } - public final void undo() throws UnexpectedUndoException { - LOG.assertTrue(false); + public final void undo() { + LOG.error("Cannot undo"); } - public void redo() throws UnexpectedUndoException { - LOG.assertTrue(false); + public void redo() { + LOG.error("Cannot redo"); } public DocumentReference[] getAffectedDocuments() { @@ -46,4 +45,4 @@ class NonUndoableAction implements UndoableAction { public boolean isGlobal() { return myGlobal; } -} \ No newline at end of file +} diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java index ffcab6183080..6368daa54529 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoableGroup.java @@ -24,6 +24,7 @@ import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.command.undo.UndoableAction; import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.Messages; @@ -32,11 +33,9 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; class UndoableGroup { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.command.impl.UndoableGroup"); @@ -99,19 +98,13 @@ class UndoableGroup { } private void undoOrRedo(boolean isUndo) { - LocalHistoryAction action = LocalHistoryAction.NULL; - - if (myProject != null) { - if (isGlobal()) { - final String actionName; - if (isUndo) { - actionName = CommonBundle.message("local.vcs.action.name.undo.command", myCommandName); - } - else { - actionName = CommonBundle.message("local.vcs.action.name.redo.command", myCommandName); - } - action = LocalHistory.getInstance().startAction(actionName); - } + LocalHistoryAction action; + if (myProject != null && isGlobal()) { + String actionName = CommonBundle.message(isUndo ? "local.vcs.action.name.undo.command" : "local.vcs.action.name.redo.command", myCommandName); + action = LocalHistory.getInstance().startAction(actionName); + } + else { + action = LocalHistoryAction.NULL; } try { @@ -122,8 +115,35 @@ class UndoableGroup { } } + private static void doInBulkMode(@NotNull final Runnable action, @NotNull Collection documents) { + Runnable runnable = action; + for (final DocumentEx document : documents) { + final Runnable oldRunnable = runnable; + runnable = new Runnable() { + @Override + public void run() { + doInBulkMode(oldRunnable, document); + } + }; + } + runnable.run(); + } + private static void doInBulkMode(@NotNull Runnable action, @NotNull DocumentEx document) { + boolean wasInBulkUpdate = document.isInBulkUpdate(); + document.setInBulkUpdate(true); + try { + action.run(); + } + finally { + if (!wasInBulkUpdate) { + document.setInBulkUpdate(false); + } + } + } + + private void doUndoOrRedo(final boolean isUndo) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { + Runnable runnable = new Runnable() { public void run() { try { for (UndoableAction each : isUndo ? ContainerUtil.iterateBackward(myActions) : myActions) { @@ -139,7 +159,27 @@ class UndoableGroup { reportUndoProblem(e, isUndo); } } - }); + }; + if (myActions.size() > 50) { + final Collection documents = new THashSet(); + for (UndoableAction action : myActions) { + DocumentReference[] affectedDocuments = action.getAffectedDocuments(); + if (affectedDocuments != null) { + for (DocumentReference affectedDocument : affectedDocuments) { + documents.add((DocumentEx)affectedDocument.getDocument()); + } + } + } + final Runnable oldRunnable = runnable; + runnable = new Runnable() { + @Override + public void run() { + doInBulkMode(oldRunnable, documents); + } + }; + } + + ApplicationManager.getApplication().runWriteAction(runnable); commitAllDocuments(); } @@ -207,9 +247,8 @@ class UndoableGroup { } public boolean shouldAskConfirmation() { - if (myConfirmationPolicy == UndoConfirmationPolicy.REQUEST_CONFIRMATION) return true; - if (myConfirmationPolicy == UndoConfirmationPolicy.DO_NOT_REQUEST_CONFIRMATION) return false; - return myGlobal; + return myConfirmationPolicy == UndoConfirmationPolicy.REQUEST_CONFIRMATION || + myConfirmationPolicy != UndoConfirmationPolicy.DO_NOT_REQUEST_CONFIRMATION && myGlobal; } public void invalidateActionsFor(DocumentReference ref) {