From 23d1d9141444dce7a2db10c11ba178ec7edc1eca Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 28 May 2021 13:23:16 +0200 Subject: [PATCH] Implement `select_larger_syntax_node` for buffer --- zed/src/editor/buffer/mod.rs | 17 +++++++++++++ zed/src/editor/buffer_view.rs | 35 +++++++++++++++++++++++++- zed/src/editor/display_map/fold_map.rs | 12 +++++++++ zed/src/editor/display_map/mod.rs | 4 +++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index 81272ced2d..9a021fb740 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -709,6 +709,23 @@ impl Buffer { }) } + pub fn range_for_containing_syntax_node( + &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); + let mut node = root.descendant_for_byte_range(range.start, range.end); + while node.map_or(false, |n| n.byte_range() == range) { + node = node.unwrap().parent(); + } + node.map(|n| n.byte_range()) + } else { + None + } + } + fn diff(&self, new_text: Arc, ctx: &AppContext) -> Task { // TODO: it would be nice to not allocate here. let old_text = self.text(); diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index e2516d2113..1026758ce7 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -166,6 +166,11 @@ pub fn init(app: &mut MutableAppContext) { "buffer:add_selection_below", Some("BufferView"), ), + Binding::new( + "alt-up", + "buffer:select-larger-syntax-node", + Some("BufferView"), + ), Binding::new("pageup", "buffer:page_up", Some("BufferView")), Binding::new("pagedown", "buffer:page_down", Some("BufferView")), Binding::new("alt-cmd-[", "buffer:fold", Some("BufferView")), @@ -270,6 +275,10 @@ pub fn init(app: &mut MutableAppContext) { "buffer:add_selection_below", BufferView::add_selection_below, ); + app.add_action( + "buffer:select-larger-syntax-node", + BufferView::select_larger_syntax_node, + ); app.add_action("buffer:page_up", BufferView::page_up); app.add_action("buffer:page_down", BufferView::page_down); app.add_action("buffer:fold", BufferView::fold); @@ -1659,7 +1668,7 @@ impl BufferView { self.add_selection(false, ctx); } - pub fn add_selection(&mut self, above: bool, ctx: &mut ViewContext) { + fn add_selection(&mut self, above: bool, ctx: &mut ViewContext) { use super::RangeExt; let app = ctx.as_ref(); @@ -1751,6 +1760,30 @@ impl BufferView { } } + pub fn select_larger_syntax_node(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + let mut selections = self.selections(app).to_vec(); + for selection in &mut selections { + let mut range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer); + while let Some(containing_range) = + buffer.range_for_containing_syntax_node(range.clone()) + { + range = containing_range; + if !self.display_map.intersects_fold(range.start, app) + && !self.display_map.intersects_fold(range.end, app) + { + break; + } + } + + selection.start = buffer.anchor_before(range.start); + selection.end = buffer.anchor_before(range.end); + } + + self.update_selections(selections, true, ctx); + } + fn build_columnar_selection( &mut self, row: u32, diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 77887d3288..3f8c8be580 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -192,6 +192,18 @@ impl FoldMap { }) } + pub fn intersects_fold(&self, offset: T, ctx: &AppContext) -> bool + where + T: ToOffset, + { + let buffer = self.buffer.read(ctx); + let offset = offset.to_offset(buffer); + let transforms = self.sync(ctx); + let mut cursor = transforms.cursor::(); + cursor.seek(&offset, SeekBias::Right, &()); + cursor.item().map_or(false, |t| t.display_text.is_some()) + } + pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool { let transforms = self.sync(ctx); let mut cursor = transforms.cursor::(); diff --git a/zed/src/editor/display_map/mod.rs b/zed/src/editor/display_map/mod.rs index 12abb7fdb7..29241623eb 100644 --- a/zed/src/editor/display_map/mod.rs +++ b/zed/src/editor/display_map/mod.rs @@ -57,6 +57,10 @@ impl DisplayMap { self.fold_map.unfold(ranges, ctx) } + pub fn intersects_fold(&self, offset: T, ctx: &AppContext) -> bool { + self.fold_map.intersects_fold(offset, ctx) + } + pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool { self.fold_map.is_line_folded(display_row, ctx) }