Fix clipping at end of line in vim mode with inlay hints (#23975)

Conrad Irwin , Ben , and Michael created

Closes #23877

Co-Authored-By: Ben <ben@zed.dev>
Co-Authored-By: Michael <michael@zed.dev>

Release Notes:

- vim: Fix navigating to end of line with inlay hints

---------

Co-authored-by: Ben <ben@zed.dev>
Co-authored-by: Michael <michael@zed.dev>

Change summary

crates/editor/src/display_map.rs | 14 ++++++----
crates/vim/src/motion.rs         | 45 +++++++++++++++++++++++++++++----
2 files changed, 47 insertions(+), 12 deletions(-)

Detailed changes

crates/editor/src/display_map.rs ๐Ÿ”—

@@ -1068,13 +1068,15 @@ impl DisplaySnapshot {
         DisplayPoint(self.block_snapshot.clip_point(point.0, bias))
     }
 
-    pub fn clip_at_line_end(&self, point: DisplayPoint) -> DisplayPoint {
-        let mut point = point.0;
-        if point.column == self.line_len(DisplayRow(point.row)) {
-            point.column = point.column.saturating_sub(1);
-            point = self.block_snapshot.clip_point(point, Bias::Left);
+    pub fn clip_at_line_end(&self, display_point: DisplayPoint) -> DisplayPoint {
+        let mut point = self.display_point_to_point(display_point, Bias::Left);
+
+        if point.column != self.buffer_snapshot.line_len(MultiBufferRow(point.row)) {
+            return display_point;
         }
-        DisplayPoint(point)
+        point.column = point.column.saturating_sub(1);
+        point = self.buffer_snapshot.clip_point(point, Bias::Left);
+        self.point_to_display_point(point, Bias::Left)
     }
 
     pub fn folds_in_range<T>(&self, range: Range<T>) -> impl Iterator<Item = &Fold>

crates/vim/src/motion.rs ๐Ÿ”—

@@ -2761,6 +2761,8 @@ mod test {
     };
     use editor::display_map::Inlay;
     use indoc::indoc;
+    use language::Point;
+    use multi_buffer::MultiBufferRow;
 
     #[gpui::test]
     async fn test_start_end_of_paragraph(cx: &mut gpui::TestAppContext) {
@@ -3428,10 +3430,10 @@ mod test {
 
         cx.set_state(
             indoc! {"
-            struct Foo {
-            ห‡
-            }
-        "},
+                struct Foo {
+                ห‡
+                }
+            "},
             Mode::Normal,
         );
 
@@ -3445,9 +3447,40 @@ mod test {
         cx.simulate_keystrokes("j");
         cx.assert_state(
             indoc! {"
-            struct Foo {
+                struct Foo {
+
+                ห‡}
+            "},
+            Mode::Normal,
+        );
+    }
+
+    #[gpui::test]
+    async fn test_clipping_with_inlay_hints_end_of_line(cx: &mut gpui::TestAppContext) {
+        let mut cx = VimTestContext::new(cx, true).await;
+
+        cx.set_state(
+            indoc! {"
+            ห‡struct Foo {
+
+            }
+        "},
+            Mode::Normal,
+        );
+        cx.update_editor(|editor, _window, cx| {
+            let snapshot = editor.buffer().read(cx).snapshot(cx);
+            let end_of_line =
+                snapshot.anchor_after(Point::new(0, snapshot.line_len(MultiBufferRow(0))));
+            let inlay_text = " hint";
+            let inlay = Inlay::inline_completion(1, end_of_line, inlay_text);
+            editor.splice_inlays(vec![], vec![inlay], cx);
+        });
+        cx.simulate_keystrokes("$");
+        cx.assert_state(
+            indoc! {"
+            struct Foo ห‡{
 
-            ห‡}
+            }
         "},
             Mode::Normal,
         );