From 6cfb1acb9d1456e854a2c44ee8fc057f45b29ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 22 Feb 2021 15:50:41 +0900 Subject: [PATCH] commands: Implement expand_selection. --- helix-core/src/lib.rs | 1 + helix-core/src/object.rs | 32 ++++++++++++++++++++++++++++++++ helix-term/src/commands.rs | 13 +++++++++++++ helix-term/src/keymap.rs | 3 ++- 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 helix-core/src/object.rs diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 14e58293f..7b4015574 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -5,6 +5,7 @@ mod history; pub mod indent; pub mod macros; +pub mod object; mod position; pub mod register; pub mod selection; diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs new file mode 100644 index 000000000..19ff9d967 --- /dev/null +++ b/helix-core/src/object.rs @@ -0,0 +1,32 @@ +use crate::{Range, RopeSlice, Selection, Syntax}; +use smallvec::smallvec; + +// TODO: to contract_selection we'd need to store the previous ranges before expand. +// Maybe just contract to the first child node? +pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: &Selection) -> Selection { + let tree = syntax.root_layer.tree.as_ref().unwrap(); + + selection.transform(|range| { + let from = text.char_to_byte(range.from()); + let to = text.char_to_byte(range.to()); + + // find parent of a descendant that matches the range + let parent = match tree + .root_node() + .descendant_for_byte_range(from, to) + .and_then(|node| node.parent()) + { + Some(parent) => parent, + None => return range, + }; + + let from = text.byte_to_char(parent.start_byte()); + let to = text.byte_to_char(parent.end_byte()); + + if range.head < range.anchor { + Range::new(to, from) + } else { + Range::new(from, to) + } + }) +} diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c048ff9a6..c37c07104 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1,6 +1,7 @@ use helix_core::{ comment, graphemes, indent::TAB_WIDTH, + object, regex::{self, Regex}, register, selection, state::{Direction, Granularity, State}, @@ -1023,3 +1024,15 @@ pub fn toggle_comments(cx: &mut Context) { doc.apply(&transaction); } + +// tree sitter node selection + +pub fn expand_selection(cx: &mut Context) { + let doc = cx.doc(); + + if let Some(syntax) = &doc.syntax { + let text = doc.text().slice(..); + let selection = object::expand_selection(syntax, text, doc.selection()); + doc.set_selection(selection); + } +} diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 69c8e48ca..81665bbe0 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -164,10 +164,11 @@ pub fn default() -> Keymaps { vec![alt!('s')] => commands::split_selection_on_newline, vec![shift!('S')] => commands::split_selection, vec![key!(';')] => commands::collapse_selection, - // TODO should be alt(;) vec![alt!(';')] => commands::flip_selections, vec![key!('%')] => commands::select_all, vec![key!('x')] => commands::select_line, + // TODO: figure out what key to use + vec![key!('[')] => commands::expand_selection, vec![key!('/')] => commands::search, vec![key!('n')] => commands::search_next, vec![key!('*')] => commands::search_selection,