4 cursor
::{SyntaxNode, SyntaxToken}
,
9 pub struct SyntaxText
{
15 pub(crate) fn new(node
: SyntaxNode
) -> SyntaxText
{
16 let range
= node
.text_range();
17 SyntaxText { node, range }
20 pub fn len(&self) -> TextSize
{
24 pub fn is_empty(&self) -> bool
{
28 pub fn contains_char(&self, c
: char) -> bool
{
29 self.try_for_each_chunk(|chunk
| if chunk
.contains(c
) { Err(()) }
else { Ok(()) }
).is_err()
32 pub fn find_char(&self, c
: char) -> Option
<TextSize
> {
33 let mut acc
: TextSize
= 0.into
();
34 let res
= self.try_for_each_chunk(|chunk
| {
35 if let Some(pos
) = chunk
.find(c
) {
36 let pos
: TextSize
= (pos
as u32).into();
37 return Err(acc
+ pos
);
39 acc
+= TextSize
::of(chunk
);
45 pub fn char_at(&self, offset
: TextSize
) -> Option
<char> {
46 let offset
= offset
.into();
47 let mut start
: TextSize
= 0.into
();
48 let res
= self.try_for_each_chunk(|chunk
| {
49 let end
= start
+ TextSize
::of(chunk
);
50 if start
<= offset
&& offset
< end
{
51 let off
: usize = u32::from(offset
- start
) as usize;
52 return Err(chunk
[off
..].chars().next().unwrap());
60 pub fn slice
<R
: private
::SyntaxTextRange
>(&self, range
: R
) -> SyntaxText
{
61 let start
= range
.start().unwrap_or_default();
62 let end
= range
.end().unwrap_or(self.len());
63 assert
!(start
<= end
);
64 let len
= end
- start
;
65 let start
= self.range
.start() + start
;
66 let end
= start
+ len
;
69 "invalid slice, range: {:?}, slice: {:?}",
71 (range
.start(), range
.end()),
73 let range
= TextRange
::new(start
, end
);
75 self.range
.contains_range(range
),
76 "invalid slice, range: {:?}, slice: {:?}",
80 SyntaxText { node: self.node.clone(), range }
83 pub fn try_fold_chunks
<T
, F
, E
>(&self, init
: T
, mut f
: F
) -> Result
<T
, E
>
85 F
: FnMut(T
, &str) -> Result
<T
, E
>,
87 self.tokens_with_ranges()
88 .try_fold(init
, move |acc
, (token
, range
)| f(acc
, &token
.text()[range
]))
91 pub fn try_for_each_chunk
<F
: FnMut(&str) -> Result
<(), E
>, E
>(
95 self.try_fold_chunks((), move |(), chunk
| f(chunk
))
98 pub fn for_each_chunk
<F
: FnMut(&str)>(&self, mut f
: F
) {
100 match self.try_for_each_chunk(|chunk
| Ok
::<(), Void
>(f(chunk
))) {
102 Err(void
) => match void {}
,
106 fn tokens_with_ranges(&self) -> impl Iterator
<Item
= (SyntaxToken
, TextRange
)> {
107 let text_range
= self.range
;
108 self.node
.descendants_with_tokens().filter_map(|element
| element
.into_token()).filter_map(
110 let token_range
= token
.text_range();
111 let range
= text_range
.intersect(token_range
)?
;
112 Some((token
, range
- token_range
.start()))
118 fn found
<T
>(res
: Result
<(), T
>) -> Option
<T
> {
125 impl fmt
::Debug
for SyntaxText
{
126 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
127 fmt
::Debug
::fmt(&self.to_string(), f
)
131 impl fmt
::Display
for SyntaxText
{
132 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
133 self.try_for_each_chunk(|chunk
| fmt
::Display
::fmt(chunk
, f
))
137 impl From
<SyntaxText
> for String
{
138 fn from(text
: SyntaxText
) -> String
{
143 impl PartialEq
<str> for SyntaxText
{
144 fn eq(&self, mut rhs
: &str) -> bool
{
145 self.try_for_each_chunk(|chunk
| {
146 if !rhs
.starts_with(chunk
) {
149 rhs
= &rhs
[chunk
.len()..];
157 impl PartialEq
<SyntaxText
> for str {
158 fn eq(&self, rhs
: &SyntaxText
) -> bool
{
163 impl PartialEq
<&'_
str> for SyntaxText
{
164 fn eq(&self, rhs
: &&str) -> bool
{
169 impl PartialEq
<SyntaxText
> for &'_
str {
170 fn eq(&self, rhs
: &SyntaxText
) -> bool
{
175 impl PartialEq
for SyntaxText
{
176 fn eq(&self, other
: &SyntaxText
) -> bool
{
177 if self.range
.len() != other
.range
.len() {
180 let mut lhs
= self.tokens_with_ranges();
181 let mut rhs
= other
.tokens_with_ranges();
182 zip_texts(&mut lhs
, &mut rhs
).is_none()
183 && lhs
.all(|it
| it
.1.is_empty
())
184 && rhs
.all(|it
| it
.1.is_empty
())
188 fn zip_texts
<I
: Iterator
<Item
= (SyntaxToken
, TextRange
)>>(xs
: &mut I
, ys
: &mut I
) -> Option
<()> {
189 let mut x
= xs
.next()?
;
190 let mut y
= ys
.next()?
;
192 while x
.1.is_empty
() {
195 while y
.1.is_empty
() {
198 let x_text
= &x
.0.text()[x
.1];
199 let y_text
= &y
.0.text()[y
.1];
200 if !(x_text
.starts_with(y_text
) || y_text
.starts_with(x_text
)) {
203 let advance
= std
::cmp
::min(x
.1.len(), y
.1.len());
204 x
.1 = TextRange
::new(x
.1.start() + advance
, x
.1.end());
205 y
.1 = TextRange
::new(y
.1.start() + advance
, y
.1.end());
209 impl Eq
for SyntaxText {}
214 use crate::{TextRange, TextSize}
;
216 pub trait SyntaxTextRange
{
217 fn start(&self) -> Option
<TextSize
>;
218 fn end(&self) -> Option
<TextSize
>;
221 impl SyntaxTextRange
for TextRange
{
222 fn start(&self) -> Option
<TextSize
> {
223 Some(TextRange
::start(*self))
225 fn end(&self) -> Option
<TextSize
> {
226 Some(TextRange
::end(*self))
230 impl SyntaxTextRange
for ops
::Range
<TextSize
> {
231 fn start(&self) -> Option
<TextSize
> {
234 fn end(&self) -> Option
<TextSize
> {
239 impl SyntaxTextRange
for ops
::RangeFrom
<TextSize
> {
240 fn start(&self) -> Option
<TextSize
> {
243 fn end(&self) -> Option
<TextSize
> {
248 impl SyntaxTextRange
for ops
::RangeTo
<TextSize
> {
249 fn start(&self) -> Option
<TextSize
> {
252 fn end(&self) -> Option
<TextSize
> {
257 impl SyntaxTextRange
for ops
::RangeFull
{
258 fn start(&self) -> Option
<TextSize
> {
261 fn end(&self) -> Option
<TextSize
> {
269 use crate::{green::SyntaxKind, GreenNodeBuilder}
;
273 fn build_tree(chunks
: &[&str]) -> SyntaxNode
{
274 let mut builder
= GreenNodeBuilder
::new();
275 builder
.start_node(SyntaxKind(62));
276 for &chunk
in chunks
.iter() {
277 builder
.token(SyntaxKind(92), chunk
.into())
279 builder
.finish_node();
280 SyntaxNode
::new_root(builder
.finish())
284 fn test_text_equality() {
285 fn do_check(t1
: &[&str], t2
: &[&str]) {
286 let t1
= build_tree(t1
).text();
287 let t2
= build_tree(t2
).text();
288 let expected
= t1
.to_string() == t2
.to_string();
289 let actual
= t1
== t2
;
290 assert_eq
!(expected
, actual
, "`{}` (SyntaxText) `{}` (SyntaxText)", t1
, t2
);
291 let actual
= t1
== &*t2
.to_string();
292 assert_eq
!(expected
, actual
, "`{}` (SyntaxText) `{}` (&str)", t1
, t2
);
294 fn check(t1
: &[&str], t2
: &[&str]) {
300 check(&["a"], &[""]);
301 check(&["a"], &["a"]);
302 check(&["abc"], &["def"]);
303 check(&["hello", "world"], &["hello", "world"]);
304 check(&["hellowo", "rld"], &["hell", "oworld"]);
305 check(&["hel", "lowo", "rld"], &["helloworld"]);
306 check(&["{", "abc", "}"], &["{", "123", "}"]);
307 check(&["{", "abc", "}", "{"], &["{", "123", "}"]);
308 check(&["{", "abc", "}"], &["{", "123", "}", "{"]);
309 check(&["{", "abc", "}ab"], &["{", "abc", "}", "ab"]);