diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index 94a98384396de900a99f688899013c88902943f6..81f17ae9e3c49884f15970297b2a15a0c09abd24 100644 --- a/zed/src/editor/buffer_view.rs +++ b/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 { - 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::>() } } + + fn empty_range(row: usize, column: usize) -> Range { + let point = DisplayPoint::new(row as u32, column as u32); + point..point + } } diff --git a/zed/src/editor/display_map/mod.rs b/zed/src/editor/display_map/mod.rs index 792df1c8d92d17127c42fa5bc20dd98e4db8670a..df81e2505ad5fe5cae1cdf7abdb57dfc10367ab4 100644 --- a/zed/src/editor/display_map/mod.rs +++ b/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);