mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-28 20:26:57 -06:00
Undo: a caught panic leaves the outer command's undo step (#406)
After a panic the guard said that no undoable command is running. A command that ran the one that panicked and carried on then had each later command it ran record an undo step of its own. The guard now puts that back to what it was when the command started.
This commit is contained in:
@@ -36,6 +36,7 @@ impl Session {
|
||||
/// Run command `id` (`f`) inside the guard.
|
||||
pub(crate) fn guarded(&mut self, id: &str, f: impl FnOnce(&mut Session) -> Result<Value>) -> Result<Value> {
|
||||
let before = self.active().map(|d| (d.uid, d.doc.clone(), d.selection.clone(), d.revision));
|
||||
let in_undo_step = self.in_undo_step;
|
||||
match catch_unwind(AssertUnwindSafe(|| f(self))) {
|
||||
Ok(r) => r,
|
||||
Err(payload) => {
|
||||
@@ -54,8 +55,8 @@ impl Session {
|
||||
{
|
||||
log::error!("crash recovery save after `{id}` failed: {e}");
|
||||
}
|
||||
// The command never got to say that it is done.
|
||||
self.in_undo_step = false;
|
||||
// The command never got to say that it is done; a command that ran it goes on.
|
||||
self.in_undo_step = in_undo_step;
|
||||
log::error!("command `{id}` panicked: {msg}");
|
||||
Err(EngineError::Internal(id.to_string(), msg))
|
||||
}
|
||||
@@ -103,4 +104,24 @@ mod tests {
|
||||
s.execute("frame.create", &json!({"rect": [36, 36, 200, 200]})).unwrap();
|
||||
assert_eq!(s.active().unwrap().history.undo.len(), 1);
|
||||
}
|
||||
|
||||
/// A command that panics inside an undoable one leaves that one running: what it runs next
|
||||
/// is still part of its undo step.
|
||||
#[test]
|
||||
fn a_panic_in_a_command_run_by_another_leaves_the_outer_undo_step() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({})).unwrap();
|
||||
// An undoable command that runs one that panics, carries on and runs another.
|
||||
s.guarded("test.outer", |s| {
|
||||
s.in_undo_step = true;
|
||||
assert!(s.guarded("test.panic", |_| panic!("boom")).is_err());
|
||||
let made = s.execute("frame.create", &json!({"rect": [36, 36, 200, 200]}));
|
||||
s.in_undo_step = false;
|
||||
made
|
||||
})
|
||||
.unwrap();
|
||||
let st = s.active().unwrap();
|
||||
assert_eq!(st.doc.spreads[0].items.len(), 1);
|
||||
assert_eq!(st.history.undo.len(), 0, "the frame is left to the outer command's step");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user