use crate::{syntax::TreeCursor, Range, RopeSlice, Selection, Syntax}; pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { let cursor = &mut syntax.walk(); selection.transform(|range| { let from = text.char_to_byte(range.from()); let to = text.char_to_byte(range.to()); let byte_range = from..to; cursor.reset_to_byte_range(from, to); while cursor.node().byte_range() == byte_range { if !cursor.goto_parent() { break; } } let node = cursor.node(); let from = text.byte_to_char(node.start_byte()); let to = text.byte_to_char(node.end_byte()); Range::new(to, from).with_direction(range.direction()) }) } pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { select_node_impl(syntax, text, selection, |cursor| { cursor.goto_first_child(); }) } pub fn select_next_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { select_node_impl(syntax, text, selection, |cursor| { while !cursor.goto_next_sibling() { if !cursor.goto_parent() { break; } } }) } pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { select_node_impl(syntax, text, selection, |cursor| { while !cursor.goto_prev_sibling() { if !cursor.goto_parent() { break; } } }) } fn select_node_impl( syntax: &Syntax, text: RopeSlice, selection: Selection, motion: F, ) -> Selection where F: Fn(&mut TreeCursor), { let cursor = &mut syntax.walk(); selection.transform(|range| { let from = text.char_to_byte(range.from()); let to = text.char_to_byte(range.to()); cursor.reset_to_byte_range(from, to); motion(cursor); let node = cursor.node(); let from = text.byte_to_char(node.start_byte()); let to = text.byte_to_char(node.end_byte()); Range::new(from, to).with_direction(range.direction()) }) }