From 0cf9476241e2e0e339bd3096ecbd3fae7aae7ffa Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Sat, 24 Oct 2026 23:01:27 +0200 Subject: [PATCH] Shift+Arrow on a whole column or row: still follow an extension that reaches the sheet's edge itself (#2451) --- crates/ui-egui/src/grid.rs | 8 +++--- crates/ui-egui/tests/it/selection_scroll.rs | 30 +++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/grid.rs b/crates/ui-egui/src/grid.rs index 09690eb94..db210480c 100644 --- a/crates/ui-egui/src/grid.rs +++ b/crates/ui-egui/src/grid.rs @@ -706,7 +706,9 @@ pub fn show(app: &mut SheetApp, ui: &mut egui::Ui) { let from = app.grid.reveal_from.take(); let target = app.editor.as_ref().and_then(|e| e.point_cell).unwrap_or(cell); // A whole column's moving end sits on the sheet's last row (a whole row's on its last - // column): extending it only moves across, so the view keeps its place the other way. + // column): when an extension moves it only across, the view keeps its place the other way. + // An extension that reaches the last row itself (Ctrl+Shift+Down past the data) still + // follows it. let extended = (moving && target == cell).then(|| sel.current()); let before = view.scroll; if paper { @@ -736,10 +738,10 @@ pub fn show(app: &mut SheetApp, ui: &mut egui::Ui) { } else if from.is_some_and(|f| f.col >= geo.fc) { view.scroll.x = 0.0; } - if extended.is_some_and(|r| r.is_full_cols()) { + if extended.is_some_and(|r| r.is_full_cols()) && from.is_some_and(|f| f.row == cell.row) { view.scroll.y = before.y; } - if extended.is_some_and(|r| r.is_full_rows()) { + if extended.is_some_and(|r| r.is_full_rows()) && from.is_some_and(|f| f.col == cell.col) { view.scroll.x = before.x; } view.scroll = view.scroll.max(egui::Vec2::ZERO); diff --git a/crates/ui-egui/tests/it/selection_scroll.rs b/crates/ui-egui/tests/it/selection_scroll.rs index 97f4d3c17..c143d378c 100644 --- a/crates/ui-egui/tests/it/selection_scroll.rs +++ b/crates/ui-egui/tests/it/selection_scroll.rs @@ -334,3 +334,33 @@ fn shift_arrows_on_a_whole_row_leave_the_columns_where_they_are() { assert!(visible(&h, "CA62") && !visible(&h, "CA1")); assert_eq!(scroll(&h).x, right); } + +#[test] +fn ctrl_shift_down_past_the_data_to_the_whole_column_still_follows_the_moving_end() { + // The second Ctrl+Shift+Down from A1 runs past A200 to the last row: the selection becomes the + // whole column, and the view still follows its moving end down the sheet. + let mut h = harness(); + key(&mut h, Key::ArrowDown, CTRL_SHIFT); + assert_extended(&h, "A1", "A200"); + let at_200 = scroll(&h).y; + key(&mut h, Key::ArrowDown, CTRL_SHIFT); + assert_eq!(h.state().session.active().unwrap().selection.current(), RangeRef::parse("A:A").unwrap()); + assert!(scroll(&h).y > at_200, "the view follows the extension to the last row"); +} + +#[test] +fn ctrl_shift_right_on_a_whole_column_follows_across_and_keeps_the_rows() { + // Ctrl+Space then Ctrl+Shift+Right selects every column: the view follows the moving end to + // the last column and stays on the rows it showed. + let mut h = harness(); + h.state_mut().session.execute("selection.set", json!({"cell": "A100"})).unwrap(); + h.state_mut().grid.ensure_visible = true; + h.run_steps(2); + let down = scroll(&h).y; + h.state_mut().session.execute("selection.column", json!({})).unwrap(); + h.run_steps(2); + key(&mut h, Key::ArrowRight, CTRL_SHIFT); + assert_eq!(h.state().session.active().unwrap().selection.current(), RangeRef::parse("A:XFD").unwrap()); + assert!(scroll(&h).x > 0.0, "the view follows the extension across"); + assert_eq!(scroll(&h).y, down, "the view stays on the rows it showed"); +}