aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/syntax_text.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/syntax_text.rs')
-rw-r--r--crates/ra_syntax/src/syntax_text.rs178
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 @@
1use std::{
2 fmt,
3 ops::{self, Bound},
4};
5
6use crate::{SmolStr, SyntaxElement, SyntaxNode, TextRange, TextUnit};
7
8#[derive(Clone)]
9pub struct SyntaxText {
10 node: SyntaxNode,
11 range: TextRange,
12}
13
14impl 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
136fn found<T>(res: Result<(), T>) -> Option<T> {
137 match res {
138 Ok(()) => None,
139 Err(it) => Some(it),
140 }
141}
142
143impl 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
149impl 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
155impl From<SyntaxText> for String {
156 fn from(text: SyntaxText) -> String {
157 text.to_string()
158 }
159}
160
161impl 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
174impl PartialEq<&'_ str> for SyntaxText {
175 fn eq(&self, rhs: &&str) -> bool {
176 self == *rhs
177 }
178}