From 7fb954909832115e0bd0412bd25ce620ffc2d352 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Tue, 5 Nov 2024 14:47:14 +0100 Subject: [PATCH] vim: Fix `d shift-g` not deleting until EOD if soft-wrap is on (#20160) This previously didn't work: `d G` would delete to the end of the "first of the soft-wrapped lines" of the last line. To fix it, we special case the delete behavior for `shift-g`, which is what Neovim also seems to do. Release Notes: - Fixed `d G` in Vim mode not deleting until the actual end of the document if soft-wrap is turned on. --- crates/vim/src/normal/delete.rs | 41 +++++++++++-------- crates/vim/src/test.rs | 18 ++++++++ .../test_wrapped_delete_end_document.json | 10 +++++ 3 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 crates/vim/test_data/test_wrapped_delete_end_document.json diff --git a/crates/vim/src/normal/delete.rs b/crates/vim/src/normal/delete.rs index 9dab839c7b..fee2ef56e1 100644 --- a/crates/vim/src/normal/delete.rs +++ b/crates/vim/src/normal/delete.rs @@ -28,25 +28,30 @@ impl Vim { original_columns.insert(selection.id, original_head.column()); motion.expand_selection(map, selection, times, true, &text_layout_details); - // Motion::NextWordStart on an empty line should delete it. - if let Motion::NextWordStart { - ignore_punctuation: _, - } = motion - { - if selection.is_empty() - && map - .buffer_snapshot - .line_len(MultiBufferRow(selection.start.to_point(map).row)) - == 0 - { - selection.end = map - .buffer_snapshot - .clip_point( - Point::new(selection.start.to_point(map).row + 1, 0), - Bias::Left, - ) - .to_display_point(map) + match motion { + // Motion::NextWordStart on an empty line should delete it. + Motion::NextWordStart { .. } => { + if selection.is_empty() + && map + .buffer_snapshot + .line_len(MultiBufferRow(selection.start.to_point(map).row)) + == 0 + { + selection.end = map + .buffer_snapshot + .clip_point( + Point::new(selection.start.to_point(map).row + 1, 0), + Bias::Left, + ) + .to_display_point(map) + } } + Motion::EndOfDocument {} => { + // Deleting until the end of the document includes the last line, including + // soft-wrapped lines. + selection.end = map.max_point() + } + _ => {} } }); }); diff --git a/crates/vim/src/test.rs b/crates/vim/src/test.rs index 9cb0b79ec5..6573959c66 100644 --- a/crates/vim/src/test.rs +++ b/crates/vim/src/test.rs @@ -730,6 +730,24 @@ async fn test_wrapped_motions(cx: &mut gpui::TestAppContext) { }); } +#[gpui::test] +async fn test_wrapped_delete_end_document(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_wrap(12).await; + + cx.set_shared_state(indoc! {" + aaˇaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccc" + }) + .await; + cx.simulate_shared_keystrokes("d shift-g i z z z").await; + cx.shared_state().await.assert_eq(indoc! {" + zzzˇ" + }); +} + #[gpui::test] async fn test_paragraphs_dont_wrap(cx: &mut gpui::TestAppContext) { let mut cx = NeovimBackedTestContext::new(cx).await; diff --git a/crates/vim/test_data/test_wrapped_delete_end_document.json b/crates/vim/test_data/test_wrapped_delete_end_document.json new file mode 100644 index 0000000000..f1dc0cb238 --- /dev/null +++ b/crates/vim/test_data/test_wrapped_delete_end_document.json @@ -0,0 +1,10 @@ +{"SetOption":{"value":"wrap"}} +{"SetOption":{"value":"columns=12"}} +{"Put":{"state":"aaˇaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbb\ncccccccccccccccccccc"}} +{"Key":"d"} +{"Key":"shift-g"} +{"Key":"i"} +{"Key":"z"} +{"Key":"z"} +{"Key":"z"} +{"Get":{"state":"zzzˇ","mode":"Insert"}}