diff options
Diffstat (limited to 'crates/ra_syntax/src/algo.rs')
-rw-r--r-- | crates/ra_syntax/src/algo.rs | 21 |
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 @@ | |||
1 | pub mod visit; | 1 | pub mod visit; |
2 | 2 | ||
3 | use itertools::Itertools; | ||
4 | |||
3 | use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement}; | 5 | use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement}; |
4 | 6 | ||
5 | pub use rowan::TokenAtOffset; | 7 | pub 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())`. | ||
22 | pub 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. |
24 | pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { | 40 | pub 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` |