aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/algo/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/algo/mod.rs')
-rw-r--r--crates/ra_syntax/src/algo/mod.rs113
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 @@
1pub mod visit; 1pub mod visit;
2// pub mod walk;
3 2
4use crate::{text_utils::contains_offset_nonstrict, SyntaxNodeRef, TextRange, TextUnit}; 3use crate::{SyntaxNode, SyntaxNodeRef, TextRange, TextUnit};
5 4
6pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset { 5pub 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)]
47pub enum LeafAtOffset<'a> {
48 None,
49 Single(SyntaxNodeRef<'a>),
50 Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>),
51}
52 6
53impl<'a> LeafAtOffset<'a> { 7pub 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
71impl<'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
89pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef { 15pub 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
107fn 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
116pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> { 19pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> {