aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/algo.rs21
1 files changed, 18 insertions, 3 deletions
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 1f68fe467..d31d00343 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -1,5 +1,7 @@
1pub mod visit; 1pub mod visit;
2 2
3use itertools::Itertools;
4
3use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement}; 5use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement};
4 6
5pub use rowan::TokenAtOffset; 7pub use rowan::TokenAtOffset;
@@ -12,6 +14,20 @@ pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffse
12 } 14 }
13} 15}
14 16
17/// Returns ancestors of the node at the offset, sorted by length. This should
18/// do the right thing at an edge, e.g. when searching for expressions at `{
19/// <|>foo }` we will get the name reference instead of the whole block, which
20/// we would get if we just did `find_token_at_offset(...).flat_map(|t|
21/// t.parent().ancestors())`.
22pub fn ancestors_at_offset(
23 node: &SyntaxNode,
24 offset: TextUnit,
25) -> impl Iterator<Item = &SyntaxNode> {
26 find_token_at_offset(node, offset)
27 .map(|token| token.parent().ancestors())
28 .kmerge_by(|node1, node2| node1.range().len() < node2.range().len())
29}
30
15/// Finds a node of specific Ast type at offset. Note that this is slightly 31/// Finds a node of specific Ast type at offset. Note that this is slightly
16/// imprecise: if the cursor is strictly between two nodes of the desired type, 32/// imprecise: if the cursor is strictly between two nodes of the desired type,
17/// as in 33/// as in
@@ -20,10 +36,9 @@ pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffse
20/// struct Foo {}|struct Bar; 36/// struct Foo {}|struct Bar;
21/// ``` 37/// ```
22/// 38///
23/// then the left node will be silently preferred. 39/// then the shorter node will be silently preferred.
24pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { 40pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> {
25 find_token_at_offset(syntax, offset) 41 ancestors_at_offset(syntax, offset).find_map(N::cast)
26 .find_map(|leaf| leaf.parent().ancestors().find_map(N::cast))
27} 42}
28 43
29/// Finds the first sibling in the given direction which is not `trivia` 44/// Finds the first sibling in the given direction which is not `trivia`