From ebdabb907a5e286e4bdaff4c2e8486c3ddc75df3 Mon Sep 17 00:00:00 2001 From: Vishal Bhavsar Date: Wed, 31 Jan 2024 13:50:08 -0500 Subject: [PATCH] vim: Support counts for `H` and `L` motions (#7149) Release Notes: - Added support for counts to `H` and `L` motions ([#4941](https://github.com/zed-industries/zed/issues/4941)). --- crates/vim/src/motion.rs | 59 +++++++++++++++++--- crates/vim/test_data/test_window_bottom.json | 4 ++ crates/vim/test_data/test_window_top.json | 4 ++ 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index 22800b2e9c..944db88a7c 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -513,9 +513,9 @@ impl Motion { StartOfLineDownward => (next_line_start(map, point, times - 1), SelectionGoal::None), EndOfLineDownward => (next_line_end(map, point, times), SelectionGoal::None), GoToColumn => (go_to_column(map, point, times), SelectionGoal::None), - WindowTop => window_top(map, point, &text_layout_details), + WindowTop => window_top(map, point, &text_layout_details, times - 1), WindowMiddle => window_middle(map, point, &text_layout_details), - WindowBottom => window_bottom(map, point, &text_layout_details), + WindowBottom => window_bottom(map, point, &text_layout_details, times - 1), }; (new_point != point || infallible).then_some((new_point, goal)) @@ -1044,11 +1044,24 @@ fn window_top( map: &DisplaySnapshot, point: DisplayPoint, text_layout_details: &TextLayoutDetails, + times: usize, ) -> (DisplayPoint, SelectionGoal) { let first_visible_line = text_layout_details.anchor.to_display_point(map); - let new_col = point.column().min(map.line_len(first_visible_line.row())); - let new_point = DisplayPoint::new(first_visible_line.row(), new_col); - (map.clip_point(new_point, Bias::Left), SelectionGoal::None) + + if let Some(visible_rows) = text_layout_details.visible_rows { + let bottom_row = first_visible_line.row() + visible_rows as u32; + let new_row = (first_visible_line.row() + (times as u32)).min(bottom_row); + let new_col = point.column().min(map.line_len(first_visible_line.row())); + + let new_point = DisplayPoint::new(new_row, new_col); + (map.clip_point(new_point, Bias::Left), SelectionGoal::None) + } else { + let new_row = first_visible_line.row() + (times as u32); + let new_col = point.column().min(map.line_len(first_visible_line.row())); + + let new_point = DisplayPoint::new(new_row, new_col); + (map.clip_point(new_point, Bias::Left), SelectionGoal::None) + } } fn window_middle( @@ -1072,13 +1085,19 @@ fn window_bottom( map: &DisplaySnapshot, point: DisplayPoint, text_layout_details: &TextLayoutDetails, + times: usize, ) -> (DisplayPoint, SelectionGoal) { if let Some(visible_rows) = text_layout_details.visible_rows { let first_visible_line = text_layout_details.anchor.to_display_point(map); let bottom_row = first_visible_line.row() + (visible_rows) as u32; let bottom_row_capped = bottom_row.min(map.max_buffer_row()); - let new_col = point.column().min(map.line_len(bottom_row_capped)); - let new_point = DisplayPoint::new(bottom_row_capped, new_col); + let new_row = if bottom_row_capped.saturating_sub(times as u32) < first_visible_line.row() { + first_visible_line.row() + } else { + bottom_row_capped.saturating_sub(times as u32) + }; + let new_col = point.column().min(map.line_len(new_row)); + let new_point = DisplayPoint::new(new_row, new_col); (map.clip_point(new_point, Bias::Left), SelectionGoal::None) } else { (point, SelectionGoal::None) @@ -1302,6 +1321,18 @@ mod test { 7 8 9 "}) .await; + + cx.set_shared_state(indoc! {r" + 1 2 3 + 4 5 ˇ6 + 7 8 9"}) + .await; + cx.simulate_shared_keystrokes(["9", "shift-h"]).await; + cx.assert_shared_state(indoc! {r" + 1 2 3 + 4 5 6 + 7 8 ˇ9"}) + .await; } #[gpui::test] @@ -1466,5 +1497,19 @@ mod test { 7 8 9 ˇ"}) .await; + + cx.set_shared_state(indoc! {r" + 1 2 3 + 4 5 ˇ6 + 7 8 9 + "}) + .await; + cx.simulate_shared_keystrokes(["9", "shift-l"]).await; + cx.assert_shared_state(indoc! {r" + 1 2 ˇ3 + 4 5 6 + 7 8 9 + "}) + .await; } } diff --git a/crates/vim/test_data/test_window_bottom.json b/crates/vim/test_data/test_window_bottom.json index 50400883f2..a4855ccb96 100644 --- a/crates/vim/test_data/test_window_bottom.json +++ b/crates/vim/test_data/test_window_bottom.json @@ -13,3 +13,7 @@ {"Put":{"state":"ˇ1 2 3\n4 5 6\n7 8 9\n"}} {"Key":"shift-l"} {"Get":{"state":"1 2 3\n4 5 6\n7 8 9\nˇ","mode":"Normal"}} +{"Put":{"state":"1 2 3\n4 5 ˇ6\n7 8 9\n"}} +{"Key":"9"} +{"Key":"shift-l"} +{"Get":{"state":"1 2 ˇ3\n4 5 6\n7 8 9\n","mode":"Normal"}} diff --git a/crates/vim/test_data/test_window_top.json b/crates/vim/test_data/test_window_top.json index 607a26c110..aab6bd6280 100644 --- a/crates/vim/test_data/test_window_top.json +++ b/crates/vim/test_data/test_window_top.json @@ -7,3 +7,7 @@ {"Put":{"state":"1 2 3\n4 5 6\nˇ7 8 9\n"}} {"Key":"shift-h"} {"Get":{"state":"ˇ1 2 3\n4 5 6\n7 8 9\n","mode":"Normal"}} +{"Put":{"state":"1 2 3\n4 5 ˇ6\n7 8 9"}} +{"Key":"9"} +{"Key":"shift-h"} +{"Get":{"state":"1 2 3\n4 5 6\n7 8 ˇ9","mode":"Normal"}}