From 966fbc59849701dc56f70af406444c351bc9f54a Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Thu, 3 Feb 2022 13:41:25 +0530 Subject: Add tree-sitter based function, class navigation --- helix-core/src/movement.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'helix-core') diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index 47fe6827..e9cd299b 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -1,6 +1,7 @@ use std::iter; use ropey::iter::Chars; +use tree_sitter::{Node, QueryCursor}; use crate::{ chars::{categorize_char, char_is_line_ending, CharCategory}, @@ -9,7 +10,10 @@ use crate::{ next_grapheme_boundary, nth_next_grapheme_boundary, nth_prev_grapheme_boundary, prev_grapheme_boundary, }, - pos_at_coords, Position, Range, RopeSlice, + pos_at_coords, + syntax::LanguageConfiguration, + textobject::TextObject, + Position, Range, RopeSlice, }; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -305,6 +309,52 @@ fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> boo } } +pub fn goto_treesitter_object( + slice: RopeSlice, + range: Range, + object_name: &str, + dir: Direction, + slice_tree: Node, + lang_config: &LanguageConfiguration, + _count: usize, +) -> Range { + let get_range = move || -> Option { + let byte_pos = slice.char_to_byte(range.cursor(slice)); + + let capture_name = format!("{}.{}", object_name, TextObject::Around); + let mut cursor = QueryCursor::new(); + let nodes = lang_config.textobject_query()?.capture_nodes( + &capture_name, + slice_tree, + slice, + &mut cursor, + )?; + + let node = match dir { + Direction::Forward => nodes + .filter(|n| n.start_byte() > byte_pos) + .min_by_key(|n| n.start_byte())?, + Direction::Backward => nodes + .filter(|n| n.start_byte() < byte_pos) + .max_by_key(|n| n.start_byte())?, + }; + + let len = slice.len_bytes(); + let start_byte = node.start_byte(); + let end_byte = node.end_byte(); + if start_byte >= len || end_byte >= len { + return None; + } + + let start_char = slice.byte_to_char(start_byte); + let end_char = slice.byte_to_char(end_byte); + + // head of range should be at beginning + Some(Range::new(end_char, start_char)) + }; + get_range().unwrap_or(range) +} + #[cfg(test)] mod test { use ropey::Rope; -- cgit v1.2.3-70-g09d2