use crate::{Range, RopeSlice, Selection, Syntax}; pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: &Selection) -> Selection { let tree = syntax.tree(); selection.clone().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| { if node.child_count() == 0 || (node.start_byte() == from && node.end_byte() == to) { node.parent() } else { Some(node) } }) { 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) } }) } pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: &Selection) -> Selection { let tree = syntax.tree(); selection.clone().transform(|range| { let from = text.char_to_byte(range.from()); let to = text.char_to_byte(range.to()); let descendant = match tree.root_node().descendant_for_byte_range(from, to) { // find first child, if not possible, fallback to the node that contains selection Some(descendant) => match descendant.child(0) { Some(child) => child, None => descendant, }, None => return range, }; let from = text.byte_to_char(descendant.start_byte()); let to = text.byte_to_char(descendant.end_byte()); if range.head < range.anchor { Range::new(to, from) } else { Range::new(from, to) } }) }