diff options
Diffstat (limited to 'crates/ra_syntax/src/syntax_text.rs')
-rw-r--r-- | crates/ra_syntax/src/syntax_text.rs | 178 |
1 files changed, 0 insertions, 178 deletions
diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs deleted file mode 100644 index 652cb7a1e..000000000 --- a/crates/ra_syntax/src/syntax_text.rs +++ /dev/null | |||
@@ -1,178 +0,0 @@ | |||
1 | use std::{ | ||
2 | fmt, | ||
3 | ops::{self, Bound}, | ||
4 | }; | ||
5 | |||
6 | use crate::{SmolStr, SyntaxElement, SyntaxNode, TextRange, TextUnit}; | ||
7 | |||
8 | #[derive(Clone)] | ||
9 | pub struct SyntaxText { | ||
10 | node: SyntaxNode, | ||
11 | range: TextRange, | ||
12 | } | ||
13 | |||
14 | impl SyntaxText { | ||
15 | pub(crate) fn new(node: SyntaxNode) -> SyntaxText { | ||
16 | let range = node.text_range(); | ||
17 | SyntaxText { node, range } | ||
18 | } | ||
19 | |||
20 | pub fn try_fold_chunks<T, F, E>(&self, init: T, mut f: F) -> Result<T, E> | ||
21 | where | ||
22 | F: FnMut(T, &str) -> Result<T, E>, | ||
23 | { | ||
24 | self.node.descendants_with_tokens().try_fold(init, move |acc, element| { | ||
25 | let res = match element { | ||
26 | SyntaxElement::Token(token) => { | ||
27 | let range = match self.range.intersection(&token.text_range()) { | ||
28 | None => return Ok(acc), | ||
29 | Some(it) => it, | ||
30 | }; | ||
31 | let slice = if range == token.text_range() { | ||
32 | token.text() | ||
33 | } else { | ||
34 | let range = range - token.text_range().start(); | ||
35 | &token.text()[range] | ||
36 | }; | ||
37 | f(acc, slice)? | ||
38 | } | ||
39 | SyntaxElement::Node(_) => acc, | ||
40 | }; | ||
41 | Ok(res) | ||
42 | }) | ||
43 | } | ||
44 | |||
45 | pub fn try_for_each_chunk<F: FnMut(&str) -> Result<(), E>, E>( | ||
46 | &self, | ||
47 | mut f: F, | ||
48 | ) -> Result<(), E> { | ||
49 | self.try_fold_chunks((), move |(), chunk| f(chunk)) | ||
50 | } | ||
51 | |||
52 | pub fn for_each_chunk<F: FnMut(&str)>(&self, mut f: F) { | ||
53 | enum Void {} | ||
54 | match self.try_for_each_chunk(|chunk| Ok::<(), Void>(f(chunk))) { | ||
55 | Ok(()) => (), | ||
56 | Err(void) => match void {}, | ||
57 | } | ||
58 | } | ||
59 | |||
60 | pub fn to_smol_string(&self) -> SmolStr { | ||
61 | self.to_string().into() | ||
62 | } | ||
63 | |||
64 | pub fn contains_char(&self, c: char) -> bool { | ||
65 | self.try_for_each_chunk(|chunk| if chunk.contains(c) { Err(()) } else { Ok(()) }).is_err() | ||
66 | } | ||
67 | |||
68 | pub fn find_char(&self, c: char) -> Option<TextUnit> { | ||
69 | let mut acc: TextUnit = 0.into(); | ||
70 | let res = self.try_for_each_chunk(|chunk| { | ||
71 | if let Some(pos) = chunk.find(c) { | ||
72 | let pos: TextUnit = (pos as u32).into(); | ||
73 | return Err(acc + pos); | ||
74 | } | ||
75 | acc += TextUnit::of_str(chunk); | ||
76 | Ok(()) | ||
77 | }); | ||
78 | found(res) | ||
79 | } | ||
80 | |||
81 | pub fn len(&self) -> TextUnit { | ||
82 | self.range.len() | ||
83 | } | ||
84 | |||
85 | pub fn is_empty(&self) -> bool { | ||
86 | self.range.is_empty() | ||
87 | } | ||
88 | |||
89 | pub fn slice(&self, range: impl ops::RangeBounds<TextUnit>) -> SyntaxText { | ||
90 | let start = match range.start_bound() { | ||
91 | Bound::Included(&b) => b, | ||
92 | Bound::Excluded(_) => panic!("utf-aware slicing can't work this way"), | ||
93 | Bound::Unbounded => 0.into(), | ||
94 | }; | ||
95 | let end = match range.end_bound() { | ||
96 | Bound::Included(_) => panic!("utf-aware slicing can't work this way"), | ||
97 | Bound::Excluded(&b) => b, | ||
98 | Bound::Unbounded => self.len(), | ||
99 | }; | ||
100 | assert!(start <= end); | ||
101 | let len = end - start; | ||
102 | let start = self.range.start() + start; | ||
103 | let end = start + len; | ||
104 | assert!( | ||
105 | start <= end, | ||
106 | "invalid slice, range: {:?}, slice: {:?}", | ||
107 | self.range, | ||
108 | (range.start_bound(), range.end_bound()), | ||
109 | ); | ||
110 | let range = TextRange::from_to(start, end); | ||
111 | assert!( | ||
112 | range.is_subrange(&self.range), | ||
113 | "invalid slice, range: {:?}, slice: {:?}", | ||
114 | self.range, | ||
115 | range, | ||
116 | ); | ||
117 | SyntaxText { node: self.node.clone(), range } | ||
118 | } | ||
119 | |||
120 | pub fn char_at(&self, offset: impl Into<TextUnit>) -> Option<char> { | ||
121 | let offset = offset.into(); | ||
122 | let mut start: TextUnit = 0.into(); | ||
123 | let res = self.try_for_each_chunk(|chunk| { | ||
124 | let end = start + TextUnit::of_str(chunk); | ||
125 | if start <= offset && offset < end { | ||
126 | let off: usize = u32::from(offset - start) as usize; | ||
127 | return Err(chunk[off..].chars().next().unwrap()); | ||
128 | } | ||
129 | start = end; | ||
130 | Ok(()) | ||
131 | }); | ||
132 | found(res) | ||
133 | } | ||
134 | } | ||
135 | |||
136 | fn found<T>(res: Result<(), T>) -> Option<T> { | ||
137 | match res { | ||
138 | Ok(()) => None, | ||
139 | Err(it) => Some(it), | ||
140 | } | ||
141 | } | ||
142 | |||
143 | impl fmt::Debug for SyntaxText { | ||
144 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
145 | fmt::Debug::fmt(&self.to_string(), f) | ||
146 | } | ||
147 | } | ||
148 | |||
149 | impl fmt::Display for SyntaxText { | ||
150 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
151 | self.try_for_each_chunk(|chunk| fmt::Display::fmt(chunk, f)) | ||
152 | } | ||
153 | } | ||
154 | |||
155 | impl From<SyntaxText> for String { | ||
156 | fn from(text: SyntaxText) -> String { | ||
157 | text.to_string() | ||
158 | } | ||
159 | } | ||
160 | |||
161 | impl PartialEq<str> for SyntaxText { | ||
162 | fn eq(&self, mut rhs: &str) -> bool { | ||
163 | self.try_for_each_chunk(|chunk| { | ||
164 | if !rhs.starts_with(chunk) { | ||
165 | return Err(()); | ||
166 | } | ||
167 | rhs = &rhs[chunk.len()..]; | ||
168 | Ok(()) | ||
169 | }) | ||
170 | .is_ok() | ||
171 | } | ||
172 | } | ||
173 | |||
174 | impl PartialEq<&'_ str> for SyntaxText { | ||
175 | fn eq(&self, rhs: &&str) -> bool { | ||
176 | self == *rhs | ||
177 | } | ||
178 | } | ||