diff --git a/crates/ui-egui/src/grid.rs b/crates/ui-egui/src/grid.rs index ab434f7..316714c 100644 --- a/crates/ui-egui/src/grid.rs +++ b/crates/ui-egui/src/grid.rs @@ -2724,7 +2724,17 @@ pub fn point_move(app: &mut SheetApp, ed: &mut EditState, dr: i64, dc: i64, exte let from = ed.point_cell.unwrap_or(ed.cell); let to = from.offset_clamped(dr, dc); let text = if extend { - let anchor = ed.point.and_then(|(s, e)| ed.text.get(s..e)).and_then(|t| CellRef::parse(t.split(':').next().unwrap_or(""))).unwrap_or(from); + // The anchor is the corner opposite the moving end: the written range is normalized, so + // after extending up or left its first cell is the moving end, not the anchor. + let pointed = ed.point.and_then(|(s, e)| ed.text.get(s..e)).and_then(RangeRef::parse); + let anchor = pointed + .map(|r| { + CellRef::new( + if from.row == r.start.row { r.end.row } else { r.start.row }, + if from.col == r.start.col { r.end.col } else { r.start.col }, + ) + }) + .unwrap_or(from); RangeRef::new(anchor, to).a1() } else { to.a1() diff --git a/crates/ui-egui/tests/interaction.rs b/crates/ui-egui/tests/interaction.rs index f5d7d3e..058d68b 100644 --- a/crates/ui-egui/tests/interaction.rs +++ b/crates/ui-egui/tests/interaction.rs @@ -191,6 +191,25 @@ fn arrows_escape_and_undo() { assert_eq!(value(&h, "B2"), Value::Empty); } +#[test] +fn shift_arrows_in_point_mode_extend_from_the_pointed_cell() { + let mut s = blank(); + s.execute("selection.set", json!({"cell": "A11"})).unwrap(); + let mut h = harness(s); + text(&mut h, "=SUM("); + key(&mut h, Key::ArrowUp, Modifiers::NONE); + let edited = |h: &egui_kittest::Harness<'static, SheetApp>| h.state().editor.as_ref().map(|e| e.text.clone()); + assert_eq!(edited(&h).as_deref(), Some("=SUM(A10")); + // Shift is held down, as on a real keyboard: the backend reports it before the arrow keys. + h.input_mut().events.push(Event::ModifiersChanged(Modifiers::SHIFT)); + for expected in ["=SUM(A9:A10", "=SUM(A8:A10", "=SUM(A7:A10"] { + key(&mut h, Key::ArrowUp, Modifiers::SHIFT); + assert_eq!(edited(&h).as_deref(), Some(expected)); + } + key(&mut h, Key::ArrowDown, Modifiers::SHIFT); + assert_eq!(edited(&h).as_deref(), Some("=SUM(A8:A10"), "Shift+Down shrinks back towards the anchor"); +} + #[test] fn shortcuts_format_and_extend() { let mut s = blank();