diff --git a/crates/vim/src/normal/change.rs b/crates/vim/src/normal/change.rs index 4735c64792..b0b0bddae1 100644 --- a/crates/vim/src/normal/change.rs +++ b/crates/vim/src/normal/change.rs @@ -121,7 +121,11 @@ impl Vim { }); }); if objects_found { - vim.copy_selections_content(editor, MotionKind::Exclusive, window, cx); + let kind = match object.target_visual_mode(vim.mode, around) { + Mode::VisualLine => MotionKind::Linewise, + _ => MotionKind::Exclusive, + }; + vim.copy_selections_content(editor, kind, window, cx); editor.insert("", window, cx); editor.refresh_edit_prediction(true, false, window, cx); } diff --git a/crates/vim/src/normal/yank.rs b/crates/vim/src/normal/yank.rs index d5a45fca54..71ed0d4438 100644 --- a/crates/vim/src/normal/yank.rs +++ b/crates/vim/src/normal/yank.rs @@ -81,7 +81,11 @@ impl Vim { start_positions.insert(selection.id, start_position); }); }); - vim.yank_selections_content(editor, MotionKind::Exclusive, window, cx); + let kind = match object.target_visual_mode(vim.mode, around) { + Mode::VisualLine => MotionKind::Linewise, + _ => MotionKind::Exclusive, + }; + vim.yank_selections_content(editor, kind, window, cx); editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(|_, selection| { let (head, goal) = start_positions.remove(&selection.id).unwrap(); diff --git a/crates/vim/src/test.rs b/crates/vim/src/test.rs index 5932a74094..4294b5e1db 100644 --- a/crates/vim/src/test.rs +++ b/crates/vim/src/test.rs @@ -2253,6 +2253,79 @@ async fn test_paragraph_multi_delete(cx: &mut gpui::TestAppContext) { cx.shared_state().await.assert_eq(indoc! {"ˇ"}); } +#[perf] +#[gpui::test] +async fn test_yank_paragraph_with_paste(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + cx.set_shared_state(indoc! { + " + first paragraph + ˇstill first + + second paragraph + still second + + third paragraph + " + }) + .await; + + cx.simulate_shared_keystrokes("y a p").await; + cx.shared_clipboard() + .await + .assert_eq("first paragraph\nstill first\n\n"); + + cx.simulate_shared_keystrokes("j j p").await; + cx.shared_state().await.assert_eq(indoc! { + " + first paragraph + still first + + ˇfirst paragraph + still first + + second paragraph + still second + + third paragraph + " + }); +} + +#[perf] +#[gpui::test] +async fn test_change_paragraph(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + cx.set_shared_state(indoc! { + " + first paragraph + ˇstill first + + second paragraph + still second + + third paragraph + " + }) + .await; + + cx.simulate_shared_keystrokes("c a p").await; + cx.shared_clipboard() + .await + .assert_eq("first paragraph\nstill first\n\n"); + + cx.simulate_shared_keystrokes("escape").await; + cx.shared_state().await.assert_eq(indoc! { + " + ˇ + second paragraph + still second + + third paragraph + " + }); +} + #[perf] #[gpui::test] async fn test_multi_cursor_replay(cx: &mut gpui::TestAppContext) { diff --git a/crates/vim/test_data/test_change_paragraph.json b/crates/vim/test_data/test_change_paragraph.json new file mode 100644 index 0000000000..6d235d9f36 --- /dev/null +++ b/crates/vim/test_data/test_change_paragraph.json @@ -0,0 +1,8 @@ +{"Put":{"state":"first paragraph\nˇstill first\n\nsecond paragraph\nstill second\n\nthird paragraph\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"p"} +{"Get":{"state":"ˇ\nsecond paragraph\nstill second\n\nthird paragraph\n","mode":"Insert"}} +{"ReadRegister":{"name":"\"","value":"first paragraph\nstill first\n\n"}} +{"Key":"escape"} +{"Get":{"state":"ˇ\nsecond paragraph\nstill second\n\nthird paragraph\n","mode":"Normal"}} diff --git a/crates/vim/test_data/test_yank_paragraph_with_paste.json b/crates/vim/test_data/test_yank_paragraph_with_paste.json new file mode 100644 index 0000000000..d73d1f6d3b --- /dev/null +++ b/crates/vim/test_data/test_yank_paragraph_with_paste.json @@ -0,0 +1,10 @@ +{"Put":{"state":"first paragraph\nˇstill first\n\nsecond paragraph\nstill second\n\nthird paragraph\n"}} +{"Key":"y"} +{"Key":"a"} +{"Key":"p"} +{"Get":{"state":"ˇfirst paragraph\nstill first\n\nsecond paragraph\nstill second\n\nthird paragraph\n","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"first paragraph\nstill first\n\n"}} +{"Key":"j"} +{"Key":"j"} +{"Key":"p"} +{"Get":{"state":"first paragraph\nstill first\n\nˇfirst paragraph\nstill first\n\nsecond paragraph\nstill second\n\nthird paragraph\n","mode":"Normal"}}