mirror of
https://github.com/helix-editor/helix.git
synced 2024-08-17 06:40:47 +03:00
Use new in-crate TreeCursor
This commit is contained in:
parent
fa67c5c474
commit
c99c333337
@ -1,5 +1,4 @@
|
||||
use crate::{movement::Direction, syntax::TreeCursor, Range, RopeSlice, Selection, Syntax};
|
||||
use tree_sitter::{Node, Tree};
|
||||
use crate::{syntax::TreeCursor, Range, RopeSlice, Selection, Syntax};
|
||||
|
||||
pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
|
||||
let cursor = &mut syntax.walk();
|
||||
@ -41,85 +40,46 @@ pub fn select_next_sibling(syntax: &Syntax, text: RopeSlice, selection: Selectio
|
||||
})
|
||||
}
|
||||
|
||||
fn find_parent_with_more_children(mut node: Node) -> Option<Node> {
|
||||
while let Some(parent) = node.parent() {
|
||||
if parent.child_count() > 1 {
|
||||
return Some(parent);
|
||||
pub fn select_all_siblings(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
|
||||
selection.transform_iter(|range| {
|
||||
let mut cursor = syntax.walk();
|
||||
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();
|
||||
}
|
||||
|
||||
node = parent;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn select_all_siblings(tree: &Tree, text: RopeSlice, selection: Selection) -> Selection {
|
||||
let root_node = &tree.root_node();
|
||||
|
||||
selection.transform_iter(|range| {
|
||||
let from = text.char_to_byte(range.from());
|
||||
let to = text.char_to_byte(range.to());
|
||||
|
||||
root_node
|
||||
.descendant_for_byte_range(from, to)
|
||||
.and_then(find_parent_with_more_children)
|
||||
.and_then(|parent| select_children(parent, text, range.direction()))
|
||||
.unwrap_or_else(|| vec![range].into_iter())
|
||||
select_children(&mut cursor, text, range).into_iter()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn select_all_children(tree: &Tree, text: RopeSlice, selection: Selection) -> Selection {
|
||||
let root_node = &tree.root_node();
|
||||
|
||||
pub fn select_all_children(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
|
||||
selection.transform_iter(|range| {
|
||||
let from = text.char_to_byte(range.from());
|
||||
let to = text.char_to_byte(range.to());
|
||||
|
||||
root_node
|
||||
.descendant_for_byte_range(from, to)
|
||||
.and_then(|parent| select_children(parent, text, range.direction()))
|
||||
.unwrap_or_else(|| vec![range].into_iter())
|
||||
let mut cursor = syntax.walk();
|
||||
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(
|
||||
node: Node,
|
||||
fn select_children<'n>(
|
||||
cursor: &'n mut TreeCursor<'n>,
|
||||
text: RopeSlice,
|
||||
direction: Direction,
|
||||
) -> Option<<Vec<Range> as std::iter::IntoIterator>::IntoIter> {
|
||||
let mut cursor = node.walk();
|
||||
|
||||
let children = node
|
||||
.named_children(&mut cursor)
|
||||
.map(|child| {
|
||||
let from = text.byte_to_char(child.start_byte());
|
||||
let to = text.byte_to_char(child.end_byte());
|
||||
|
||||
if direction == Direction::Backward {
|
||||
Range::new(to, from)
|
||||
} else {
|
||||
Range::new(from, to)
|
||||
}
|
||||
})
|
||||
range: Range,
|
||||
) -> Vec<Range> {
|
||||
let children = cursor
|
||||
.named_children()
|
||||
.map(|child| Range::from_node(child, text, range.direction()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !children.is_empty() {
|
||||
Some(children.into_iter())
|
||||
children
|
||||
} else {
|
||||
None
|
||||
vec![range]
|
||||
}
|
||||
}
|
||||
|
||||
fn find_sibling_recursive<F>(node: Node, sibling_fn: F) -> Option<Node>
|
||||
where
|
||||
F: Fn(Node) -> Option<Node>,
|
||||
{
|
||||
sibling_fn(node).or_else(|| {
|
||||
node.parent()
|
||||
.and_then(|node| find_sibling_recursive(node, sibling_fn))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
|
||||
select_node_impl(syntax, text, selection, |cursor| {
|
||||
while !cursor.goto_prev_sibling() {
|
||||
|
@ -90,6 +90,19 @@ pub fn goto_parent(&mut self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn goto_parent_with<P>(&mut self, predicate: P) -> bool
|
||||
where
|
||||
P: Fn(&Node) -> bool,
|
||||
{
|
||||
while self.goto_parent() {
|
||||
if predicate(&self.node()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Finds the injection layer that has exactly the same range as the given `range`.
|
||||
fn layer_id_of_byte_range(&self, search_range: Range<usize>) -> Option<LayerId> {
|
||||
let start_idx = self
|
||||
@ -102,7 +115,7 @@ fn layer_id_of_byte_range(&self, search_range: Range<usize>) -> Option<LayerId>
|
||||
.find_map(|range| (range.start == search_range.start).then_some(range.layer_id))
|
||||
}
|
||||
|
||||
pub fn goto_first_child(&mut self) -> bool {
|
||||
fn goto_first_child_impl(&mut self, named: bool) -> bool {
|
||||
// Check if the current node's range is an exact injection layer range.
|
||||
if let Some(layer_id) = self
|
||||
.layer_id_of_byte_range(self.node().byte_range())
|
||||
@ -111,8 +124,16 @@ pub fn goto_first_child(&mut self) -> bool {
|
||||
// Switch to the child layer.
|
||||
self.current = layer_id;
|
||||
self.cursor = self.layers[self.current].tree().root_node();
|
||||
true
|
||||
} else if let Some(child) = self.cursor.child(0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let child = if named {
|
||||
self.cursor.named_child(0)
|
||||
} else {
|
||||
self.cursor.child(0)
|
||||
};
|
||||
|
||||
if let Some(child) = child {
|
||||
// Otherwise descend in the current tree.
|
||||
self.cursor = child;
|
||||
true
|
||||
@ -121,8 +142,45 @@ pub fn goto_first_child(&mut self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn goto_first_child(&mut self) -> bool {
|
||||
self.goto_first_child_impl(false)
|
||||
}
|
||||
|
||||
pub fn goto_first_named_child(&mut self) -> bool {
|
||||
self.goto_first_child_impl(true)
|
||||
}
|
||||
|
||||
fn goto_next_sibling_impl(&mut self, named: bool) -> bool {
|
||||
let sibling = if named {
|
||||
self.cursor.next_named_sibling()
|
||||
} else {
|
||||
self.cursor.next_sibling()
|
||||
};
|
||||
|
||||
if let Some(sibling) = sibling {
|
||||
self.cursor = sibling;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn goto_next_sibling(&mut self) -> bool {
|
||||
if let Some(sibling) = self.cursor.next_sibling() {
|
||||
self.goto_next_sibling_impl(false)
|
||||
}
|
||||
|
||||
pub fn goto_next_named_sibling(&mut self) -> bool {
|
||||
self.goto_next_sibling_impl(true)
|
||||
}
|
||||
|
||||
fn goto_prev_sibling_impl(&mut self, named: bool) -> bool {
|
||||
let sibling = if named {
|
||||
self.cursor.prev_named_sibling()
|
||||
} else {
|
||||
self.cursor.prev_sibling()
|
||||
};
|
||||
|
||||
if let Some(sibling) = sibling {
|
||||
self.cursor = sibling;
|
||||
true
|
||||
} else {
|
||||
@ -131,12 +189,11 @@ pub fn goto_next_sibling(&mut self) -> bool {
|
||||
}
|
||||
|
||||
pub fn goto_prev_sibling(&mut self) -> bool {
|
||||
if let Some(sibling) = self.cursor.prev_sibling() {
|
||||
self.cursor = sibling;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.goto_prev_sibling_impl(false)
|
||||
}
|
||||
|
||||
pub fn goto_prev_named_sibling(&mut self) -> bool {
|
||||
self.goto_prev_sibling_impl(true)
|
||||
}
|
||||
|
||||
/// Finds the injection layer that contains the given start-end range.
|
||||
@ -157,4 +214,51 @@ pub fn reset_to_byte_range(&mut self, start: usize, end: usize) {
|
||||
let root = self.layers[self.current].tree().root_node();
|
||||
self.cursor = root.descendant_for_byte_range(start, end).unwrap_or(root);
|
||||
}
|
||||
|
||||
/// Returns an iterator over the children of the node the TreeCursor is on
|
||||
/// at the time this is called.
|
||||
pub fn children(&'a mut self) -> ChildIter {
|
||||
let parent = self.node();
|
||||
|
||||
ChildIter {
|
||||
cursor: self,
|
||||
parent,
|
||||
named: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the named children of the node the TreeCursor is on
|
||||
/// at the time this is called.
|
||||
pub fn named_children(&'a mut self) -> ChildIter {
|
||||
let parent = self.node();
|
||||
|
||||
ChildIter {
|
||||
cursor: self,
|
||||
parent,
|
||||
named: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChildIter<'n> {
|
||||
cursor: &'n mut TreeCursor<'n>,
|
||||
parent: Node<'n>,
|
||||
named: bool,
|
||||
}
|
||||
|
||||
impl<'n> Iterator for ChildIter<'n> {
|
||||
type Item = Node<'n>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// first iteration, just visit the first child
|
||||
if self.cursor.node() == self.parent {
|
||||
self.cursor
|
||||
.goto_first_child_impl(self.named)
|
||||
.then(|| self.cursor.node())
|
||||
} else {
|
||||
self.cursor
|
||||
.goto_next_sibling_impl(self.named)
|
||||
.then(|| self.cursor.node())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
textobject,
|
||||
unicode::width::UnicodeWidthChar,
|
||||
visual_offset_from_block, Deletion, LineEnding, Position, Range, Rope, RopeGraphemes,
|
||||
RopeReader, RopeSlice, Selection, SmallVec, Tendril, Transaction,
|
||||
RopeReader, RopeSlice, Selection, SmallVec, Syntax, Tendril, Transaction,
|
||||
};
|
||||
use helix_view::{
|
||||
document::{FormatterError, Mode, SCRATCH_BUFFER_NAME},
|
||||
@ -4976,17 +4976,23 @@ pub fn extend_parent_node_start(cx: &mut Context) {
|
||||
move_node_bound_impl(cx, Direction::Backward, Movement::Extend)
|
||||
}
|
||||
|
||||
fn select_all_impl<F>(editor: &mut Editor, select_fn: F)
|
||||
where
|
||||
F: Fn(&Syntax, RopeSlice, Selection) -> Selection,
|
||||
{
|
||||
let (view, doc) = current!(editor);
|
||||
|
||||
if let Some(syntax) = doc.syntax() {
|
||||
let text = doc.text().slice(..);
|
||||
let current_selection = doc.selection(view.id);
|
||||
let selection = select_fn(syntax, text, current_selection.clone());
|
||||
doc.set_selection(view.id, selection);
|
||||
}
|
||||
}
|
||||
|
||||
fn select_all_siblings(cx: &mut Context) {
|
||||
let motion = |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
|
||||
if let Some(syntax) = doc.syntax() {
|
||||
let text = doc.text().slice(..);
|
||||
let current_selection = doc.selection(view.id);
|
||||
let selection =
|
||||
object::select_all_siblings(syntax.tree(), text, current_selection.clone());
|
||||
doc.set_selection(view.id, selection);
|
||||
}
|
||||
select_all_impl(editor, object::select_all_siblings);
|
||||
};
|
||||
|
||||
cx.editor.apply_motion(motion);
|
||||
@ -4994,19 +5000,10 @@ fn select_all_siblings(cx: &mut Context) {
|
||||
|
||||
fn select_all_children(cx: &mut Context) {
|
||||
let motion = |editor: &mut Editor| {
|
||||
let (view, doc) = current!(editor);
|
||||
|
||||
if let Some(syntax) = doc.syntax() {
|
||||
let text = doc.text().slice(..);
|
||||
let current_selection = doc.selection(view.id);
|
||||
let selection =
|
||||
object::select_all_children(syntax.tree(), text, current_selection.clone());
|
||||
doc.set_selection(view.id, selection);
|
||||
}
|
||||
select_all_impl(editor, object::select_all_children);
|
||||
};
|
||||
|
||||
motion(cx.editor);
|
||||
cx.editor.last_motion = Some(Motion(Box::new(motion)));
|
||||
cx.editor.apply_motion(motion);
|
||||
}
|
||||
|
||||
fn match_brackets(cx: &mut Context) {
|
||||
@ -6040,7 +6037,10 @@ fn jump_to_label(cx: &mut Context, labels: Vec<Range>, behaviour: Movement) {
|
||||
let doc = doc.id();
|
||||
cx.on_next_key(move |cx, event| {
|
||||
let alphabet = &cx.editor.config().jump_label_alphabet;
|
||||
let Some(i ) = event.char().and_then(|ch| alphabet.iter().position(|&it| it == ch)) else {
|
||||
let Some(i) = event
|
||||
.char()
|
||||
.and_then(|ch| alphabet.iter().position(|&it| it == ch))
|
||||
else {
|
||||
doc_mut!(cx.editor, &doc).remove_jump_labels(view);
|
||||
return;
|
||||
};
|
||||
@ -6053,7 +6053,10 @@ fn jump_to_label(cx: &mut Context, labels: Vec<Range>, behaviour: Movement) {
|
||||
cx.on_next_key(move |cx, event| {
|
||||
doc_mut!(cx.editor, &doc).remove_jump_labels(view);
|
||||
let alphabet = &cx.editor.config().jump_label_alphabet;
|
||||
let Some(inner ) = event.char().and_then(|ch| alphabet.iter().position(|&it| it == ch)) else {
|
||||
let Some(inner) = event
|
||||
.char()
|
||||
.and_then(|ch| alphabet.iter().position(|&it| it == ch))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if let Some(mut range) = labels.get(outer + inner).copied() {
|
||||
@ -6073,8 +6076,8 @@ fn jump_to_label(cx: &mut Context, labels: Vec<Range>, behaviour: Movement) {
|
||||
to
|
||||
}
|
||||
};
|
||||
Range::new(anchor, range.head)
|
||||
}else{
|
||||
Range::new(anchor, range.head)
|
||||
} else {
|
||||
range.with_direction(Direction::Forward)
|
||||
};
|
||||
doc_mut!(cx.editor, &doc).set_selection(view, range.into());
|
||||
|
@ -607,16 +607,16 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
let tests = vec![
|
||||
// basic tests
|
||||
(
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let foo = bar#[(a, b, c)|]#;
|
||||
"##}),
|
||||
"##},
|
||||
"<A-I>",
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let foo = bar(#[a|]#, #(b|)#, #(c|)#);
|
||||
"##}),
|
||||
"##},
|
||||
),
|
||||
(
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = #[[
|
||||
1,
|
||||
2,
|
||||
@ -624,9 +624,9 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
4,
|
||||
5,
|
||||
]|]#;
|
||||
"##}),
|
||||
"##},
|
||||
"<A-I>",
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = [
|
||||
#[1|]#,
|
||||
#(2|)#,
|
||||
@ -634,11 +634,11 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
#(4|)#,
|
||||
#(5|)#,
|
||||
];
|
||||
"##}),
|
||||
"##},
|
||||
),
|
||||
// direction is preserved
|
||||
(
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = #[|[
|
||||
1,
|
||||
2,
|
||||
@ -646,9 +646,9 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
4,
|
||||
5,
|
||||
]]#;
|
||||
"##}),
|
||||
"##},
|
||||
"<A-I>",
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = [
|
||||
#[|1]#,
|
||||
#(|2)#,
|
||||
@ -656,11 +656,11 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
#(|4)#,
|
||||
#(|5)#,
|
||||
];
|
||||
"##}),
|
||||
"##},
|
||||
),
|
||||
// can't pick any more children - selection stays the same
|
||||
(
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = [
|
||||
#[1|]#,
|
||||
#(2|)#,
|
||||
@ -668,9 +668,9 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
#(4|)#,
|
||||
#(5|)#,
|
||||
];
|
||||
"##}),
|
||||
"##},
|
||||
"<A-I>",
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = [
|
||||
#[1|]#,
|
||||
#(2|)#,
|
||||
@ -678,11 +678,11 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
#(4|)#,
|
||||
#(5|)#,
|
||||
];
|
||||
"##}),
|
||||
"##},
|
||||
),
|
||||
// each cursor does the sibling select independently
|
||||
(
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = #[|[
|
||||
1,
|
||||
2,
|
||||
@ -698,9 +698,9 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
"four",
|
||||
"five",
|
||||
]|)#;
|
||||
"##}),
|
||||
"##},
|
||||
"<A-I>",
|
||||
helpers::platform_line(indoc! {r##"
|
||||
indoc! {r##"
|
||||
let a = [
|
||||
#[|1]#,
|
||||
#(|2)#,
|
||||
@ -716,7 +716,7 @@ async fn select_all_children() -> anyhow::Result<()> {
|
||||
#("four"|)#,
|
||||
#("five"|)#,
|
||||
];
|
||||
"##}),
|
||||
"##},
|
||||
),
|
||||
];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user