[rd-editor] IJPL-201535 Refactor UndoManagerImpl

GitOrigin-RevId: 530cef1022a380370a101070ab70f85dcb3afb36
This commit is contained in:
Alexander Trushev
2025-09-17 19:22:25 +00:00
committed by intellij-monorepo-bot
parent 469df27af9
commit cf0b1ecfab
4 changed files with 83 additions and 41 deletions
@@ -73,13 +73,13 @@ final class UndoClientState implements Disposable {
}
private UndoClientState(@NotNull UndoManagerImpl undoManager, @NotNull ClientId clientId) {
this.clientId = clientId;
this.project = undoManager.getProject();
this.undoSpy = undoManager.getUndoSpy();
this.isTransparentSupported = undoManager.isTransparentSupported();
this.isConfirmationSupported = undoManager.isConfirmationSupported();
this.isCompactSupported = undoManager.isCompactSupported();
this.isGlobalSplitSupported = undoManager.isGlobalSplitSupported();
this.clientId = clientId;
this.adjustableUndoableActionsHolder = undoManager.getAdjustableUndoableActionsHolder();
this.sharedUndoStacksHolder = undoManager.getSharedUndoStacksHolder();
this.sharedRedoStacksHolder = undoManager.getSharedRedoStacksHolder();
@@ -343,10 +343,7 @@ final class UndoClientState implements Disposable {
commandMerger.clearDocumentReferences(document);
}
@Nullable PerClientLocalUndoRedoSnapshot getUndoRedoSnapshotForDocument(
@NotNull DocumentReference reference,
@NotNull SharedAdjustableUndoableActionsHolder adjustableUndoableActionsHolder
) {
@Nullable PerClientLocalUndoRedoSnapshot getUndoRedoSnapshotForDocument(@NotNull DocumentReference reference) {
CommandMerger currentMerger = currentCommandMerger;
if (currentMerger != null && currentMerger.hasActions()) {
return null;
@@ -358,8 +355,7 @@ final class UndoClientState implements Disposable {
return new PerClientLocalUndoRedoSnapshot(
mergerSnapshot,
undoStacksHolder.getStack(reference).snapshot(),
redoStacksHolder.getStack(reference).snapshot(),
adjustableUndoableActionsHolder.getStack(reference).snapshot()
redoStacksHolder.getStack(reference).snapshot()
);
}
@@ -60,9 +60,7 @@ public class UndoManagerImpl extends UndoManager {
}
private final @Nullable Project myProject;
private final @NotNull SharedAdjustableUndoableActionsHolder myAdjustableUndoableActionsHolder;
private final @NotNull SharedUndoRedoStacksHolder mySharedUndoStacksHolder;
private final @NotNull SharedUndoRedoStacksHolder mySharedRedoStacksHolder;
private final @NotNull UndoSharedState myUndoSharedState;
private @Nullable CurrentEditorProvider myOverriddenEditorProvider;
@@ -80,9 +78,7 @@ public class UndoManagerImpl extends UndoManager {
@NonInjectable
protected UndoManagerImpl(@Nullable ComponentManager componentManager) {
myProject = componentManager instanceof Project project ? project : null;
myAdjustableUndoableActionsHolder = new SharedAdjustableUndoableActionsHolder();
mySharedUndoStacksHolder = new SharedUndoRedoStacksHolder(myAdjustableUndoableActionsHolder, isPerClientSupported(), true);
mySharedRedoStacksHolder = new SharedUndoRedoStacksHolder(myAdjustableUndoableActionsHolder, isPerClientSupported(), false);
myUndoSharedState = new UndoSharedState(isPerClientSupported());
}
@Override
@@ -272,8 +268,7 @@ public class UndoManagerImpl extends UndoManager {
for (UndoClientState state : getAllClientStates()) {
state.clearDocumentReferences(document);
}
mySharedUndoStacksHolder.clearDocumentReferences(document);
mySharedRedoStacksHolder.clearDocumentReferences(document);
myUndoSharedState.clearDocumentReferences(document);
}
@ApiStatus.Internal
@@ -345,11 +340,6 @@ public class UndoManagerImpl extends UndoManager {
return state.getStackSize(docRef, isUndo);
}
void trimSharedStacks(@NotNull DocumentReference docRef) {
mySharedRedoStacksHolder.trimStacks(Collections.singleton(docRef));
mySharedUndoStacksHolder.trimStacks(Collections.singleton(docRef));
}
@ApiStatus.Internal
protected void onCommandStarted(
@Nullable Project project,
@@ -391,36 +381,32 @@ public class UndoManagerImpl extends UndoManager {
}
@Nullable LocalUndoRedoSnapshot getUndoRedoSnapshotForDocument(@NotNull DocumentReference reference) {
HashMap<ClientId, PerClientLocalUndoRedoSnapshot> map = new HashMap<>();
var perClient = new HashMap<ClientId, PerClientLocalUndoRedoSnapshot>();
for (UndoClientState state : getAllClientStates()) {
PerClientLocalUndoRedoSnapshot perClientSnapshot = state.getUndoRedoSnapshotForDocument(reference, myAdjustableUndoableActionsHolder);
PerClientLocalUndoRedoSnapshot perClientSnapshot = state.getUndoRedoSnapshotForDocument(reference);
if (perClientSnapshot == null) {
return null;
}
map.put(state.getClientId(), perClientSnapshot);
perClient.put(state.getClientId(), perClientSnapshot);
}
return new LocalUndoRedoSnapshot(
map,
mySharedUndoStacksHolder.getStack(reference).snapshot(),
mySharedRedoStacksHolder.getStack(reference).snapshot()
Collections.unmodifiableMap(perClient),
myUndoSharedState.getSharedUndoRedoSnapshot(reference)
);
}
boolean resetLocalHistory(DocumentReference reference, LocalUndoRedoSnapshot snapshot) {
boolean resetLocalHistory(@NotNull DocumentReference reference, @NotNull LocalUndoRedoSnapshot snapshot) {
for (UndoClientState state : getAllClientStates()) {
PerClientLocalUndoRedoSnapshot perClientSnapshot = snapshot.getClientSnapshots().get(state.getClientId());
if (perClientSnapshot == null) {
perClientSnapshot = PerClientLocalUndoRedoSnapshot.empty();
}
boolean success = state.resetLocalHistory(reference, perClientSnapshot);
if (success) {
myAdjustableUndoableActionsHolder.getStack(reference).resetTo(perClientSnapshot.getActionsHolderSnapshot());
} else {
if (!success) {
return false;
}
}
mySharedUndoStacksHolder.getStack(reference).resetTo(snapshot.getSharedUndoStack());
mySharedRedoStacksHolder.getStack(reference).resetTo(snapshot.getSharedRedoStack());
myUndoSharedState.resetLocalHistory(reference, snapshot.getSharedSnapshot());
return true;
}
@@ -430,15 +416,15 @@ public class UndoManagerImpl extends UndoManager {
}
@NotNull SharedAdjustableUndoableActionsHolder getAdjustableUndoableActionsHolder() {
return myAdjustableUndoableActionsHolder;
return myUndoSharedState.getAdjustableActions();
}
@NotNull SharedUndoRedoStacksHolder getSharedUndoStacksHolder() {
return mySharedUndoStacksHolder;
return myUndoSharedState.getUndoStacks();
}
@NotNull SharedUndoRedoStacksHolder getSharedRedoStacksHolder() {
return mySharedRedoStacksHolder;
return myUndoSharedState.getRedoStacks();
}
@TestOnly
@@ -469,7 +455,7 @@ public class UndoManagerImpl extends UndoManager {
if (state != null) {
DocumentReference docRef = DocumentReferenceManager.getInstance().create(file);
state.clearUndoRedoQueue(docRef);
trimSharedStacks(docRef);
myUndoSharedState.trimSharedStacks(docRef);
}
}
@@ -479,7 +465,7 @@ public class UndoManagerImpl extends UndoManager {
if (state != null) {
DocumentReference docRef = DocumentReferenceManager.getInstance().create(document);
state.clearUndoRedoQueue(docRef);
trimSharedStacks(docRef);
myUndoSharedState.trimSharedStacks(docRef);
}
}
@@ -43,17 +43,21 @@ internal class LocalCommandMergerSnapshot(
}
}
internal class LocalUndoRedoSnapshot(
val clientSnapshots: Map<ClientId, PerClientLocalUndoRedoSnapshot>,
internal class SharedUndoRedoSnapshot(
val actionsHolderSnapshot: UndoRedoSetSnapshot<AdjustableUndoableAction>,
val sharedUndoStack: UndoRedoListSnapshot<ImmutableActionChangeRange>,
val sharedRedoStack: UndoRedoListSnapshot<ImmutableActionChangeRange>,
)
internal class LocalUndoRedoSnapshot(
val clientSnapshots: Map<ClientId, PerClientLocalUndoRedoSnapshot>,
val sharedSnapshot: SharedUndoRedoSnapshot,
)
internal class PerClientLocalUndoRedoSnapshot(
val localCommandMergerSnapshot: LocalCommandMergerSnapshot,
val undoStackSnapshot: UndoRedoListSnapshot<UndoableGroup>,
val redoStackSnapshot: UndoRedoListSnapshot<UndoableGroup>,
val actionsHolderSnapshot: UndoRedoSetSnapshot<AdjustableUndoableAction>,
) {
companion object {
@JvmStatic
@@ -61,7 +65,6 @@ internal class PerClientLocalUndoRedoSnapshot(
LocalCommandMergerSnapshot.empty(),
UndoRedoList<UndoableGroup>().snapshot(),
UndoRedoList<UndoableGroup>().snapshot(),
UndoRedoSet<AdjustableUndoableAction>().snapshot(),
)
}
}
@@ -0,0 +1,57 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.command.impl;
import com.intellij.openapi.command.undo.DocumentReference;
import com.intellij.openapi.editor.Document;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
final class UndoSharedState {
private final @NotNull SharedAdjustableUndoableActionsHolder adjustableActions;
private final @NotNull SharedUndoRedoStacksHolder undoStacks;
private final @NotNull SharedUndoRedoStacksHolder redoStacks;
UndoSharedState(boolean isPerClientSupported) {
adjustableActions = new SharedAdjustableUndoableActionsHolder();
undoStacks = new SharedUndoRedoStacksHolder(adjustableActions, isPerClientSupported, true);
redoStacks = new SharedUndoRedoStacksHolder(adjustableActions, isPerClientSupported, false);
}
@NotNull SharedUndoRedoSnapshot getSharedUndoRedoSnapshot(@NotNull DocumentReference reference) {
return new SharedUndoRedoSnapshot(
adjustableActions.getStack(reference).snapshot(),
undoStacks.getStack(reference).snapshot(),
redoStacks.getStack(reference).snapshot()
);
}
void resetLocalHistory(@NotNull DocumentReference reference, @NotNull SharedUndoRedoSnapshot snapshot) {
adjustableActions.getStack(reference).resetTo(snapshot.getActionsHolderSnapshot());
undoStacks.getStack(reference).resetTo(snapshot.getSharedUndoStack());
redoStacks.getStack(reference).resetTo(snapshot.getSharedRedoStack());
}
void clearDocumentReferences(@NotNull Document document) {
undoStacks.clearDocumentReferences(document);
redoStacks.clearDocumentReferences(document);
}
void trimSharedStacks(@NotNull DocumentReference docRef) {
redoStacks.trimStacks(Collections.singleton(docRef));
undoStacks.trimStacks(Collections.singleton(docRef));
}
@NotNull SharedAdjustableUndoableActionsHolder getAdjustableActions() {
return adjustableActions;
}
@NotNull SharedUndoRedoStacksHolder getUndoStacks() {
return undoStacks;
}
@NotNull SharedUndoRedoStacksHolder getRedoStacks() {
return redoStacks;
}
}