From ebed567adbb0cde7f63a830ef295df5cb91d2577 Mon Sep 17 00:00:00 2001 From: Dino Date: Mon, 2 Jun 2025 08:50:13 -0700 Subject: [PATCH] vim: Handle paste in visual line mode when cursor is at newline (#30791) This Pull Request fixes the current paste behavior in vim mode, when in visual mode, and the cursor is at a newline character. Currently this joins the pasted contents with the line right below it, but in vim this does not happen, so these changes make it so that Zed's vim mode behaves the same as vim for this specific case. Closes #29270 Release Notes: - Fixed pasting in vim's visual line mode when cursor is on a newline character --- crates/vim/src/normal/paste.rs | 26 ++++++++++++++++++++- crates/vim/test_data/test_paste_visual.json | 8 +++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/vim/src/normal/paste.rs b/crates/vim/src/normal/paste.rs index 68b0acefac..f16f442705 100644 --- a/crates/vim/src/normal/paste.rs +++ b/crates/vim/src/normal/paste.rs @@ -124,7 +124,20 @@ impl Vim { } let display_range = if !selection.is_empty() { - selection.start..selection.end + // If vim is in VISUAL LINE mode and the column for the + // selection's end point is 0, that means that the + // cursor is at the newline character (\n) at the end of + // the line. In this situation we'll want to move one + // position to the left, ensuring we don't join the last + // line of the selection with the line directly below. + let end_point = + if vim.mode == Mode::VisualLine && selection.end.column() == 0 { + movement::left(&display_map, selection.end) + } else { + selection.end + }; + + selection.start..end_point } else if line_mode { let point = if before { movement::line_beginning(&display_map, selection.start, false) @@ -553,6 +566,17 @@ mod test { ˇfox jumps over the lazy dog"}); cx.shared_clipboard().await.assert_eq("The quick brown\n"); + + // Copy line and paste in visual mode, with cursor on newline character. + cx.set_shared_state(indoc! {" + ˇThe quick brown + fox jumps over + the lazy dog"}) + .await; + cx.simulate_shared_keystrokes("y y shift-v j $ p").await; + cx.shared_state().await.assert_eq(indoc! {" + ˇThe quick brown + the lazy dog"}); } #[gpui::test] diff --git a/crates/vim/test_data/test_paste_visual.json b/crates/vim/test_data/test_paste_visual.json index c5597ba0f3..fb10f94782 100644 --- a/crates/vim/test_data/test_paste_visual.json +++ b/crates/vim/test_data/test_paste_visual.json @@ -41,3 +41,11 @@ {"Key":"p"} {"Get":{"state":"ˇfox jumps over\nthe lazy dog","mode":"Normal"}} {"ReadRegister":{"name":"\"","value":"The quick brown\n"}} +{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"y"} +{"Key":"y"} +{"Key":"shift-v"} +{"Key":"j"} +{"Key":"$"} +{"Key":"p"} +{"Get":{"state":"ˇThe quick brown\nthe lazy dog","mode":"Normal"}}