Skip to main content

line_column/
span.rs

1//! Out of the box [`Span`] for storing source code and text range.
2
3use core::{fmt, ops};
4use std::string::String;
5
6#[cfg(feature = "sync")]
7use std::sync::Arc;
8#[cfg(not(feature = "sync"))]
9use std::rc::Rc as Arc;
10
11pub use text_size::{TextRange, TextSize};
12
13pub mod wrapper;
14
15/// [`text_size::TextRange`] wrapper
16///
17/// Stored source code pointers, allowing for easy retrieval of lines, columns, and source code text
18///
19/// If `len() == 0`, it is used to indicate offset
20///
21/// **NOTE**: Default [`Span`] not implement [`Sync`] and [`Send`], about `sync` feature
22///
23/// # Examples
24///
25/// ```
26/// use line_column::span::*;
27///
28/// let source = Span::new_full("foo,bar,baz");
29/// let comma = source.create(TextRange::at(3.into(), TextSize::of(',')));
30/// let bar = comma.after().take(TextSize::of("bar"));
31///
32/// assert_eq!(comma.text(), ",");
33/// assert_eq!(bar.text(), "bar");
34/// assert_eq!(bar.source(), "foo,bar,baz");
35/// assert_eq!(bar.line_column(), (1, 5));
36/// ```
37#[derive(Clone, Default)]
38pub struct Span {
39    source: Arc<String>,
40    range: TextRange,
41}
42
43impl fmt::Debug for Span {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        let text = self.text();
46        write!(f, "Span({text:?}@{:?})", self.range())
47    }
48}
49
50impl Span {
51    /// New a source and span range.
52    ///
53    /// **NOTE**: It is not recommended to call repeatedly,
54    /// otherwise the `source` will be allocated repeatedly.  Consider using [`Span::create`]
55    ///
56    /// # Panics
57    ///
58    /// - Panics if `range` out of source.
59    /// - Panics if `source.len()` out of [`TextSize`].
60    ///
61    /// # Examples
62    ///
63    /// ```
64    /// use line_column::span::*;
65    ///
66    /// let source = "abcdef";
67    /// let span = Span::new(source, TextRange::new(2.into(), 4.into()));
68    /// assert_eq!(span.text(), "cd");
69    /// ```
70    #[inline]
71    #[track_caller]
72    pub fn new(source: impl Into<String>, range: TextRange) -> Self {
73        Self::checked_new(source.into().into(), range)
74    }
75
76    /// New a full span of source.
77    ///
78    /// **NOTE**: It is not recommended to call repeatedly,
79    /// otherwise the `source` will be allocated repeatedly.  Consider using [`Span::create`]
80    ///
81    /// # Panics
82    ///
83    /// - Panics if `source.len()` out of [`TextSize`].
84    ///
85    /// # Examples
86    ///
87    /// ```
88    /// use line_column::span::*;
89    ///
90    /// let source = "abcdef";
91    /// let full = Span::new_full(source);
92    /// assert_eq!(full.text(), "abcdef");
93    /// ```
94    #[inline]
95    pub fn new_full(source: impl Into<String>) -> Self {
96        let source = source.into();
97        let range = TextRange::up_to(len_size(source.len()));
98        Self::checked_new(source.into(), range)
99    }
100
101    /// New a span **source** range from exist span.
102    ///
103    /// # Panics
104    ///
105    /// - Panics if `range` out of source.
106    ///
107    /// # Examples
108    ///
109    /// ```
110    /// use line_column::span::*;
111    ///
112    /// let source = "abcdef";
113    /// let full = Span::new_full(source);
114    /// assert_eq!(full.text(), "abcdef");
115    ///
116    /// let span = full.create(TextRange::at(1.into(), 3.into()));
117    /// assert_eq!(span.text(), "bcd");
118    /// let span2 = span.create(TextRange::at(3.into(), 3.into()));
119    /// assert_eq!(span2.text(), "def");
120    /// ```
121    #[inline]
122    #[track_caller]
123    pub fn create(&self, range: TextRange) -> Self {
124        Self::checked_new(self.source.clone(), range)
125    }
126
127    /// New a span **relative** range from exist span.
128    ///
129    /// # Panics
130    ///
131    /// - Panics if `range+start` out of source.
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// use line_column::span::*;
137    ///
138    /// let source = "abcdef";
139    /// let full = Span::new_full(source);
140    /// assert_eq!(full.text(), "abcdef");
141    ///
142    /// let span = full.slice(TextRange::at(1.into(), 3.into()));
143    /// assert_eq!(span.text(), "bcd");
144    /// let span2 = span.slice(TextRange::at(1.into(), 3.into()));
145    /// assert_eq!(span2.text(), "cde");
146    /// ```
147    #[inline]
148    #[track_caller]
149    pub fn slice(&self, range: TextRange) -> Self {
150        let start = self.range.start();
151        self.create(range+start)
152    }
153
154    /// New splitted pair of spans from this span, using **relative** index (`len`).
155    ///
156    /// # Panics
157    ///
158    /// - Panics if `len+start()` out of source.
159    ///
160    /// # Examples
161    ///
162    /// ```
163    /// use line_column::span::*;
164    ///
165    /// let source = "abcdef";
166    /// let full = Span::new_full(source);
167    /// assert_eq!(full.text(), "abcdef");
168    ///
169    /// let (a, span) = full.split(TextSize::of("a"));
170    /// assert_eq!(a.text(), "a");
171    /// assert_eq!(span.text(), "bcdef");
172    ///
173    /// let (bcd, span2) = span.split(TextSize::of("bcd"));
174    /// assert_eq!(bcd.text(), "bcd");
175    /// assert_eq!(span2.text(), "ef");
176    /// ```
177    #[inline]
178    #[track_caller]
179    pub fn split(&self, len: TextSize) -> (Self, Self) {
180        self.split_at(self.range.start()+len)
181    }
182
183    /// New splitted pair of spans from this span, using **source** `index`.
184    ///
185    /// # Panics
186    ///
187    /// - Panics if `index` out of source.
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// use line_column::span::*;
193    ///
194    /// let source = "abcdef";
195    /// let full = Span::new_full(source);
196    /// assert_eq!(full.text(), "abcdef");
197    ///
198    /// let (a, span) = full.split_at(TextSize::of("a"));
199    /// assert_eq!(a.text(), "a");
200    /// assert_eq!(span.text(), "bcdef");
201    ///
202    /// let (bcd, span2) = span.split_at(TextSize::of("abcd"));
203    /// assert_eq!(bcd.text(), "bcd");
204    /// assert_eq!(span2.text(), "ef");
205    /// ```
206    #[inline]
207    #[track_caller]
208    pub fn split_at(&self, index: TextSize) -> (Self, Self) {
209        self.split_at_range(TextRange::empty(index))
210    }
211
212    /// New splitted pair of spans from this span, using **source** `range`.
213    ///
214    /// # Panics
215    ///
216    /// - Panics if `range.end()` out of source.
217    ///
218    /// # Examples
219    ///
220    /// ```
221    /// use line_column::span::*;
222    ///
223    /// let source = "abcdef";
224    /// let full = Span::new_full(source);
225    /// let sub = full.create(TextRange::at(TextSize::of("ab"), TextSize::of("cd")));
226    /// assert_eq!(full.text(), "abcdef");
227    /// assert_eq!(sub.text(), "cd");
228    ///
229    /// let (a, b) = full.split_at_range(sub.range());
230    /// assert_eq!(a.text(), "ab");
231    /// assert_eq!(b.text(), "ef");
232    /// ```
233    #[inline]
234    #[track_caller]
235    pub fn split_at_range(&self, range: TextRange) -> (Self, Self) {
236        let start = self.range.start();
237        let end = self.range.end();
238        (
239            self.create(TextRange::new(start, range.start())),
240            self.create(TextRange::new(range.end(), end)),
241        )
242    }
243
244    #[inline]
245    #[track_caller]
246    fn checked_new(source: Arc<String>, range: TextRange) -> Self {
247        let source_length = len_size(source.len());
248
249        assert!(range.end() <= source_length, "range end > source length ({:?} > {source_length:?})", range.end());
250
251        Self { source, range }
252    }
253
254    /// Returns the is empty of this [`Span`] range.
255    ///
256    /// # Examples
257    ///
258    /// ```
259    /// use line_column::span::*;
260    ///
261    /// let span = Span::new_full("foo");
262    /// let empty = span.create(TextRange::empty(1.into()));
263    /// assert_eq!(span.is_empty(),  false);
264    /// assert_eq!(empty.is_empty(), true);
265    /// assert_eq!(empty.range(),    TextRange::new(1.into(), 1.into()));
266    /// ```
267    #[inline]
268    pub fn is_empty(&self) -> bool {
269        self.range().is_empty()
270    }
271
272    /// Returns the length of this [`Span`] range.
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// use line_column::span::*;
278    ///
279    /// let span = Span::new_full("foo");
280    /// let empty = span.create(TextRange::empty(1.into()));
281    /// assert_eq!(span.len(),  TextSize::new(3));
282    /// assert_eq!(empty.len(), TextSize::new(0));
283    /// ```
284    #[inline]
285    pub fn len(&self) -> TextSize {
286        self.range().len()
287    }
288
289    /// Returns the source before of this [`Span`].
290    ///
291    /// # Examples
292    ///
293    /// ```
294    /// use line_column::span::*;
295    ///
296    /// let span = Span::new("foobarbaz", TextRange::new(3.into(), 6.into()));
297    /// assert_eq!(span.text(),          "bar");
298    /// assert_eq!(span.before().text(), "foo");
299    /// ```
300    pub fn before(&self) -> Self {
301        let range = TextRange::up_to(self.range().start());
302        self.create(range)
303    }
304
305    /// Returns the source after of this [`Span`].
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use line_column::span::*;
311    ///
312    /// let span = Span::new("foobarbaz", TextRange::new(3.into(), 6.into()));
313    /// assert_eq!(span.text(),          "bar");
314    /// assert_eq!(span.after().text(),  "baz");
315    /// ```
316    pub fn after(&self) -> Self {
317        let end = TextSize::of(self.source());
318        let range = TextRange::new(self.range().end(), end);
319        self.create(range)
320    }
321
322    /// Returns truncated sub-span.
323    ///
324    /// # Examples
325    ///
326    /// ```
327    /// use line_column::span::*;
328    ///
329    /// let span = Span::new("foobarbaz", TextRange::new(3.into(), 7.into()));
330    /// assert_eq!(span.text(), "barb");
331    /// assert_eq!(span.take(3.into()).text(), "bar");
332    /// ```
333    pub fn take(&self, len: TextSize) -> Self {
334        let range = self.range;
335        let new_len = range.len().min(len);
336        let new_range = TextRange::at(self.range.start(), new_len);
337        self.create(new_range)
338    }
339
340    /// Returns the start of this [`Span`].
341    ///
342    /// # Examples
343    ///
344    /// ```
345    /// use line_column::span::*;
346    ///
347    /// let span = Span::new("abcdef", TextRange::new(1.into(), 4.into()));
348    /// assert_eq!(span.start().range(), TextRange::new(1.into(), 1.into()));
349    /// ```
350    pub fn start(&self) -> Self {
351        self.create(TextRange::empty(self.range.start()))
352    }
353
354    /// Returns the end of this [`Span`].
355    ///
356    /// # Examples
357    ///
358    /// ```
359    /// use line_column::span::*;
360    ///
361    /// let span = Span::new("abcdef", TextRange::new(1.into(), 4.into()));
362    /// assert_eq!(span.end().range(), TextRange::new(4.into(), 4.into()));
363    /// ```
364    pub fn end(&self) -> Self {
365        self.create(TextRange::empty(self.range.end()))
366    }
367
368    /// Returns the start index of this [`Span`] range.
369    ///
370    /// # Examples
371    ///
372    /// ```
373    /// use line_column::span::*;
374    ///
375    /// let span = Span::new("abcdef", TextRange::new(1.into(), 4.into()));
376    /// assert_eq!(span.index(), TextSize::new(1));
377    /// ```
378    #[inline]
379    pub fn index(&self) -> TextSize {
380        self.range().start()
381    }
382
383    /// Returns the source text of the range reference.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// use line_column::span::*;
389    ///
390    /// let span = Span::new("abcdef", TextRange::new(1.into(), 4.into()));
391    /// assert_eq!(span.text(), "bcd");
392    /// ```
393    #[doc(alias = "as_str")]
394    pub fn text(&self) -> &str {
395        &self.source()[self.range()]
396    }
397
398    /// Returns the source text of the range reference.
399    ///
400    /// # Examples
401    ///
402    /// ```
403    /// use line_column::span::*;
404    ///
405    /// let span = Span::new("abcdef", TextRange::new(1.into(), 4.into()));
406    /// assert_eq!(span.range(),       TextRange::new(1.into(), 4.into()));
407    /// ```
408    pub fn range(&self) -> TextRange {
409        self.range
410    }
411
412    /// Returns the source text.
413    ///
414    /// # Examples
415    ///
416    /// ```
417    /// use line_column::span::*;
418    ///
419    /// let span = Span::new("abcdef", TextRange::new(1.into(), 4.into()));
420    /// assert_eq!(span.source(), "abcdef");
421    /// assert_eq!(span.text(),   "bcd");
422    /// ```
423    pub fn source(&self) -> &str {
424        &self.source
425    }
426}
427
428impl Span {
429    /// Use [`line_column`](crate::line_column) calculate line and column
430    ///
431    /// # Examples
432    ///
433    /// ```
434    /// use line_column::span::*;
435    ///
436    /// let span = Span::new("ab\ncdef", TextRange::empty(TextSize::of("ab\ncd")));
437    /// assert_eq!(span.before().text(), "ab\ncd");
438    /// assert_eq!(span.line_column(), (2, 3));
439    /// ```
440    pub fn line_column(&self) -> (u32, u32) {
441        crate::line_column(self.source(), self.index().into())
442    }
443
444    /// Get line from [`Span::line_column`]
445    pub fn line(&self) -> u32 {
446        self.line_column().0
447    }
448
449    /// Get column from [`Span::line_column`]
450    pub fn column(&self) -> u32 {
451        self.line_column().1
452    }
453
454    /// Returns the current line of this [`Span`].
455    ///
456    /// Maybe include end of line char, like `'\n'`.
457    ///
458    /// # Examples
459    ///
460    /// ```
461    /// use line_column::span::*;
462    ///
463    /// let span = Span::new_full("foo\nbar\nbaz");
464    /// let next = span.create(TextRange::at(TextSize::of("foo\n"), 5.into()));
465    /// let tail = span.create(TextRange::at(TextSize::of("foo\nbar\n"), 3.into()));
466    /// let endl = span.create(TextRange::at(TextSize::of("foo"), 3.into()));
467    ///
468    /// assert_eq!(next.text(), "bar\nb");
469    /// assert_eq!(tail.text(), "baz");
470    /// assert_eq!(endl.text(), "\nba");
471    ///
472    /// assert_eq!(span.current_line().text(), "foo\n");
473    /// assert_eq!(next.current_line().text(), "bar\n");
474    /// assert_eq!(tail.current_line().text(), "baz");
475    /// assert_eq!(endl.current_line().text(), "foo\n");
476    /// ```
477    pub fn current_line(&self) -> Self {
478        let before = &self.source[..self.range.start().into()];
479        let line_start = before.rfind('\n').map_or(0, |it| it+1);
480        let rest = &self.source[line_start..];
481
482        let line_len = match rest.split_once('\n') {
483            Some((line, _)) => TextSize::of(line) + TextSize::of('\n'),
484            None => TextSize::of(rest),
485        };
486        let range = TextRange::at(len_size(line_start), line_len);
487        self.create(range)
488    }
489
490    /// Returns the previous line of this [`Span`].
491    ///
492    /// # Examples
493    ///
494    /// ```
495    /// use line_column::span::*;
496    ///
497    /// let span = Span::new_full("foo\nbar\nbaz");
498    /// let next = span.create(TextRange::at(TextSize::of("foo\n"), 5.into()));
499    /// let tail = span.create(TextRange::at(TextSize::of("foo\nbar\n"), 3.into()));
500    /// let endl = span.create(TextRange::at(TextSize::of("foo"), 3.into()));
501    ///
502    /// assert_eq!(next.text(), "bar\nb");
503    /// assert_eq!(tail.text(), "baz");
504    /// assert_eq!(endl.text(), "\nba");
505    ///
506    /// assert_eq!(span.prev_line().text(), "");
507    /// assert_eq!(next.prev_line().text(), "foo\n");
508    /// assert_eq!(tail.prev_line().text(), "bar\n");
509    /// assert_eq!(endl.prev_line().text(), "");
510    /// ```
511    pub fn prev_line(&self) -> Self {
512        let index = self.current_line().index();
513        if let Some(prev_line_offset) = index.checked_sub(TextSize::of('\n')) {
514            self.create(TextRange::empty(prev_line_offset)).current_line()
515        } else {
516            self.create(TextRange::empty(TextSize::new(0)))
517        }
518    }
519
520    /// Returns the next line of this [`Span`].
521    ///
522    /// # Examples
523    ///
524    /// ```
525    /// use line_column::span::*;
526    ///
527    /// let span = Span::new_full("foo\nbar\nbaz");
528    /// let next = span.create(TextRange::at(TextSize::of("foo\n"), 5.into()));
529    /// let tail = span.create(TextRange::at(TextSize::of("foo\nbar\n"), 3.into()));
530    /// let endl = span.create(TextRange::at(TextSize::of("foo"), 3.into()));
531    ///
532    /// assert_eq!(next.text(), "bar\nb");
533    /// assert_eq!(tail.text(), "baz");
534    /// assert_eq!(endl.text(), "\nba");
535    ///
536    /// assert_eq!(span.next_line().text(), "bar\n");
537    /// assert_eq!(next.next_line().text(), "baz");
538    /// assert_eq!(tail.next_line().text(), "");
539    /// assert_eq!(endl.next_line().text(), "bar\n");
540    /// ```
541    pub fn next_line(&self) -> Self {
542        let cur_line_end = self.current_line().range().end();
543        if self.source().len() == cur_line_end.into() {
544            self.create(TextRange::empty(cur_line_end))
545        } else {
546            let range = TextRange::empty(cur_line_end);
547            self.create(range).current_line()
548        }
549    }
550}
551
552impl Span {
553    /// Returns the trim end of this [`Span`] range.
554    ///
555    /// # Examples
556    ///
557    /// ```
558    /// use line_column::span::*;
559    ///
560    /// let span = Span::new("foo  bar  baz", TextRange::new(4.into(), 9.into()));
561    /// assert_eq!(span.text(), " bar ");
562    /// assert_eq!(span.trim_end().text(), " bar");
563    /// ```
564    pub fn trim_end(&self) -> Self {
565        let text = self.text();
566        let trimmed = text.trim_end();
567        let len = TextSize::of(trimmed);
568        self.create(TextRange::at(self.range.start(), len))
569    }
570
571    /// Returns the trim start of this [`Span`] range.
572    ///
573    /// # Examples
574    ///
575    /// ```
576    /// use line_column::span::*;
577    ///
578    /// let span = Span::new("foo  bar  baz", TextRange::new(4.into(), 9.into()));
579    /// assert_eq!(span.text(), " bar ");
580    /// assert_eq!(span.trim_start().text(), "bar ");
581    /// ```
582    pub fn trim_start(&self) -> Self {
583        let text = self.text();
584        let trimmed = text.trim_start();
585        let len = TextSize::of(trimmed);
586
587        let offset = TextSize::of(text) - len;
588        let start = self.range.start() + offset;
589        self.create(TextRange::at(start, len))
590    }
591}
592
593#[inline]
594#[track_caller]
595fn len_size(len: usize) -> TextSize {
596    match TextSize::try_from(len) {
597        Ok(source_length) => source_length,
598        _ => panic!("source length {len} overflow TextSize"),
599    }
600}
601
602#[cfg(test)]
603mod tests {
604    use core::iter::successors;
605    use std::{format, vec::Vec};
606
607    use super::*;
608
609    #[track_caller]
610    fn check_texts(spans: impl IntoIterator<Item = Span>, expect: &[&str]) {
611        let spans = Vec::from_iter(spans);
612        let texts = spans.iter().map(|it| it.text()).collect::<Vec<_>>();
613        assert_eq!(texts, expect);
614    }
615
616    #[cfg(feature = "sync")]
617    fn _test_sync(span: Span) {
618        fn check_sync(_: impl Sync) {}
619        check_sync(span);
620    }
621
622    #[test]
623    #[should_panic = "range end > source length"]
624    fn new_panic_out_of_source() {
625        let _span = Span::new("x", TextRange::up_to(TextSize::of("xy")));
626    }
627
628    #[test]
629    fn next_lines_without_end_eol() {
630        let source = "foo\nbar\n\nbaz";
631        let span = Span::new_full(source);
632        let lines =
633            successors(span.current_line().into(), |it| Some(it.next_line()))
634                .take_while(|it| !it.is_empty())
635                .collect::<Vec<_>>();
636        check_texts(lines, &[
637            "foo\n",
638            "bar\n",
639            "\n",
640            "baz",
641        ]);
642    }
643
644    #[test]
645    fn next_lines_multi_bytes_char() {
646        let source = "测试\n实现\n\n多字节";
647        let span = Span::new_full(source);
648        let lines =
649            successors(span.current_line().into(), |it| Some(it.next_line()))
650                .take_while(|it| !it.is_empty())
651                .collect::<Vec<_>>();
652        check_texts(lines, &[
653            "测试\n",
654            "实现\n",
655            "\n",
656            "多字节",
657        ]);
658    }
659
660    #[test]
661    fn next_lines_with_end_eol() {
662        let source = "foo\nbar\n\nbaz\n";
663        let span = Span::new_full(source);
664        let lines =
665            successors(span.current_line().into(), |it| Some(it.next_line()))
666                .take_while(|it| !it.is_empty())
667                .collect::<Vec<_>>();
668        check_texts(lines, &[
669            "foo\n",
670            "bar\n",
671            "\n",
672            "baz\n",
673        ]);
674    }
675
676    #[test]
677    fn next_lines_first_empty_line() {
678        let source = "\nfoo\nbar\n\nbaz";
679        let span = Span::new_full(source);
680        let lines =
681            successors(span.current_line().into(), |it| Some(it.next_line()))
682                .take_while(|it| !it.is_empty())
683                .collect::<Vec<_>>();
684        check_texts(lines, &[
685            "\n",
686            "foo\n",
687            "bar\n",
688            "\n",
689            "baz",
690        ]);
691    }
692
693    #[test]
694    fn prev_lines_with_end_eol() {
695        let source = "foo\nbar\n\nbaz\n";
696        let span = Span::new(source, TextRange::empty(TextSize::of(source)));
697        let lines =
698            successors(span.current_line().into(), |it| Some(it.prev_line()))
699                .skip(1)
700                .take_while(|it| !it.is_empty())
701                .collect::<Vec<_>>();
702        check_texts(lines, &[
703            "baz\n",
704            "\n",
705            "bar\n",
706            "foo\n",
707        ]);
708    }
709
710    #[test]
711    fn prev_lines_without_end_eol() {
712        let source = "foo\nbar\n\nbaz";
713        let span = Span::new(source, TextRange::empty(TextSize::of(source)));
714        let lines =
715            successors(span.current_line().into(), |it| Some(it.prev_line()))
716                .take_while(|it| !it.is_empty())
717                .collect::<Vec<_>>();
718        check_texts(lines, &[
719            "baz",
720            "\n",
721            "bar\n",
722            "foo\n",
723        ]);
724    }
725
726    #[test]
727    fn prev_lines_multi_bytes_char() {
728        let source = "测试\n实现\n\n多字节";
729        let span = Span::new(source, TextRange::empty(TextSize::of(source)));
730        let lines =
731            successors(span.current_line().into(), |it| Some(it.prev_line()))
732                .take_while(|it| !it.is_empty())
733                .collect::<Vec<_>>();
734        check_texts(lines, &[
735            "多字节",
736            "\n",
737            "实现\n",
738            "测试\n",
739        ]);
740    }
741
742    #[test]
743    fn test_trim_start() {
744        let datas = [
745            "",
746            "f",
747            "foo",
748            " ",
749            " f",
750            " foo",
751            "  ",
752            "  f",
753            "  foo",
754            "  f",
755            "  foo",
756        ];
757        for prefix in ["", "x"] {
758            for suffix in ["", "x", " ", "  "] {
759                for data in datas {
760                    let source = format!("{prefix}{data}{suffix}");
761                    let range = TextRange::new(
762                        TextSize::of(prefix),
763                        TextSize::of(&source),
764                    );
765                    let span = Span::new(&source, range);
766                    assert_eq!(span.trim_start().text(), source[range].trim_start());
767                }
768            }
769        }
770    }
771
772    #[test]
773    fn test_trim_end() {
774        let datas = [
775            "",
776            "f",
777            "foo",
778            " ",
779            " f",
780            "foo ",
781            "  ",
782            "f  ",
783            "foo  ",
784            "f  ",
785            "foo  ",
786        ];
787        for prefix in ["", "x", " ", "  "] {
788            for suffix in ["", "x"] {
789                for data in datas {
790                    let source = format!("{prefix}{data}{suffix}");
791                    let range = TextRange::new(
792                        TextSize::new(0),
793                        TextSize::of(&source) - TextSize::of(suffix),
794                    );
795                    let span = Span::new(&source, range);
796                    assert_eq!(span.trim_end().text(), source[range].trim_end());
797                }
798            }
799        }
800    }
801}