Merge #301: Keep the redo steps when a failed command batch rolls back (#196) (@MarekSpodBiedry)

This commit is contained in:
bflatastic
2026-10-15 17:52:54 +07:00
2 changed files with 26 additions and 1 deletions
+22
View File
@@ -61,3 +61,25 @@ fn failed_plugin_run_restores_each_document_without_restoring_unrelated_state()
assert_eq!(s.journal, before_journal);
assert_eq!(s.message, before_message);
}
#[test]
fn failed_group_keeps_the_redo_steps() {
let mut s = Session::new();
s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap();
assert!(s.undo().unwrap());
assert_eq!(s.undo_depth().1, 1);
let result = s.execute(
"command.batch",
&json!({
"commands": [
{"command": "shape.rectangle", "params": {"x": 20, "y": 20, "width": 10, "height": 10}},
{"command": "node.set", "params": {"id": 999999, "props": {"name": "must fail"}}}
]
}),
);
assert!(result.is_err());
assert_eq!(s.undo_depth().1, 1, "the redo step survives the failed batch");
assert!(s.redo().unwrap());
}
+4 -1
View File
@@ -1091,6 +1091,8 @@ impl Session {
self.ds()?;
let before: Vec<_> =
self.docs.iter().map(|ds| (ds.uid, ds.doc.clone(), ds.selection.clone(), ds.page, ds.history.undo.len(), ds.history.limit)).collect();
// An edit inside clears the redo steps; a failed group has to bring them back.
let redo_before: Vec<_> = self.docs.iter().map(|ds| ds.history.redo.clone()).collect();
let active = self.active;
let journal_len = self.journal.len();
@@ -1108,8 +1110,9 @@ impl Session {
if result.is_err() {
self.docs.retain(|ds| before.iter().any(|(uid, _, _, _, _, _)| *uid == ds.uid));
for (uid, doc, selection, page, undo_len, limit) in &before {
for ((uid, doc, selection, page, undo_len, limit), redo) in before.iter().zip(redo_before) {
if let Some(ds) = self.docs.iter_mut().find(|ds| ds.uid == *uid) {
ds.history.redo = redo;
ds.doc = doc.clone();
ds.selection = selection.clone();
ds.page = *page;