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