diff --git a/zed/src/editor.rs b/zed/src/editor.rs index 20488fe9f66dafeb6956143b5f053858b39fc869..dbdf646802394e0354e995a1b7e0b0f0415189ea 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -384,7 +384,7 @@ pub struct Editor { single_line: bool, } -struct Snapshot { +pub struct Snapshot { pub display_snapshot: DisplayMapSnapshot, pub gutter_visible: bool, pub scroll_position: Vector2F, @@ -488,10 +488,14 @@ impl Editor { *self.scroll_position.lock() } - pub fn clamp_scroll_left(&self, max: f32) { + pub fn clamp_scroll_left(&mut self, max: f32) -> bool { let mut scroll_position = self.scroll_position.lock(); - let scroll_left = scroll_position.x(); - scroll_position.set_x(scroll_left.min(max)); + if max < scroll_position.x() { + scroll_position.set_x(max); + true + } else { + false + } } pub fn autoscroll_vertically( @@ -559,7 +563,7 @@ impl Editor { max_glyph_width: f32, layouts: &[text_layout::Line], cx: &mut MutableAppContext, - ) { + ) -> bool { let display_map = self.display_map.snapshot(cx); let mut target_left = std::f32::INFINITY; let mut target_right = 0.0_f32; @@ -577,7 +581,7 @@ impl Editor { target_right = target_right.min(scroll_width); if target_right - target_left > viewport_width { - return; + return false; } let mut scroll_position = self.scroll_position.lock(); @@ -586,8 +590,12 @@ impl Editor { if target_left < scroll_left { scroll_position.set_x(target_left / max_glyph_width); + true } else if target_right > scroll_right { scroll_position.set_x((target_right - viewport_width) / max_glyph_width); + true + } else { + false } } @@ -2564,70 +2572,64 @@ mod tests { fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) { let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx)); let settings = settings::channel(&cx.font_cache()).unwrap().1; - let (_, buffer_view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + let (_, editor) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); - buffer_view.update(cx, |view, cx| { + editor.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(2, 2), false, cx); }); - let view = buffer_view.read(cx); assert_eq!( - view.selection_ranges(cx), + editor.update(cx, |view, cx| view.selection_ranges(cx)), [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] ); - buffer_view.update(cx, |view, cx| { + editor.update(cx, |view, cx| { view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx); }); - let view = buffer_view.read(cx); assert_eq!( - view.selection_ranges(cx), + editor.update(cx, |view, cx| view.selection_ranges(cx)), [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] ); - buffer_view.update(cx, |view, cx| { + editor.update(cx, |view, cx| { view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx); }); - let view = buffer_view.read(cx); assert_eq!( - view.selection_ranges(cx), + editor.update(cx, |view, cx| view.selection_ranges(cx)), [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] ); - buffer_view.update(cx, |view, cx| { + editor.update(cx, |view, cx| { view.end_selection(cx); view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx); }); - let view = buffer_view.read(cx); assert_eq!( - view.selection_ranges(cx), + editor.update(cx, |view, cx| view.selection_ranges(cx)), [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] ); - buffer_view.update(cx, |view, cx| { + editor.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(3, 3), true, cx); view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx); }); - let view = buffer_view.read(cx); assert_eq!( - view.selection_ranges(cx), + editor.update(cx, |view, cx| view.selection_ranges(cx)), [ DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1), DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0) ] ); - buffer_view.update(cx, |view, cx| { + editor.update(cx, |view, cx| { view.end_selection(cx); }); - let view = buffer_view.read(cx); assert_eq!( - view.selection_ranges(cx), + editor.update(cx, |view, cx| view.selection_ranges(cx)), [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)] ); } @@ -2640,28 +2642,28 @@ mod tests { view.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(2, 2), false, cx); + assert_eq!( + view.selection_ranges(cx), + [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] - ); view.update(cx, |view, cx| { view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx); + assert_eq!( + view.selection_ranges(cx), + [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] - ); view.update(cx, |view, cx| { view.cancel(&(), cx); view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx); + assert_eq!( + view.selection_ranges(cx), + [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] - ); } #[gpui::test] @@ -2678,26 +2680,30 @@ mod tests { view.begin_selection(DisplayPoint::new(0, 1), true, cx); view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx); view.end_selection(cx); + assert_eq!( + view.selection_ranges(cx), + [ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1), + ] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1), - ] - ); - view.update(cx, |view, cx| view.cancel(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)] - ); + view.update(cx, |view, cx| { + view.cancel(&(), cx); + assert_eq!( + view.selection_ranges(cx), + [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)] + ); + }); - view.update(cx, |view, cx| view.cancel(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)] - ); + view.update(cx, |view, cx| { + view.cancel(&(), cx); + assert_eq!( + view.selection_ranges(cx), + [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)] + ); + }); } #[gpui::test] @@ -2708,13 +2714,14 @@ mod tests { let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx)); let settings = settings::channel(&font_cache).unwrap().1; - let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); + let (_, editor) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); - let layouts = view - .read(cx) - .snapshot(cx) - .layout_line_numbers(1000.0, &font_cache, &layout_cache) - .unwrap(); + let layouts = editor.update(cx, |editor, cx| { + editor + .snapshot(cx) + .layout_line_numbers(1000.0, &font_cache, &layout_cache) + .unwrap() + }); assert_eq!(layouts.len(), 6); } @@ -2983,110 +2990,130 @@ mod tests { .unwrap(); }); - view.update(cx, |view, cx| view.move_to_beginning_of_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - ] - ); + view.update(cx, |view, cx| { + view.move_to_beginning_of_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + ] + ); + }); - view.update(cx, |view, cx| view.move_to_beginning_of_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); + view.update(cx, |view, cx| { + view.move_to_beginning_of_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); + }); - view.update(cx, |view, cx| view.move_to_beginning_of_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - ] - ); + view.update(cx, |view, cx| { + view.move_to_beginning_of_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + ] + ); + }); - view.update(cx, |view, cx| view.move_to_end_of_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), - ] - ); + view.update(cx, |view, cx| { + view.move_to_end_of_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + ] + ); + }); // Moving to the end of line again is a no-op. - view.update(cx, |view, cx| view.move_to_end_of_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), - ] - ); + view.update(cx, |view, cx| { + view.move_to_end_of_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + ] + ); + }); view.update(cx, |view, cx| { view.move_left(&(), cx); view.select_to_beginning_of_line(&true, cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), + ] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), - ] - ); - view.update(cx, |view, cx| view.select_to_beginning_of_line(&true, cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0), - ] - ); + view.update(cx, |view, cx| { + view.select_to_beginning_of_line(&true, cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0), + ] + ); + }); - view.update(cx, |view, cx| view.select_to_beginning_of_line(&true, cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), - ] - ); + view.update(cx, |view, cx| { + view.select_to_beginning_of_line(&true, cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), + ] + ); + }); - view.update(cx, |view, cx| view.select_to_end_of_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5), - ] - ); + view.update(cx, |view, cx| { + view.select_to_end_of_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5), + ] + ); + }); - view.update(cx, |view, cx| view.delete_to_end_of_line(&(), cx)); - assert_eq!(view.read(cx).text(cx), "ab\n de"); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), - ] - ); + view.update(cx, |view, cx| { + view.delete_to_end_of_line(&(), cx); + assert_eq!(view.text(cx), "ab\n de"); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), + ] + ); + }); - view.update(cx, |view, cx| view.delete_to_beginning_of_line(&(), cx)); - assert_eq!(view.read(cx).text(cx), "\n"); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); + view.update(cx, |view, cx| { + assert_eq!(view.text(cx), "\n"); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); + view.delete_to_beginning_of_line(&(), cx) + }); } #[gpui::test] @@ -3106,155 +3133,173 @@ mod tests { .unwrap(); }); - view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), - ] - ); - - view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), - DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), - ] - ); - - view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), - ] - ); - - view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); - - view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), - ] - ); - - view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23), - ] - ); - - view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), - ] - ); - - view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); + view.update(cx, |view, cx| { + view.move_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), + ] + ); + }); - view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), - ] - ); + view.update(cx, |view, cx| { + view.move_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), + DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), + ] + ); + }); - view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), - ] - ); + view.update(cx, |view, cx| { + view.move_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), + DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), + ] + ); + }); view.update(cx, |view, cx| { - view.move_right(&(), cx); - view.select_to_previous_word_boundary(&(), cx); + view.move_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), - ] - ); view.update(cx, |view, cx| { - view.select_to_previous_word_boundary(&(), cx) + view.move_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), + ] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0), - ] - ); - view.update(cx, |view, cx| view.select_to_next_word_boundary(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), - ] - ); + view.update(cx, |view, cx| { + view.move_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23), + ] + ); + }); - view.update(cx, |view, cx| view.delete_to_next_word_boundary(&(), cx)); - assert_eq!( - view.read(cx).text(cx), - "use std::s::{foo, bar}\n\n {az.qux()}" - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), - ] - ); + view.update(cx, |view, cx| { + view.move_to_next_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), + ] + ); + }); view.update(cx, |view, cx| { - view.delete_to_previous_word_boundary(&(), cx) + view.move_to_next_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); + }); + + view.update(cx, |view, cx| { + view.move_to_next_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), + DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), + ] + ); + }); + + view.update(cx, |view, cx| { + view.move_to_next_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), + ] + ); + }); + + view.update(cx, |view, cx| { + view.move_right(&(), cx); + view.select_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), + ] + ); + }); + + view.update(cx, |view, cx| { + view.select_to_previous_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0), + ] + ); + }); + + view.update(cx, |view, cx| { + view.select_to_next_word_boundary(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), + ] + ); + }); + + view.update(cx, |view, cx| { + view.delete_to_next_word_boundary(&(), cx); + assert_eq!(view.text(cx), "use std::s::{foo, bar}\n\n {az.qux()}"); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), + ] + ); + }); + + view.update(cx, |view, cx| { + view.delete_to_previous_word_boundary(&(), cx); + assert_eq!(view.text(cx), "use std::::{foo, bar}\n\n az.qux()}"); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), + ] + ); }); - assert_eq!( - view.read(cx).text(cx), - "use std::::{foo, bar}\n\n az.qux()}" - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), - ] - ); } #[gpui::test] @@ -3341,15 +3386,15 @@ mod tests { ) .unwrap(); view.delete_line(&(), cx); + assert_eq!(view.text(cx), "ghi"); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1) + ] + ); }); - assert_eq!(view.read(cx).text(cx), "ghi"); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1) - ] - ); let settings = settings::channel(&cx.font_cache()).unwrap().1; let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); @@ -3358,12 +3403,12 @@ mod tests { view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], cx) .unwrap(); view.delete_line(&(), cx); + assert_eq!(view.text(cx), "ghi\n"); + assert_eq!( + view.selection_ranges(cx), + vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] + ); }); - assert_eq!(view.read(cx).text(cx), "ghi\n"); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] - ); } #[gpui::test] @@ -3383,17 +3428,17 @@ mod tests { ) .unwrap(); view.duplicate_line(&(), cx); + assert_eq!(view.text(cx), "abc\nabc\ndef\ndef\nghi\n\n"); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), + DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0), + ] + ); }); - assert_eq!(view.read(cx).text(cx), "abc\nabc\ndef\ndef\nghi\n\n"); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0), - ] - ); let settings = settings::channel(&cx.font_cache()).unwrap().1; let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); @@ -3408,15 +3453,15 @@ mod tests { ) .unwrap(); view.duplicate_line(&(), cx); + assert_eq!(view.text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n"); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1), + DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1), + ] + ); }); - assert_eq!(view.read(cx).text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n"); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1), - DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1), - ] - ); } #[gpui::test] @@ -3443,71 +3488,62 @@ mod tests { cx, ) .unwrap(); - }); - assert_eq!( - view.read(cx).text(cx), - "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj" - ); + assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj"); - view.update(cx, |view, cx| view.move_line_up(&(), cx)); - assert_eq!( - view.read(cx).text(cx), - "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff" - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), - DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) - ] - ); + view.move_line_up(&(), cx); + assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff"); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), + DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) + ] + ); + }); - view.update(cx, |view, cx| view.move_line_down(&(), cx)); - assert_eq!( - view.read(cx).text(cx), - "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj" - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) - ] - ); + view.update(cx, |view, cx| { + view.move_line_down(&(), cx); + assert_eq!(view.text(cx), "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj"); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), + DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) + ] + ); + }); - view.update(cx, |view, cx| view.move_line_down(&(), cx)); - assert_eq!( - view.read(cx).text(cx), - "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj" - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) - ] - ); + view.update(cx, |view, cx| { + view.move_line_down(&(), cx); + assert_eq!(view.text(cx), "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj"); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), + DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) + ] + ); + }); - view.update(cx, |view, cx| view.move_line_up(&(), cx)); - assert_eq!( - view.read(cx).text(cx), - "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff" - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), - DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) - ] - ); + view.update(cx, |view, cx| { + view.move_line_up(&(), cx); + assert_eq!(view.text(cx), "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff"); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), + DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) + ] + ); + }); } #[gpui::test] @@ -3522,23 +3558,23 @@ mod tests { view.update(cx, |view, cx| { view.select_ranges(vec![0..4, 8..14, 19..24], false, cx); view.cut(&(), cx); + assert_eq!(view.text(cx), "two four six "); }); - assert_eq!(view.read(cx).text(cx), "two four six "); // Paste with three cursors. Each cursor pastes one slice of the clipboard text. view.update(cx, |view, cx| { view.select_ranges(vec![4..4, 9..9, 13..13], false, cx); view.paste(&(), cx); + assert_eq!(view.text(cx), "two one four three six five "); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8), + DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19), + DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28) + ] + ); }); - assert_eq!(view.read(cx).text(cx), "two one four three six five "); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8), - DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19), - DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28) - ] - ); // Paste again but with only two cursors. Since the number of cursors doesn't // match the number of slices in the clipboard, the entire clipboard text @@ -3548,20 +3584,20 @@ mod tests { view.insert(&"( ".to_string(), cx); view.paste(&(), cx); view.insert(&") ".to_string(), cx); + assert_eq!( + view.text(cx), + "( one three five ) two one four three six five ( one three five ) " + ); }); - assert_eq!( - view.read(cx).text(cx), - "( one three five ) two one four three six five ( one three five ) " - ); view.update(cx, |view, cx| { view.select_ranges(vec![0..0], false, cx); view.insert(&"123\n4567\n89\n".to_string(), cx); + assert_eq!( + view.text(cx), + "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) " + ); }); - assert_eq!( - view.read(cx).text(cx), - "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) " - ); // Cut with three selections, one of which is full-line. view.update(cx, |view, cx| { @@ -3575,11 +3611,11 @@ mod tests { ) .unwrap(); view.cut(&(), cx); + assert_eq!( + view.text(cx), + "13\n9\n( one three five ) two one four three six five ( one three five ) " + ); }); - assert_eq!( - view.read(cx).text(cx), - "13\n9\n( one three five ) two one four three six five ( one three five ) " - ); // Paste with three selections, noticing how the copied selection that was full-line // gets inserted before the second cursor. @@ -3594,19 +3630,19 @@ mod tests { ) .unwrap(); view.paste(&(), cx); + assert_eq!( + view.text(cx), + "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) " + ); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3), + ] + ); }); - assert_eq!( - view.read(cx).text(cx), - "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) " - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3), - ] - ); // Copy with a single cursor only, which writes the whole line into the clipboard. view.update(cx, |view, cx| { @@ -3628,19 +3664,19 @@ mod tests { ) .unwrap(); view.paste(&(), cx); - }); - assert_eq!( - view.read(cx).text(cx), + assert_eq!( + view.text(cx), "123\n123\n123\n67\n123\n9\n( 8ne three five ) two one four three six five ( one three five ) " ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1), - ] - ); + assert_eq!( + view.selection_ranges(cx), + &[ + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1), + ] + ); + }); } #[gpui::test] @@ -3648,11 +3684,13 @@ mod tests { let buffer = cx.add_model(|cx| Buffer::new(0, "abc\nde\nfgh", cx)); let settings = settings::channel(&cx.font_cache()).unwrap().1; let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); - view.update(cx, |b, cx| b.select_all(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)] - ); + view.update(cx, |view, cx| { + view.select_all(&(), cx); + assert_eq!( + view.selection_ranges(cx), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)] + ); + }); } #[gpui::test] @@ -3672,29 +3710,33 @@ mod tests { ) .unwrap(); view.select_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0), + DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0), + ] + ); }); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0), - DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0), - ] - ); - view.update(cx, |view, cx| view.select_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5), - ] - ); + view.update(cx, |view, cx| { + view.select_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5), + ] + ); + }); - view.update(cx, |view, cx| view.select_line(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)] - ); + view.update(cx, |view, cx| { + view.select_line(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)] + ); + }); } #[gpui::test] @@ -3721,43 +3763,45 @@ mod tests { cx, ) .unwrap(); + assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"); }); - assert_eq!(view.read(cx).text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"); - view.update(cx, |view, cx| view.split_selection_into_lines(&(), cx)); - assert_eq!(view.read(cx).text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4) - ] - ); + view.update(cx, |view, cx| { + view.split_selection_into_lines(&(), cx); + assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i"); + assert_eq!( + view.selection_ranges(cx), + [ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4) + ] + ); + }); view.update(cx, |view, cx| { view.select_display_ranges(&[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)], cx) .unwrap(); view.split_selection_into_lines(&(), cx); + assert_eq!( + view.text(cx), + "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i" + ); + assert_eq!( + view.selection_ranges(cx), + [ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5), + DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5), + DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5), + DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5), + DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5), + DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0) + ] + ); }); - assert_eq!( - view.read(cx).text(cx), - "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i" - ); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), - DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5), - DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5), - DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5), - DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5), - DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5), - DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0) - ] - ); } #[gpui::test] @@ -3770,141 +3814,167 @@ mod tests { view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], cx) .unwrap(); }); - view.update(cx, |view, cx| view.add_selection_above(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) - ] - ); + view.update(cx, |view, cx| { + view.add_selection_above(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) + ] + ); + }); - view.update(cx, |view, cx| view.add_selection_above(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) - ] - ); + view.update(cx, |view, cx| { + view.add_selection_above(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) + ] + ); + }); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)] - ); + view.update(cx, |view, cx| { + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)] + ); + }); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) - ] - ); + view.update(cx, |view, cx| { + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) + ] + ); + }); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) - ] - ); + view.update(cx, |view, cx| { + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) + ] + ); + }); view.update(cx, |view, cx| { view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], cx) .unwrap(); }); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) - ] - ); + view.update(cx, |view, cx| { + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) + ] + ); + }); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) - ] - ); + view.update(cx, |view, cx| { + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) + ] + ); + }); - view.update(cx, |view, cx| view.add_selection_above(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] - ); + view.update(cx, |view, cx| { + view.add_selection_above(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] + ); + }); - view.update(cx, |view, cx| view.add_selection_above(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] - ); + view.update(cx, |view, cx| { + view.add_selection_above(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] + ); + }); view.update(cx, |view, cx| { view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], cx) .unwrap(); + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), + ] + ); }); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), - ] - ); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), - DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4), - ] - ); + view.update(cx, |view, cx| { + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), + DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4), + ] + ); + }); - view.update(cx, |view, cx| view.add_selection_above(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), - ] - ); + view.update(cx, |view, cx| { + view.add_selection_above(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), + ] + ); + }); view.update(cx, |view, cx| { view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], cx) .unwrap(); }); - view.update(cx, |view, cx| view.add_selection_above(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), - ] - ); + view.update(cx, |view, cx| { + view.add_selection_above(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), + ] + ); + }); - view.update(cx, |view, cx| view.add_selection_below(&(), cx)); - assert_eq!( - view.update(cx, |view, cx| view.selection_ranges(cx)), - vec![ - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), - ] - ); + view.update(cx, |view, cx| { + view.add_selection_below(&(), cx); + assert_eq!( + view.selection_ranges(cx), + vec![ + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), + ] + ); + }); } #[gpui::test] diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index d20bcec8deda8ce7149ac7c77d5e01ac88e6df2a..054aaa6dff2077262cfe25ad2216e5174628c1fa 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -26,10 +26,6 @@ impl OutputPoint { Self(super::Point::new(row, column)) } - pub fn zero() -> Self { - Self::new(0, 0) - } - pub fn row(self) -> u32 { self.0.row } @@ -42,6 +38,7 @@ impl OutputPoint { &mut self.0.row } + #[cfg(test)] pub fn column_mut(&mut self) -> &mut u32 { &mut self.0.column } @@ -450,10 +447,6 @@ impl Snapshot { self.chunks_at(OutputOffset(0)).collect() } - pub fn text_summary(&self) -> TextSummary { - self.transforms.summary().output - } - pub fn text_summary_for_range(&self, range: Range) -> TextSummary { let mut summary = TextSummary::default(); @@ -499,6 +492,7 @@ impl Snapshot { OutputOffset(self.transforms.summary().output.bytes) } + #[cfg(test)] pub fn line_len(&self, row: u32) -> u32 { let line_start = self.to_output_offset(OutputPoint::new(row, 0)).0; let line_end = if row >= self.max_point().row() { @@ -527,6 +521,7 @@ impl Snapshot { OutputPoint(self.transforms.summary().output.lines) } + #[cfg(test)] pub fn longest_row(&self) -> u32 { self.transforms.summary().output.longest_row } @@ -584,7 +579,7 @@ impl Snapshot { } } - pub fn highlighted_chunks(&self, range: Range) -> HighlightedChunks { + pub fn highlighted_chunks(&mut self, range: Range) -> HighlightedChunks { let mut transform_cursor = self.transforms.cursor::(); transform_cursor.seek(&range.end, Bias::Right, &()); @@ -1093,6 +1088,7 @@ pub struct Edit { pub new_bytes: Range, } +#[cfg(test)] impl Edit { pub fn delta(&self) -> isize { self.inserted_bytes() as isize - self.deleted_bytes() as isize diff --git a/zed/src/editor/display_map/line_wrapper.rs b/zed/src/editor/display_map/line_wrapper.rs index 7f2c2145f03255990f72ae1741f4c0d89f16e974..79c69b5d1303d17d06905fd57a90288d2ffdf9d4 100644 --- a/zed/src/editor/display_map/line_wrapper.rs +++ b/zed/src/editor/display_map/line_wrapper.rs @@ -5,7 +5,6 @@ use std::{collections::HashMap, sync::Arc}; pub struct LineWrapper { font_system: Arc, - font_cache: Arc, font_id: FontId, font_size: f32, cached_ascii_char_widths: Mutex<[f32; 128]>, @@ -15,7 +14,7 @@ pub struct LineWrapper { impl LineWrapper { pub fn new( font_system: Arc, - font_cache: Arc, + font_cache: &FontCache, settings: Settings, ) -> Self { let font_id = font_cache @@ -23,7 +22,6 @@ impl LineWrapper { .unwrap(); let font_size = settings.buffer_font_size; Self { - font_cache, font_system, font_id, font_size, @@ -32,12 +30,13 @@ impl LineWrapper { } } + #[cfg(test)] pub fn wrap_line_with_shaping(&self, line: &str, wrap_width: f32) -> Vec { self.font_system .wrap_line(line, self.font_id, self.font_size, wrap_width) } - pub fn wrap_line_without_shaping(&self, line: &str, wrap_width: f32) -> Vec { + pub fn wrap_line(&self, line: &str, wrap_width: f32) -> Vec { let mut width = 0.0; let mut boundaries = Vec::new(); let mut last_boundary_ix = 0; @@ -126,14 +125,14 @@ mod tests { ..Settings::new(&font_cache).unwrap() }; - let wrapper = LineWrapper::new(font_system, font_cache, settings); + let wrapper = LineWrapper::new(font_system, &font_cache, settings); assert_eq!( wrapper.wrap_line_with_shaping("aa bbb cccc ddddd eeee", 72.0), &[7, 12, 18], ); assert_eq!( - wrapper.wrap_line_without_shaping("aa bbb cccc ddddd eeee", 72.0), + wrapper.wrap_line("aa bbb cccc ddddd eeee", 72.0), &[7, 12, 18], ); @@ -142,7 +141,7 @@ mod tests { &[4, 11, 18], ); assert_eq!( - wrapper.wrap_line_without_shaping("aaa aaaaaaaaaaaaaaaaaa", 72.0), + wrapper.wrap_line("aaa aaaaaaaaaaaaaaaaaa", 72.0), &[4, 11, 18], ); } diff --git a/zed/src/editor/display_map/tab_map.rs b/zed/src/editor/display_map/tab_map.rs index fd347ff1bfa48a7c2a6d3ece1da21f1f71892adb..d182ae099128c33089e215c993ec8c461aeedb85 100644 --- a/zed/src/editor/display_map/tab_map.rs +++ b/zed/src/editor/display_map/tab_map.rs @@ -2,7 +2,7 @@ use parking_lot::Mutex; use super::fold_map::{ self, Chunks as InputChunks, Edit as InputEdit, HighlightedChunks as InputHighlightedChunks, - OutputOffset as InputOffset, OutputPoint as InputPoint, Snapshot as InputSnapshot, + OutputPoint as InputPoint, Snapshot as InputSnapshot, }; use crate::{editor::rope, settings::StyleId, util::Bias}; use std::{cmp, mem, ops::Range}; @@ -144,7 +144,7 @@ impl Snapshot { } } - pub fn highlighted_chunks(&self, range: Range) -> HighlightedChunks { + pub fn highlighted_chunks(&mut self, range: Range) -> HighlightedChunks { let (input_start, expanded_char_column, to_next_stop) = self.to_input_point(range.start, Bias::Left); let input_start = self.input.to_output_offset(input_start); @@ -170,20 +170,6 @@ impl Snapshot { self.chunks_at(Default::default()).collect() } - pub fn len(&self) -> OutputOffset { - self.to_output_offset(self.input.len()) - } - - pub fn line_len(&self, row: u32) -> u32 { - self.to_output_point(InputPoint::new(row, self.input.line_len(row))) - .column() - } - - pub fn longest_row(&self) -> u32 { - // TODO: Account for tab expansion. - self.input.longest_row() - } - pub fn max_point(&self) -> OutputPoint { self.to_output_point(self.input.max_point()) } @@ -195,15 +181,6 @@ impl Snapshot { ) } - pub fn to_output_offset(&self, input_offset: InputOffset) -> OutputOffset { - let input_point = input_offset.to_point(&self.input); - let input_row_start_offset = self - .input - .to_output_offset(InputPoint::new(input_point.row(), 0)); - let output_point = self.to_output_point(input_point); - OutputOffset(input_row_start_offset.0 + output_point.column() as usize) - } - pub fn to_output_point(&self, input: InputPoint) -> OutputPoint { let chars = self.input.chars_at(InputPoint::new(input.row(), 0)); let expanded = Self::expand_tabs(chars, input.column() as usize, self.tab_size); @@ -306,14 +283,6 @@ impl OutputPoint { pub fn column(self) -> u32 { self.0.column } - - pub fn row_mut(&mut self) -> &mut u32 { - &mut self.0.row - } - - pub fn column_mut(&mut self) -> &mut u32 { - &mut self.0.column - } } impl From for OutputPoint { diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index 63071a47f24bc99211c5cfb725daa729ca125bef..e443ce5932d76bf39be8d3c62517acc7c8f8438e 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -90,7 +90,7 @@ impl WrapMap { snapshot: Snapshot::new(tab_snapshot), line_wrapper: Arc::new(LineWrapper::new( cx.platform().fonts(), - cx.font_cache().clone(), + cx.font_cache(), settings, )), }))); @@ -98,6 +98,7 @@ impl WrapMap { this } + #[cfg(test)] pub fn is_rewrapping(&self) -> bool { self.0.lock().background_task.is_some() } @@ -392,7 +393,7 @@ impl Snapshot { } let mut prev_boundary_ix = 0; - for boundary_ix in line_wrapper.wrap_line_without_shaping(&line, wrap_width) { + for boundary_ix in line_wrapper.wrap_line(&line, wrap_width) { let wrapped = &line[prev_boundary_ix..boundary_ix]; new_transforms .push_or_extend(Transform::isomorphic(TextSummary::from(wrapped))); @@ -717,6 +718,7 @@ impl WrapPoint { Self(super::Point::new(row, column)) } + #[cfg(test)] pub fn zero() -> Self { Self::new(0, 0) } @@ -826,7 +828,7 @@ mod tests { }); let mut notifications = wrap_map.notifications(); - let mut line_wrapper = LineWrapper::new(font_system, font_cache, settings); + let mut line_wrapper = LineWrapper::new(font_system, &font_cache, settings); let unwrapped_text = tabs_snapshot.text(); let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper); @@ -888,7 +890,7 @@ mod tests { } let mut prev_ix = 0; - for ix in line_wrapper.wrap_line_without_shaping(line, wrap_width) { + for ix in line_wrapper.wrap_line(line, wrap_width) { wrapped_text.push_str(&line[prev_ix..ix]); wrapped_text.push('\n'); prev_ix = ix; diff --git a/zed/src/editor/element.rs b/zed/src/editor/element.rs index a19877382e52a5065eee8c67a851cf4937c172e6..5a174c0f853bcdaf2a3a0d6df3798988ebedff43 100644 --- a/zed/src/editor/element.rs +++ b/zed/src/editor/element.rs @@ -51,8 +51,7 @@ impl EditorElement { ) -> bool { if paint.text_bounds.contains_point(position) { let position = self.update_view(cx.app, |view, cx| { - let font_cache = cx.font_cache().clone(); - paint.point_for_position(view, layout, position, &font_cache, cx) + paint.point_for_position(view, layout, position, cx) }); cx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd }); true @@ -110,7 +109,7 @@ impl EditorElement { let font_cache = cx.font_cache.clone(); let text_layout_cache = cx.text_layout_cache.clone(); let action = self.update_view(cx.app, |view, cx| SelectAction::Update { - position: paint.point_for_position(view, layout, position, &font_cache, cx), + position: paint.point_for_position(view, layout, position, cx), scroll_position: (view.scroll_position() + scroll_delta).clamp( Vector2F::zero(), layout.scroll_max(&font_cache, &text_layout_cache), @@ -376,7 +375,7 @@ impl Element for EditorElement { size.set_y((snapshot.max_point().row() + 1) as f32 * line_height); } - let (autoscroll_horizontally, snapshot) = self.update_view(cx.app, |view, cx| { + let (autoscroll_horizontally, mut snapshot) = self.update_view(cx.app, |view, cx| { let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx); let snapshot = view.snapshot(cx); (autoscroll_horizontally, snapshot) @@ -416,21 +415,22 @@ impl Element for EditorElement { } }; - let view = self.view(cx.app); let mut selections = HashMap::new(); - for selection_set_id in view.active_selection_sets(cx.app) { - selections.insert( - selection_set_id.replica_id, - view.selections_in_range( - selection_set_id, - DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0), - cx.app, - ) - .collect(), - ); - } + self.update_view(cx.app, |view, cx| { + for selection_set_id in view.active_selection_sets(cx).collect::>() { + selections.insert( + selection_set_id.replica_id, + view.selections_in_range( + selection_set_id, + DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0), + cx, + ) + .collect(), + ); + } + }); - let layout = LayoutState { + let mut layout = LayoutState { size, gutter_size, gutter_padding, @@ -446,19 +446,26 @@ impl Element for EditorElement { max_visible_line_width, }; - // TODO: If any of the below changes the editor's scroll state, update the layout's snapshot to reflect it. - let view = self.view(cx.app); - view.clamp_scroll_left(layout.scroll_max(cx.font_cache, cx.text_layout_cache).x()); - if autoscroll_horizontally { - view.autoscroll_horizontally( - view.scroll_position().y() as u32, - layout.text_size.x(), - layout.scroll_width(cx.font_cache, cx.text_layout_cache), - snapshot.em_width(cx.font_cache), - &layout.line_layouts, - cx.app, - ); - } + self.update_view(cx.app, |view, cx| { + let clamped = view.clamp_scroll_left(layout.scroll_max(font_cache, layout_cache).x()); + let autoscrolled; + if autoscroll_horizontally { + autoscrolled = view.autoscroll_horizontally( + view.scroll_position().y() as u32, + layout.text_size.x(), + layout.scroll_width(font_cache, layout_cache), + layout.snapshot.em_width(font_cache), + &layout.line_layouts, + cx, + ); + } else { + autoscrolled = false; + } + + if clamped || autoscrolled { + layout.snapshot = view.snapshot(cx); + } + }); (size, Some(layout)) } @@ -588,7 +595,6 @@ impl PaintState { view: &Editor, layout: &LayoutState, position: Vector2F, - font_cache: &FontCache, cx: &mut MutableAppContext, ) -> DisplayPoint { let scroll_position = view.scroll_position(); diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 2595d5105db7bcb518ccef8b2113a46f7457a594..fb5e4da20d9f840dbe395309f7b7c084a569ab26 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -311,7 +311,8 @@ impl FileFinder { } fn workspace_updated(&mut self, _: ViewHandle, cx: &mut ViewContext) { - if let Some(task) = self.spawn_search(self.query_buffer.read(cx).text(cx), cx) { + let query = self.query_buffer.update(cx, |buffer, cx| buffer.text(cx)); + if let Some(task) = self.spawn_search(query, cx) { task.detach(); } }