use crate::{movement::Direction, 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()) as u32; let to = text.char_to_byte(range.to()) as u32; 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() as usize); let to = text.byte_to_char(node.end_byte() as usize); Range::new(to, from).with_direction(range.direction()) }) } pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { selection.transform(move |range| { let (from, to) = range.into_byte_range(text); let mut cursor = syntax.walk(); cursor.reset_to_byte_range(from, to); if let Some(node) = cursor .into_iter() .find(|node| node.is_named() && node.is_contained_within(from..to)) { return Range::from_node(node, text, range.direction()); } range }) } pub fn select_next_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { selection.transform(move |range| { let (from, to) = range.into_byte_range(text); let mut cursor = syntax.walk(); cursor.reset_to_byte_range(from, to); while !cursor.goto_next_sibling() { if !cursor.goto_parent() { return range; } } Range::from_node(cursor.node(), text, Direction::Forward) }) } pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { selection.transform(move |range| { let (from, to) = range.into_byte_range(text); let mut cursor = syntax.walk(); cursor.reset_to_byte_range(from, to); while !cursor.goto_previous_sibling() { if !cursor.goto_parent() { return range; } } Range::from_node(cursor.node(), text, Direction::Backward) }) } pub fn select_all_siblings(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { let mut cursor = syntax.walk(); selection.transform_iter(move |range| { let (from, to) = range.into_byte_range(text); cursor.reset_to_byte_range(from, to); if !cursor.goto_parent_with(|parent| parent.child_count() > 1) { return vec![range].into_iter(); } select_children(&mut cursor, text, range).into_iter() }) } pub fn select_all_children(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { let mut cursor = syntax.walk(); selection.transform_iter(move |range| { let (from, to) = range.into_byte_range(text); cursor.reset_to_byte_range(from, to); select_children(&mut cursor, text, range).into_iter() }) } fn select_children(cursor: &mut TreeCursor, text: RopeSlice, range: Range) -> Vec { let children = cursor .children() .filter(|child| child.is_named()) .map(|child| Range::from_node(child, text, range.direction())) .collect::>(); if !children.is_empty() { children } else { vec![range] } }