From dcd4d1d13f81d2da24cf703358858646eb2a7a1a Mon Sep 17 00:00:00 2001 From: justinjohn0306 Date: Mon, 19 Oct 2026 10:16:13 +0530 Subject: [PATCH] #1855: redo selects the redone cell Undo stored the selection at the moment of undoing (wherever the user had clicked) in the redo entry, so redo jumped back there instead of to the cells it changed. The redo entry now keeps the undone step's selection. Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/edit.rs | 3 ++- crates/engine/src/tests.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/edit.rs b/crates/engine/src/cmd/edit.rs index c69bac208..f2d0ca521 100644 --- a/crates/engine/src/cmd/edit.rs +++ b/crates/engine/src/cmd/edit.rs @@ -601,7 +601,8 @@ fn undo(s: &mut Session, p: &Json) -> Result { let now = d.wb.clone(); for _ in 0..steps { let Some(e) = d.undo.pop() else { break }; - let cur = crate::HistoryEntry { label: e.label.clone(), wb: d.wb.clone(), selection: d.selection.clone() }; + // Redo goes back to the undone edit's cells, not wherever the user clicked before undoing (#1855). + let cur = crate::HistoryEntry { label: e.label.clone(), wb: d.wb.clone(), selection: e.selection.clone() }; d.redo.push(cur); label = e.label.clone(); d.wb = e.wb; diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index ae499a189..513366848 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -253,6 +253,22 @@ fn undo_redo() { assert!(s.doc().unwrap().is_dirty()); } +#[test] +fn redo_selects_the_redone_cell() { + // #1855: type into A1..A3, click A1, undo, redo: the selection follows the edit to A3. + let mut s = s(); + for (cell, text) in [("A1", "first"), ("A2", "second"), ("A3", "third")] { + s.execute("selection.set", json!({"cell": cell})).unwrap(); + s.execute("cell.set", json!({"cell": cell, "input": text})).unwrap(); + } + s.execute("selection.set", json!({"cell": "A1"})).unwrap(); + s.execute("edit.undo", json!({})).unwrap(); + assert_eq!(s.doc().unwrap().selection.a1(), "A3"); + s.execute("edit.redo", json!({})).unwrap(); + assert_eq!(v(&s, "A3"), Value::from("third")); + assert_eq!(s.doc().unwrap().selection.a1(), "A3"); +} + #[test] fn shape_text_edit_undo_redo_and_noop() { let mut s = s();