From 4db6876c0726e1f0137454e9cee20d867a21ca4d Mon Sep 17 00:00:00 2001 From: justinjohn0306 Date: Mon, 19 Oct 2026 08:59:49 +0530 Subject: [PATCH] #1855: Backspace then Enter is one undo step Backspace clears the cell (edit.clearContents) and opens an empty editor. Committing that editor ran cell.set "" on the already-empty cell, which recorded a second, empty undo step, so Ctrl+Z appeared to do nothing and the next Ctrl+Z undid an unrelated earlier edit. Committing empty text into an empty cell now runs no command. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/lib.rs | 14 +++++++++++++- crates/ui-egui/tests/interaction.rs | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index f96cdac3c..2cbf0510f 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -929,7 +929,19 @@ impl SheetApp { } self.toast = Some((msg, now_ms())); } - let r = if fill_selection { + // Committing nothing into an empty cell changes nothing: no undo step (#1855, Backspace has + // already cleared the cell as its own step). + let unchanged = !fill_selection + && !array + && text.is_empty() + && self + .session + .active() + .and_then(|d| d.wb.sheet(ed.sheet)) + .is_some_and(|sh| sh.cell(ed.cell).is_none_or(|c| c.formula.is_none() && c.value == gridcraft_engine::core::Value::Empty)); + let r = if unchanged { + Ok(json!({})) + } else if fill_selection { self.session.run("range.fill", json!({"input": text})) } else { self.session.run("cell.set", json!({"cell": ed.cell.a1(), "input": text, "array": array})) diff --git a/crates/ui-egui/tests/interaction.rs b/crates/ui-egui/tests/interaction.rs index b40769cf8..02084ffb8 100644 --- a/crates/ui-egui/tests/interaction.rs +++ b/crates/ui-egui/tests/interaction.rs @@ -892,3 +892,22 @@ fn rotated_wrapped_text_is_drawn_rotated_inside_its_cell() { assert!(clip.width() < 70.0, "clip spans one 6-character column, got {clip:?}"); } } + +#[test] +fn undo_after_backspace_restores_the_cleared_cell() { + // #1855: Backspace clears the cell and opens an empty editor; committing it must not add a + // second, empty undo step, so one Ctrl+Z brings the value back and leaves other edits alone. + let mut h = harness(blank()); + text(&mut h, "3200"); + key(&mut h, Key::Enter, Modifiers::NONE); + click_cell(&mut h, "C5"); + text(&mut h, "11750"); + key(&mut h, Key::Enter, Modifiers::NONE); + click_cell(&mut h, "A1"); + key(&mut h, Key::Backspace, Modifiers::NONE); + key(&mut h, Key::Enter, Modifiers::NONE); + assert_eq!(value(&h, "A1"), Value::Empty); + key(&mut h, Key::Z, Modifiers::COMMAND); + assert_eq!(value(&h, "A1"), Value::Number(3200.0)); + assert_eq!(value(&h, "C5"), Value::Number(11750.0)); +}