feat(command): select_all_children
This commit is contained in:
parent
87c4161732
commit
fa67c5c474
4 changed files with 170 additions and 6 deletions
|
@ -63,7 +63,21 @@ pub fn select_all_siblings(tree: &Tree, text: RopeSlice, selection: Selection) -
|
||||||
root_node
|
root_node
|
||||||
.descendant_for_byte_range(from, to)
|
.descendant_for_byte_range(from, to)
|
||||||
.and_then(find_parent_with_more_children)
|
.and_then(find_parent_with_more_children)
|
||||||
.map(|parent| select_children(parent, text, range.direction()))
|
.and_then(|parent| select_children(parent, text, range.direction()))
|
||||||
|
.unwrap_or_else(|| vec![range].into_iter())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_all_children(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(|parent| select_children(parent, text, range.direction()))
|
||||||
.unwrap_or_else(|| vec![range].into_iter())
|
.unwrap_or_else(|| vec![range].into_iter())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -72,10 +86,11 @@ fn select_children(
|
||||||
node: Node,
|
node: Node,
|
||||||
text: RopeSlice,
|
text: RopeSlice,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
) -> <Vec<Range> as std::iter::IntoIterator>::IntoIter {
|
) -> Option<<Vec<Range> as std::iter::IntoIterator>::IntoIter> {
|
||||||
let mut cursor = node.walk();
|
let mut cursor = node.walk();
|
||||||
|
|
||||||
node.named_children(&mut cursor)
|
let children = node
|
||||||
|
.named_children(&mut cursor)
|
||||||
.map(|child| {
|
.map(|child| {
|
||||||
let from = text.byte_to_char(child.start_byte());
|
let from = text.byte_to_char(child.start_byte());
|
||||||
let to = text.byte_to_char(child.end_byte());
|
let to = text.byte_to_char(child.end_byte());
|
||||||
|
@ -86,8 +101,13 @@ fn select_children(
|
||||||
Range::new(from, to)
|
Range::new(from, to)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>();
|
||||||
.into_iter()
|
|
||||||
|
if !children.is_empty() {
|
||||||
|
Some(children.into_iter())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_sibling_recursive<F>(node: Node, sibling_fn: F) -> Option<Node>
|
fn find_sibling_recursive<F>(node: Node, sibling_fn: F) -> Option<Node>
|
||||||
|
|
|
@ -440,7 +440,8 @@ impl MappableCommand {
|
||||||
shrink_selection, "Shrink selection to previously expanded syntax node",
|
shrink_selection, "Shrink selection to previously expanded syntax node",
|
||||||
select_next_sibling, "Select next sibling in the syntax tree",
|
select_next_sibling, "Select next sibling in the syntax tree",
|
||||||
select_prev_sibling, "Select previous sibling the in syntax tree",
|
select_prev_sibling, "Select previous sibling the in syntax tree",
|
||||||
select_all_siblings, "Select all siblings in the syntax tree",
|
select_all_siblings, "Select all siblings of the current node",
|
||||||
|
select_all_children, "Select all children of the current node",
|
||||||
jump_forward, "Jump forward on jumplist",
|
jump_forward, "Jump forward on jumplist",
|
||||||
jump_backward, "Jump backward on jumplist",
|
jump_backward, "Jump backward on jumplist",
|
||||||
save_selection, "Save current selection to jumplist",
|
save_selection, "Save current selection to jumplist",
|
||||||
|
@ -4991,6 +4992,23 @@ fn select_all_siblings(cx: &mut Context) {
|
||||||
cx.editor.apply_motion(motion);
|
cx.editor.apply_motion(motion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
motion(cx.editor);
|
||||||
|
cx.editor.last_motion = Some(Motion(Box::new(motion)));
|
||||||
|
}
|
||||||
|
|
||||||
fn match_brackets(cx: &mut Context) {
|
fn match_brackets(cx: &mut Context) {
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let is_select = cx.editor.mode == Mode::Select;
|
let is_select = cx.editor.mode == Mode::Select;
|
||||||
|
|
|
@ -87,6 +87,7 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
|
||||||
"A-;" => flip_selections,
|
"A-;" => flip_selections,
|
||||||
"A-o" | "A-up" => expand_selection,
|
"A-o" | "A-up" => expand_selection,
|
||||||
"A-i" | "A-down" => shrink_selection,
|
"A-i" | "A-down" => shrink_selection,
|
||||||
|
"A-I" | "A-S-down" => select_all_children,
|
||||||
"A-p" | "A-left" => select_prev_sibling,
|
"A-p" | "A-left" => select_prev_sibling,
|
||||||
"A-n" | "A-right" => select_next_sibling,
|
"A-n" | "A-right" => select_next_sibling,
|
||||||
"A-e" => move_parent_node_end,
|
"A-e" => move_parent_node_end,
|
||||||
|
|
|
@ -601,3 +601,128 @@ async fn select_all_siblings() -> anyhow::Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn select_all_children() -> anyhow::Result<()> {
|
||||||
|
let tests = vec![
|
||||||
|
// basic tests
|
||||||
|
(
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let foo = bar#[(a, b, c)|]#;
|
||||||
|
"##}),
|
||||||
|
"<A-I>",
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let foo = bar(#[a|]#, #(b|)#, #(c|)#);
|
||||||
|
"##}),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = #[[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
]|]#;
|
||||||
|
"##}),
|
||||||
|
"<A-I>",
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = [
|
||||||
|
#[1|]#,
|
||||||
|
#(2|)#,
|
||||||
|
#(3|)#,
|
||||||
|
#(4|)#,
|
||||||
|
#(5|)#,
|
||||||
|
];
|
||||||
|
"##}),
|
||||||
|
),
|
||||||
|
// direction is preserved
|
||||||
|
(
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = #[|[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
]]#;
|
||||||
|
"##}),
|
||||||
|
"<A-I>",
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = [
|
||||||
|
#[|1]#,
|
||||||
|
#(|2)#,
|
||||||
|
#(|3)#,
|
||||||
|
#(|4)#,
|
||||||
|
#(|5)#,
|
||||||
|
];
|
||||||
|
"##}),
|
||||||
|
),
|
||||||
|
// can't pick any more children - selection stays the same
|
||||||
|
(
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = [
|
||||||
|
#[1|]#,
|
||||||
|
#(2|)#,
|
||||||
|
#(3|)#,
|
||||||
|
#(4|)#,
|
||||||
|
#(5|)#,
|
||||||
|
];
|
||||||
|
"##}),
|
||||||
|
"<A-I>",
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = [
|
||||||
|
#[1|]#,
|
||||||
|
#(2|)#,
|
||||||
|
#(3|)#,
|
||||||
|
#(4|)#,
|
||||||
|
#(5|)#,
|
||||||
|
];
|
||||||
|
"##}),
|
||||||
|
),
|
||||||
|
// each cursor does the sibling select independently
|
||||||
|
(
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = #[|[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
]]#;
|
||||||
|
|
||||||
|
let b = #([
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
"three",
|
||||||
|
"four",
|
||||||
|
"five",
|
||||||
|
]|)#;
|
||||||
|
"##}),
|
||||||
|
"<A-I>",
|
||||||
|
helpers::platform_line(indoc! {r##"
|
||||||
|
let a = [
|
||||||
|
#[|1]#,
|
||||||
|
#(|2)#,
|
||||||
|
#(|3)#,
|
||||||
|
#(|4)#,
|
||||||
|
#(|5)#,
|
||||||
|
];
|
||||||
|
|
||||||
|
let b = [
|
||||||
|
#("one"|)#,
|
||||||
|
#("two"|)#,
|
||||||
|
#("three"|)#,
|
||||||
|
#("four"|)#,
|
||||||
|
#("five"|)#,
|
||||||
|
];
|
||||||
|
"##}),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for test in tests {
|
||||||
|
test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue