diff options
Diffstat (limited to 'crates/ra_syntax/src/algo/mod.rs')
-rw-r--r-- | crates/ra_syntax/src/algo/mod.rs | 113 |
1 files changed, 8 insertions, 105 deletions
diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs index faf5a6211..4b3548ea9 100644 --- a/crates/ra_syntax/src/algo/mod.rs +++ b/crates/ra_syntax/src/algo/mod.rs | |||
@@ -1,116 +1,19 @@ | |||
1 | pub mod visit; | 1 | pub mod visit; |
2 | // pub mod walk; | ||
3 | 2 | ||
4 | use crate::{text_utils::contains_offset_nonstrict, SyntaxNodeRef, TextRange, TextUnit}; | 3 | use crate::{SyntaxNode, SyntaxNodeRef, TextRange, TextUnit}; |
5 | 4 | ||
6 | pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset { | 5 | pub use rowan::LeafAtOffset; |
7 | let range = node.range(); | ||
8 | assert!( | ||
9 | contains_offset_nonstrict(range, offset), | ||
10 | "Bad offset: range {:?} offset {:?}", | ||
11 | range, | ||
12 | offset | ||
13 | ); | ||
14 | if range.is_empty() { | ||
15 | return LeafAtOffset::None; | ||
16 | } | ||
17 | |||
18 | if node.is_leaf() { | ||
19 | return LeafAtOffset::Single(node); | ||
20 | } | ||
21 | |||
22 | let mut children = node.children().filter(|child| { | ||
23 | let child_range = child.range(); | ||
24 | !child_range.is_empty() && contains_offset_nonstrict(child_range, offset) | ||
25 | }); | ||
26 | |||
27 | let left = children.next().unwrap(); | ||
28 | let right = children.next(); | ||
29 | assert!(children.next().is_none()); | ||
30 | |||
31 | if let Some(right) = right { | ||
32 | match ( | ||
33 | find_leaf_at_offset(left, offset), | ||
34 | find_leaf_at_offset(right, offset), | ||
35 | ) { | ||
36 | (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => { | ||
37 | LeafAtOffset::Between(left, right) | ||
38 | } | ||
39 | _ => unreachable!(), | ||
40 | } | ||
41 | } else { | ||
42 | find_leaf_at_offset(left, offset) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | #[derive(Clone, Debug)] | ||
47 | pub enum LeafAtOffset<'a> { | ||
48 | None, | ||
49 | Single(SyntaxNodeRef<'a>), | ||
50 | Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>), | ||
51 | } | ||
52 | 6 | ||
53 | impl<'a> LeafAtOffset<'a> { | 7 | pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset<SyntaxNodeRef> { |
54 | pub fn right_biased(self) -> Option<SyntaxNodeRef<'a>> { | 8 | match node.0.leaf_at_offset(offset) { |
55 | match self { | 9 | LeafAtOffset::None => LeafAtOffset::None, |
56 | LeafAtOffset::None => None, | 10 | LeafAtOffset::Single(n) => LeafAtOffset::Single(SyntaxNode(n)), |
57 | LeafAtOffset::Single(node) => Some(node), | 11 | LeafAtOffset::Between(l, r) => LeafAtOffset::Between(SyntaxNode(l), SyntaxNode(r)), |
58 | LeafAtOffset::Between(_, right) => Some(right), | ||
59 | } | ||
60 | } | ||
61 | |||
62 | pub fn left_biased(self) -> Option<SyntaxNodeRef<'a>> { | ||
63 | match self { | ||
64 | LeafAtOffset::None => None, | ||
65 | LeafAtOffset::Single(node) => Some(node), | ||
66 | LeafAtOffset::Between(left, _) => Some(left), | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | impl<'f> Iterator for LeafAtOffset<'f> { | ||
72 | type Item = SyntaxNodeRef<'f>; | ||
73 | |||
74 | fn next(&mut self) -> Option<SyntaxNodeRef<'f>> { | ||
75 | match *self { | ||
76 | LeafAtOffset::None => None, | ||
77 | LeafAtOffset::Single(node) => { | ||
78 | *self = LeafAtOffset::None; | ||
79 | Some(node) | ||
80 | } | ||
81 | LeafAtOffset::Between(left, right) => { | ||
82 | *self = LeafAtOffset::Single(right); | ||
83 | Some(left) | ||
84 | } | ||
85 | } | ||
86 | } | 12 | } |
87 | } | 13 | } |
88 | 14 | ||
89 | pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef { | 15 | pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef { |
90 | assert!( | 16 | SyntaxNode(root.0.covering_node(range)) |
91 | range.is_subrange(&root.range()), | ||
92 | "node range: {:?}, target range: {:?}", | ||
93 | root.range(), | ||
94 | range, | ||
95 | ); | ||
96 | let (left, right) = match ( | ||
97 | find_leaf_at_offset(root, range.start()).right_biased(), | ||
98 | find_leaf_at_offset(root, range.end()).left_biased(), | ||
99 | ) { | ||
100 | (Some(l), Some(r)) => (l, r), | ||
101 | _ => return root, | ||
102 | }; | ||
103 | |||
104 | common_ancestor(left, right) | ||
105 | } | ||
106 | |||
107 | fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> { | ||
108 | for p in n1.ancestors() { | ||
109 | if n2.ancestors().any(|a| a == p) { | ||
110 | return p; | ||
111 | } | ||
112 | } | ||
113 | panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) | ||
114 | } | 17 | } |
115 | 18 | ||
116 | pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> { | 19 | pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> { |