Fix bugs and add tests for move_{up,down}

Max Brunsfeld created

Change summary

zed/src/editor/buffer_view.rs     | 57 ++++++++++++++++++++++++++++++--
zed/src/editor/display_map/mod.rs | 40 ++++++++++++++++++++++
2 files changed, 91 insertions(+), 6 deletions(-)

Detailed changes

zed/src/editor/buffer_view.rs šŸ”—

@@ -2729,11 +2729,6 @@ mod tests {
         assert_eq!('ⓐ'.len_utf8(), 3);
         assert_eq!('α'.len_utf8(), 2);
 
-        fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
-            let point = DisplayPoint::new(row as u32, column as u32);
-            point..point
-        }
-
         view.update(app, |view, ctx| {
             view.fold_ranges(
                 vec![
@@ -2826,6 +2821,53 @@ mod tests {
         });
     }
 
+    #[gpui::test]
+    fn test_move_cursor_different_line_lengths(app: &mut gpui::MutableAppContext) {
+        let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", ctx));
+        let settings = settings::channel(&app.font_cache()).unwrap().1;
+        let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
+        view.update(app, |view, ctx| {
+            view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], ctx)
+                .unwrap();
+
+            view.move_down(&(), ctx);
+            assert_eq!(
+                view.selection_ranges(ctx.as_ref()),
+                &[empty_range(1, "abcd".len())]
+            );
+
+            view.move_down(&(), ctx);
+            assert_eq!(
+                view.selection_ranges(ctx.as_ref()),
+                &[empty_range(2, "αβγ".len())]
+            );
+
+            view.move_down(&(), ctx);
+            assert_eq!(
+                view.selection_ranges(ctx.as_ref()),
+                &[empty_range(3, "abcd".len())]
+            );
+
+            view.move_down(&(), ctx);
+            assert_eq!(
+                view.selection_ranges(ctx.as_ref()),
+                &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())]
+            );
+
+            view.move_up(&(), ctx);
+            assert_eq!(
+                view.selection_ranges(ctx.as_ref()),
+                &[empty_range(3, "abcd".len())]
+            );
+
+            view.move_up(&(), ctx);
+            assert_eq!(
+                view.selection_ranges(ctx.as_ref()),
+                &[empty_range(2, "αβγ".len())]
+            );
+        });
+    }
+
     #[gpui::test]
     fn test_beginning_end_of_line(app: &mut gpui::MutableAppContext) {
         let buffer = app.add_model(|ctx| Buffer::new(0, "abc\n  def", ctx));
@@ -3803,4 +3845,9 @@ mod tests {
                 .collect::<Vec<_>>()
         }
     }
+
+    fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
+        let point = DisplayPoint::new(row as u32, column as u32);
+        point..point
+    }
 }

zed/src/editor/display_map/mod.rs šŸ”—

@@ -176,7 +176,7 @@ impl DisplayMapSnapshot {
         let mut count = 0;
         let mut column = 0;
         for c in self.chars_at(DisplayPoint::new(display_row, 0), ctx) {
-            if count >= char_count {
+            if c == '\n' || count >= char_count {
                 break;
             }
             count += 1;
@@ -441,6 +441,44 @@ mod tests {
         );
     }
 
+    #[gpui::test]
+    fn test_clip_point(app: &mut gpui::MutableAppContext) {
+        use Bias::{Left, Right};
+
+        let text = "\n'a', 'α',\t'āœ‹',\t'āŽ', 'šŸ'\n";
+        let display_text = "\n'a', 'α',   'āœ‹',    'āŽ', 'šŸ'\n";
+        let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
+        let ctx = app.as_ref();
+        let map = DisplayMap::new(buffer.clone(), 4, ctx);
+        assert_eq!(map.text(ctx), display_text);
+
+        let map = map.snapshot(ctx);
+        for (input_column, bias, output_column) in vec![
+            ("'a', '".len(), Left, "'a', '".len()),
+            ("'a', '".len() + 1, Left, "'a', '".len()),
+            ("'a', '".len() + 1, Right, "'a', 'α".len()),
+            ("'a', 'α', ".len(), Left, "'a', 'α',".len()),
+            ("'a', 'α', ".len(), Right, "'a', 'α',   ".len()),
+            ("'a', 'α',   '".len() + 1, Left, "'a', 'α',   '".len()),
+            ("'a', 'α',   '".len() + 1, Right, "'a', 'α',   'āœ‹".len()),
+            ("'a', 'α',   'āœ‹',".len(), Right, "'a', 'α',   'āœ‹',".len()),
+            ("'a', 'α',   'āœ‹', ".len(), Left, "'a', 'α',   'āœ‹',".len()),
+            (
+                "'a', 'α',   'āœ‹', ".len(),
+                Right,
+                "'a', 'α',   'āœ‹',    ".len(),
+            ),
+        ] {
+            assert_eq!(
+                map.clip_point(DisplayPoint::new(1, input_column as u32), bias, ctx),
+                DisplayPoint::new(1, output_column as u32),
+                "clip_point(({}, {}))",
+                1,
+                input_column,
+            );
+        }
+    }
+
     #[test]
     fn test_expand_tabs() {
         assert_eq!(expand_tabs("\t".chars(), 0, 4), 0);