From 36c1d21025d7ed2cc74a971b5ec786ec5b5b1aa7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 28 May 2021 14:59:29 +0200 Subject: [PATCH] Add unit test for `BufferView::select_{larger,smaller}_syntax_node` --- zed/src/editor/buffer/mod.rs | 5 +- zed/src/editor/buffer_view.rs | 151 +++++++++++++++++++++++++++++++++- 2 files changed, 148 insertions(+), 8 deletions(-) diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index 9a021fb740059f5f1d4b71ae606a10e401e4d2bc..d0e082b7cc849c768ab745e60b13a672fdab21f9 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -709,10 +709,7 @@ impl Buffer { }) } - pub fn range_for_containing_syntax_node( - &self, - range: Range, - ) -> Option> { + pub fn range_for_syntax_ancestor(&self, range: Range) -> Option> { if let Some(tree) = self.syntax_tree() { let root = tree.root_node(); let range = range.start.to_offset(self)..range.end.to_offset(self); diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index 68dee5f75c290e183bd6b9cc1d1e3709c05de805..bd51be56f4a61b08614f47cef90c200621d1e045 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -1782,9 +1782,7 @@ impl BufferView { for selection in &old_selections { let old_range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer); let mut new_range = old_range.clone(); - while let Some(containing_range) = - buffer.range_for_containing_syntax_node(new_range.clone()) - { + while let Some(containing_range) = buffer.range_for_syntax_ancestor(new_range.clone()) { new_range = containing_range; if !self.display_map.intersects_fold(new_range.start, app) && !self.display_map.intersects_fold(new_range.end, app) @@ -2445,7 +2443,12 @@ impl workspace::ItemView for BufferView { #[cfg(test)] mod tests { use super::*; - use crate::{editor::Point, settings, test::sample_text}; + use crate::{ + editor::Point, + settings, + test::{build_app_state, sample_text}, + }; + use buffer::History; use unindent::Unindent; #[gpui::test] @@ -3926,6 +3929,146 @@ mod tests { ); } + #[gpui::test] + async fn test_select_larger_smaller_syntax_node(mut app: gpui::TestAppContext) { + let app_state = app.read(build_app_state); + let lang = app_state.language_registry.select_language("z.rs"); + let text = r#" + use mod1::mod2::{mod3, mod4}; + + fn fn_1(param1: bool, param2: &str) { + let var1 = "text"; + } + "# + .unindent(); + let buffer = app.add_model(|ctx| { + let history = History::new(text.into()); + Buffer::from_history(0, history, None, lang.cloned(), ctx) + }); + let (_, view) = + app.add_window(|ctx| BufferView::for_buffer(buffer, app_state.settings, ctx)); + view.condition(&app, |view, ctx| !view.buffer.read(ctx).is_parsing()) + .await; + + view.update(&mut app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), + DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), + DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + ], + ctx, + ) + .unwrap(); + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), + DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), + DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), + DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] + ); + + // Trying to expand the selected syntax node one more time has no effect. + view.update(&mut app, |view, ctx| { + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] + ); + + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), + DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), + DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), + DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), + DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), + DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + ] + ); + + // Trying to shrink the selected syntax node one more time has no effect. + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), + DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), + DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + ] + ); + + // Ensure that we keep expanding the selection if the larger selection starts or ends within + // a fold. + view.update(&mut app, |view, ctx| { + view.fold_ranges( + vec![ + Point::new(0, 21)..Point::new(0, 24), + Point::new(3, 20)..Point::new(3, 22), + ], + ctx, + ); + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), + DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), + DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23), + ] + ); + } + impl BufferView { fn selection_ranges(&self, app: &AppContext) -> Vec> { self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app)