Restore the clipboard when a command fails and is rolled back (#1167)

Fixes #1100

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-24 05:24:29 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 8864e42dce
commit 9c0d1c19fe
2 changed files with 22 additions and 0 deletions
+3
View File
@@ -966,6 +966,8 @@ impl Session {
ds.end_preview();
}
let before = self.ds().ok().map(|d| (d.doc.clone(), d.selection.clone(), d.page, d.uid));
// Cut and copy write the clipboard before a later check can refuse the command.
let clipboard_before = self.clipboard.clone();
let result = guard::run(id, || (spec.run)(self, params))
.and_then(|v| self.check_instance_structure(id, &before).map(|()| v))
.and_then(|v| self.check_preview(id, &before).map(|()| v))
@@ -998,6 +1000,7 @@ impl Session {
ds.selection = sel;
ds.page = page;
}
self.clipboard = clipboard_before;
}
}
result
@@ -97,3 +97,22 @@ fn preview_keeps_the_unsaved_state_and_saving_saves_the_document() {
assert_eq!(count(&s), three);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn a_refused_cut_leaves_the_clipboard_as_it_was() {
let mut s = Session::new();
let a = rect(&mut s, 0.0);
s.execute("file.saveVersion", &json!({"name": "One"})).unwrap();
let b = rect(&mut s, 20.0);
s.execute("edit.copy", &json!({"ids": [b]})).unwrap();
let roots = |s: &Session| s.clipboard.nodes.iter().map(|(r, _)| *r).collect::<Vec<_>>();
assert_eq!(roots(&s), vec![b]);
let source = s.clipboard.source.clone().unwrap();
let depth = s.undo_depth();
s.execute("version.preview", &json!({"index": 0})).unwrap();
let err = s.execute("edit.cut", &json!({"ids": [a]})).unwrap_err();
assert!(matches!(err, EngineError::Disabled(..)), "{err:?}");
assert_eq!(roots(&s), vec![b], "failed edit.cut changed the clipboard");
assert!(std::sync::Arc::ptr_eq(s.clipboard.source.as_ref().unwrap(), &source));
assert_eq!(s.undo_depth(), depth, "history untouched");
}