Fix dw at the end of a soft wrapped line (#13065)

Conrad Irwin and Richard created

Co-Authored-By: Richard <richard@zed.dev>
Release Notes:

- vim: Fixed behavior of `dw` at the end of a soft wrapped line

Co-authored-by: Richard <richard@zed.dev>

Change summary

crates/vim/src/motion.rs              | 18 ++++++++++--------
crates/vim/src/test.rs                | 14 ++++++++++++++
crates/vim/test_data/test_dw_eol.json |  6 ++++++
3 files changed, 30 insertions(+), 8 deletions(-)

Detailed changes

crates/vim/src/motion.rs 🔗

@@ -873,18 +873,20 @@ impl Motion {
                 // becomes inclusive. Example: "}" moves to the first line after a paragraph,
                 // but "d}" will not include that line.
                 let mut inclusive = self.inclusive();
+                let start_point = selection.start.to_point(&map);
+                let mut end_point = selection.end.to_point(&map);
+
+                // DisplayPoint
+
                 if !inclusive
                     && self != &Motion::Backspace
-                    && selection.end.row() > selection.start.row()
-                    && selection.end.column() == 0
+                    && end_point.row > start_point.row
+                    && end_point.column == 0
                 {
                     inclusive = true;
-                    *selection.end.row_mut() -= 1;
-                    *selection.end.column_mut() = 0;
-                    selection.end = map.clip_point(
-                        map.next_line_boundary(selection.end.to_point(map)).1,
-                        Bias::Left,
-                    );
+                    end_point.row -= 1;
+                    end_point.column = 0;
+                    selection.end = map.clip_point(map.next_line_boundary(end_point).1, Bias::Left);
                 }
 
                 if inclusive && selection.end.column() < map.line_len(selection.end.row()) {

crates/vim/src/test.rs 🔗

@@ -1197,3 +1197,17 @@ async fn test_caret_mark(cx: &mut TestAppContext) {
     "
     });
 }
+
+#[cfg(target_os = "macos")]
+#[gpui::test]
+async fn test_dw_eol(cx: &mut gpui::TestAppContext) {
+    let mut cx = NeovimBackedTestContext::new(cx).await;
+
+    cx.set_shared_wrap(12).await;
+    cx.set_shared_state("twelve ˇchar twelve char\ntwelve char")
+        .await;
+    cx.simulate_shared_keystrokes("d w").await;
+    cx.shared_state()
+        .await
+        .assert_eq("twelve ˇtwelve char\ntwelve char");
+}

crates/vim/test_data/test_dw_eol.json 🔗

@@ -0,0 +1,6 @@
+{"SetOption":{"value":"wrap"}}
+{"SetOption":{"value":"columns=12"}}
+{"Put":{"state":"twelve ˇchar twelve char\ntwelve char"}}
+{"Key":"d"}
+{"Key":"w"}
+{"Get":{"state":"twelve ˇtwelve char\ntwelve char","mode":"Normal"}}