Add YankEndOfLine action (#39143)

David Kleingeld created

Since 2021 Neovim remaps Y to $y (1). DO the same in zed through a new action `YankToEndOfLine`. 

1: https://github.com/neovim/neovim/pull/13268

Release Notes:

- Added vim::YankToEndOfLine action which copies from the cursor to the end of the line excluding the newline. We bind it to Y by default in the vim keymap.

Change summary

assets/keymaps/vim.json                            |  3 +
crates/vim/src/normal.rs                           | 30 ++++++++++++++++
crates/vim/test_data/test_yank_to_end_of_line.json |  4 ++
3 files changed, 36 insertions(+), 1 deletion(-)

Detailed changes

assets/keymaps/vim.json 🔗

@@ -240,6 +240,7 @@
       "delete": "vim::DeleteRight",
       "g shift-j": "vim::JoinLinesNoWhitespace",
       "y": "vim::PushYank",
+      "shift-y": "vim::YankToEndOfLine",
       "x": "vim::DeleteRight",
       "shift-x": "vim::DeleteLeft",
       "ctrl-a": "vim::Increment",
@@ -392,7 +393,7 @@
       "escape": "editor::Cancel",
       "shift-d": "vim::DeleteToEndOfLine",
       "shift-j": "vim::JoinLines",
-      "shift-y": "vim::YankLine",
+      "shift-y": "vim::YankToEndOfLine",
       "shift-i": "vim::InsertFirstNonWhitespace",
       "shift-a": "vim::InsertEndOfLine",
       "o": "vim::InsertLineBelow",

crates/vim/src/normal.rs 🔗

@@ -74,6 +74,8 @@ actions!(
         Yank,
         /// Yanks the entire line.
         YankLine,
+        /// Yanks from cursor to end of line.
+        YankToEndOfLine,
         /// Toggles the case of selected text.
         ChangeCase,
         /// Converts selected text to uppercase.
@@ -117,6 +119,7 @@ pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
     Vim::action(editor, cx, Vim::convert_to_rot13);
     Vim::action(editor, cx, Vim::convert_to_rot47);
     Vim::action(editor, cx, Vim::yank_line);
+    Vim::action(editor, cx, Vim::yank_to_end_of_line);
     Vim::action(editor, cx, Vim::toggle_comments);
     Vim::action(editor, cx, Vim::paste);
     Vim::action(editor, cx, Vim::show_location);
@@ -843,6 +846,25 @@ impl Vim {
         )
     }
 
+    fn yank_to_end_of_line(
+        &mut self,
+        _: &YankToEndOfLine,
+        window: &mut Window,
+        cx: &mut Context<Self>,
+    ) {
+        let count = Vim::take_count(cx);
+        let forced_motion = Vim::take_forced_motion(cx);
+        self.yank_motion(
+            motion::Motion::EndOfLine {
+                display_lines: false,
+            },
+            count,
+            forced_motion,
+            window,
+            cx,
+        )
+    }
+
     fn show_location(&mut self, _: &ShowLocation, _: &mut Window, cx: &mut Context<Self>) {
         let count = Vim::take_count(cx);
         Vim::take_forced_motion(cx);
@@ -1978,6 +2000,14 @@ mod test {
         cx.shared_state().await.assert_eq("// hello\n// ˇ\n// x\n");
     }
 
+    #[gpui::test]
+    async fn test_yank_to_end_of_line(cx: &mut gpui::TestAppContext) {
+        let mut cx = NeovimBackedTestContext::new(cx).await;
+        cx.set_shared_state("heˇllo\n").await;
+        cx.simulate_shared_keystrokes("Y p").await;
+        cx.shared_state().await.assert_eq("helllˇolo\n");
+    }
+
     #[gpui::test]
     async fn test_yank_line_with_trailing_newline(cx: &mut gpui::TestAppContext) {
         let mut cx = NeovimBackedTestContext::new(cx).await;