rat_text/
grapheme.rs

1use crate::text_store::SkipLine;
2use crate::{Cursor, TextError};
3use ropey::RopeSlice;
4use ropey::iter::Chunks;
5use std::borrow::Cow;
6use std::cmp;
7use std::fmt::Debug;
8use std::ops::Range;
9use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
10
11/// One grapheme.
12#[derive(Debug, PartialEq)]
13pub struct Grapheme<'a> {
14    /// grapheme
15    grapheme: Cow<'a, str>,
16    /// byte-range of the grapheme in the given slice.
17    text_bytes: Range<usize>,
18}
19
20impl<R: AsRef<str>> PartialEq<R> for Grapheme<'_> {
21    fn eq(&self, other: &R) -> bool {
22        self.grapheme.as_ref() == other.as_ref()
23    }
24}
25
26impl<'a> Grapheme<'a> {
27    pub fn new(grapheme: Cow<'a, str>, text_bytes: Range<usize>) -> Self {
28        Self {
29            grapheme,
30            text_bytes,
31        }
32    }
33
34    /// First (only) char of the grapheme is a whitespace.
35    #[inline]
36    pub fn is_whitespace(&self) -> bool {
37        self.grapheme
38            .chars()
39            .next()
40            .map(|v| v.is_whitespace())
41            .unwrap_or(false)
42    }
43
44    /// First (only) char of the grapheme is a whitespace.
45    #[inline]
46    pub fn is_alphanumeric(&self) -> bool {
47        self.grapheme
48            .chars()
49            .next()
50            .map(|v| v.is_alphanumeric())
51            .unwrap_or(false)
52    }
53
54    /// Is a linebreak.
55    #[inline]
56    #[allow(clippy::nonminimal_bool)]
57    pub fn is_line_break(&self) -> bool {
58        if cfg!(feature = "cr_lines") {
59            self.grapheme == "\r" || self.grapheme == "\n" || self.grapheme == "\r\n"
60        } else if cfg!(feature = "unicode_lines") {
61            self.grapheme == "\r"
62                || self.grapheme == "\n"
63                || self.grapheme == "\r\n"
64                || self.grapheme == "\u{000D}"
65                || self.grapheme == "\u{000C}"
66                || self.grapheme == "\u{000B}"
67                || self.grapheme == "\u{0085}"
68                || self.grapheme == "\u{2028}"
69                || self.grapheme == "\u{2029}"
70        } else {
71            self.grapheme == "\n" || self.grapheme == "\r\n"
72        }
73    }
74
75    /// Get the grapheme.
76    #[inline]
77    pub fn grapheme(&'a self) -> &'a str {
78        self.grapheme.as_ref()
79    }
80
81    /// Destructure to the grapheme.
82    #[inline]
83    pub fn into_parts(self) -> (Cow<'a, str>, Range<usize>) {
84        (self.grapheme, self.text_bytes)
85    }
86
87    /// Get the byte-range as absolute range into the complete text.
88    #[inline]
89    pub fn text_bytes(&self) -> Range<usize> {
90        self.text_bytes.clone()
91    }
92}
93
94/// A cursor over graphemes of a string.
95#[derive(Debug, Clone)]
96pub struct StrGraphemes<'a> {
97    text_offset: usize,
98    text: &'a str,
99    cursor: GraphemeCursor,
100}
101
102impl<'a> StrGraphemes<'a> {
103    /// Iterate the graphemes of a str-slice.
104    ///
105    /// * slice_offset - offset of the slice in the complete text.
106    /// * slice - slice
107    ///
108    pub(crate) fn new(slice_offset: usize, slice: &'a str) -> Self {
109        Self {
110            text_offset: slice_offset,
111            text: slice,
112            cursor: GraphemeCursor::new(0, slice.len(), true),
113        }
114    }
115
116    /// Iterate the graphemes of a str-slice.
117    ///
118    /// * slice_offset - offset of the slice in the complete text.
119    /// * slice - slice
120    /// * offset - relative offset into the slice
121    ///
122    pub(crate) fn new_offset(slice_offset: usize, slice: &'a str, offset: usize) -> Self {
123        Self {
124            text_offset: slice_offset,
125            text: slice,
126            cursor: GraphemeCursor::new(offset, slice.len(), true),
127        }
128    }
129}
130
131impl Cursor for StrGraphemes<'_> {
132    fn prev(&mut self) -> Option<Self::Item> {
133        let start = self.cursor.cur_cursor();
134        let prev = self.cursor.prev_boundary(self.text, 0).unwrap()?;
135        Some(Grapheme {
136            grapheme: Cow::Borrowed(&self.text[prev..start]),
137            text_bytes: self.text_offset + prev..self.text_offset + start,
138        })
139    }
140
141    fn rev_cursor(self) -> impl Cursor<Item = Self::Item> {
142        RevStrGraphemes { it: self }
143    }
144
145    fn text_offset(&self) -> usize {
146        self.text_offset + self.cursor.cur_cursor()
147    }
148}
149
150impl SkipLine for StrGraphemes<'_> {
151    fn skip_line(&mut self) -> Result<(), TextError> {
152        self.cursor.set_cursor(self.text.len());
153        Ok(())
154    }
155
156    fn skip_to(&mut self, byte_pos: usize) -> Result<(), TextError> {
157        assert!(byte_pos >= self.text_offset);
158        let offset = byte_pos - self.text_offset;
159        self.cursor.set_cursor(offset);
160        Ok(())
161    }
162}
163
164impl<'a> Iterator for StrGraphemes<'a> {
165    type Item = Grapheme<'a>;
166
167    #[inline]
168    fn next(&mut self) -> Option<Grapheme<'a>> {
169        let start = self.cursor.cur_cursor();
170        let next = self.cursor.next_boundary(self.text, 0).unwrap()?;
171        Some(Grapheme {
172            grapheme: Cow::Borrowed(&self.text[start..next]),
173            text_bytes: self.text_offset + start..self.text_offset + next,
174        })
175    }
176
177    #[inline]
178    fn size_hint(&self) -> (usize, Option<usize>) {
179        let slen = self.text.len() - self.cursor.cur_cursor();
180        (cmp::min(slen, 1), Some(slen))
181    }
182}
183
184#[derive(Debug)]
185pub(crate) struct RevStrGraphemes<'a> {
186    it: StrGraphemes<'a>,
187}
188
189impl<'a> Iterator for RevStrGraphemes<'a> {
190    type Item = Grapheme<'a>;
191
192    #[inline]
193    fn next(&mut self) -> Option<Self::Item> {
194        self.it.prev()
195    }
196}
197
198impl Cursor for RevStrGraphemes<'_> {
199    #[inline]
200    fn prev(&mut self) -> Option<Self::Item> {
201        self.it.next()
202    }
203
204    #[inline]
205    fn rev_cursor(self) -> impl Cursor<Item = Self::Item> {
206        self.it
207    }
208
209    fn text_offset(&self) -> usize {
210        self.it.text_offset()
211    }
212}
213
214impl SkipLine for RevStrGraphemes<'_> {
215    fn skip_line(&mut self) -> Result<(), TextError> {
216        unimplemented!("no skip_line()");
217    }
218
219    fn skip_to(&mut self, _byte_pos: usize) -> Result<(), TextError> {
220        unimplemented!("no skip_to()");
221    }
222}
223
224/// An implementation of a graphemes iterator, for iterating over
225/// the graphemes of a RopeSlice.
226#[derive(Debug, Clone)]
227pub struct RopeGraphemes<'a> {
228    text_offset: usize,
229    text: RopeSlice<'a>,
230    chunks: Chunks<'a>,
231    was_next: Option<bool>,
232    cur_chunk: &'a str,
233    cur_chunk_start: usize,
234    cursor: GraphemeCursor,
235}
236
237impl<'a> RopeGraphemes<'a> {
238    /// New grapheme iterator.
239    ///
240    /// * slice_offset - offset of the slice in the complete text.
241    /// * slice - slice of the complete text
242    pub(crate) fn new(slice_offset: usize, slice: RopeSlice<'a>) -> RopeGraphemes<'a> {
243        let mut chunks = slice.chunks();
244
245        // was_next is only useful, if there was a true next().
246        // otherwise it confuses the algorithm.
247        let (first_chunk, was_next) = match chunks.next() {
248            Some(v) => (v, Some(true)),
249            None => ("", None),
250        };
251
252        RopeGraphemes {
253            text_offset: slice_offset,
254            text: slice,
255            chunks,
256            was_next,
257            cur_chunk: first_chunk,
258            cur_chunk_start: 0,
259            cursor: GraphemeCursor::new(0, slice.len_bytes(), true),
260        }
261    }
262
263    /// New grapheme iterator.
264    ///
265    /// * slice_offset - offset of the slice in the complete text.
266    /// * slice - slice of the complete text
267    /// * offset - relative offset into the slice
268    ///
269    /// Offset must be a valid char boundary.
270    pub(crate) fn new_offset(
271        slice_offset: usize,
272        slice: RopeSlice<'a>,
273        offset: usize,
274    ) -> Result<RopeGraphemes<'a>, TextError> {
275        let Some((mut chunks, chunk_start, _, _)) = slice.get_chunks_at_byte(offset) else {
276            return Err(TextError::ByteIndexOutOfBounds(offset, slice.len_bytes()));
277        };
278
279        // was_next is only useful, if there was a true next().
280        // otherwise it confuses the algorithm.
281        let (first_chunk, was_next) = match chunks.next() {
282            Some(v) => (v, Some(true)),
283            None => ("", None),
284        };
285
286        Ok(RopeGraphemes {
287            text_offset: slice_offset,
288            text: slice,
289            chunks,
290            was_next,
291            cur_chunk: first_chunk,
292            cur_chunk_start: chunk_start,
293            cursor: GraphemeCursor::new(offset, slice.len_bytes(), true),
294        })
295    }
296}
297
298impl<'a> Cursor for RopeGraphemes<'a> {
299    #[inline]
300    fn prev(&mut self) -> Option<Grapheme<'a>> {
301        let a = self.cursor.cur_cursor();
302        let b;
303        loop {
304            match self
305                .cursor
306                .prev_boundary(self.cur_chunk, self.cur_chunk_start)
307            {
308                Ok(None) => {
309                    return None;
310                }
311                Ok(Some(n)) => {
312                    b = n;
313                    break;
314                }
315                Err(GraphemeIncomplete::PrevChunk) => {
316                    if self.was_next == Some(true) {
317                        // skip current
318                        self.chunks.prev();
319                    }
320                    (self.cur_chunk, self.was_next) = match self.chunks.prev() {
321                        Some(v) => (v, Some(false)),
322                        None => ("", None),
323                    };
324                    self.cur_chunk_start -= self.cur_chunk.len();
325                }
326                Err(GraphemeIncomplete::PreContext(idx)) => {
327                    let (chunk, byte_idx, _, _) = self.text.chunk_at_byte(idx.saturating_sub(1));
328                    self.cursor.provide_context(chunk, byte_idx);
329                }
330                _ => unreachable!(),
331            }
332        }
333
334        if a >= self.cur_chunk_start + self.cur_chunk.len() {
335            let a_char = self.text.byte_to_char(a);
336            let b_char = self.text.byte_to_char(b);
337
338            Some(Grapheme {
339                grapheme: Cow::Owned(self.text.slice(b_char..a_char).to_string()),
340                text_bytes: self.text_offset + b..self.text_offset + a,
341            })
342        } else {
343            let a2 = a - self.cur_chunk_start;
344            let b2 = b - self.cur_chunk_start;
345            Some(Grapheme {
346                grapheme: Cow::Borrowed(&self.cur_chunk[b2..a2]),
347                text_bytes: self.text_offset + b..self.text_offset + a,
348            })
349        }
350    }
351
352    fn rev_cursor(self) -> impl Cursor<Item = Self::Item> {
353        RevRopeGraphemes { it: self }
354    }
355
356    fn text_offset(&self) -> usize {
357        self.text_offset + self.cursor.cur_cursor()
358    }
359}
360
361impl<'a> SkipLine for RopeGraphemes<'a> {
362    fn skip_line(&mut self) -> Result<(), TextError> {
363        let cursor = self.cursor.cur_cursor();
364        let line = self.text.try_byte_to_line(cursor)?;
365        let next_offset = self.text.try_line_to_byte(line + 1)?;
366
367        let Some((mut chunks, chunk_start, _, _)) = self.text.get_chunks_at_byte(next_offset)
368        else {
369            return Err(TextError::ByteIndexOutOfBounds(
370                next_offset,
371                self.text.len_bytes(),
372            ));
373        };
374
375        // was_next is only useful, if there was a true next().
376        // otherwise it confuses the algorithm.
377        let (first_chunk, _was_next) = match chunks.next() {
378            Some(v) => (v, Some(true)),
379            None => ("", None),
380        };
381
382        self.chunks = chunks;
383        self.cur_chunk = first_chunk;
384        self.cur_chunk_start = chunk_start;
385        self.cursor = GraphemeCursor::new(next_offset, self.text.len_bytes(), true);
386
387        Ok(())
388    }
389
390    fn skip_to(&mut self, byte_pos: usize) -> Result<(), TextError> {
391        assert!(byte_pos >= self.text_offset);
392        // byte_pos is absolute to all text, but everything here is
393        // relative to the slice.
394        let byte_pos = byte_pos - self.text_offset;
395
396        let Some((mut chunks, chunk_start, _, _)) = self.text.get_chunks_at_byte(byte_pos) else {
397            return Err(TextError::ByteIndexOutOfBounds(
398                byte_pos,
399                self.text.len_bytes(),
400            ));
401        };
402
403        // was_next is only useful, if there was a true next().
404        // otherwise it confuses the algorithm.
405        let (first_chunk, _was_next) = match chunks.next() {
406            Some(v) => (v, Some(true)),
407            None => ("", None),
408        };
409
410        self.chunks = chunks;
411        self.cur_chunk = first_chunk;
412        self.cur_chunk_start = chunk_start;
413        self.cursor = GraphemeCursor::new(byte_pos, self.text.len_bytes(), true);
414
415        Ok(())
416    }
417}
418
419impl<'a> Iterator for RopeGraphemes<'a> {
420    type Item = Grapheme<'a>;
421
422    #[inline]
423    fn next(&mut self) -> Option<Grapheme<'a>> {
424        let a = self.cursor.cur_cursor();
425        let b;
426        loop {
427            match self
428                .cursor
429                .next_boundary(self.cur_chunk, self.cur_chunk_start)
430            {
431                Ok(None) => {
432                    return None;
433                }
434                Ok(Some(n)) => {
435                    b = n;
436                    break;
437                }
438                Err(GraphemeIncomplete::NextChunk) => {
439                    self.cur_chunk_start += self.cur_chunk.len();
440                    if self.was_next == Some(false) {
441                        // skip current
442                        self.chunks.next();
443                    }
444                    (self.cur_chunk, self.was_next) = match self.chunks.next() {
445                        Some(v) => (v, Some(true)),
446                        None => ("", None),
447                    };
448                }
449                Err(GraphemeIncomplete::PreContext(idx)) => {
450                    let (chunk, byte_idx, _, _) = self.text.chunk_at_byte(idx.saturating_sub(1));
451                    self.cursor.provide_context(chunk, byte_idx);
452                }
453                _ => unreachable!(),
454            }
455        }
456
457        if a < self.cur_chunk_start {
458            let a_char = self.text.byte_to_char(a);
459            let b_char = self.text.byte_to_char(b);
460
461            Some(Grapheme {
462                grapheme: Cow::Owned(self.text.slice(a_char..b_char).to_string()),
463                text_bytes: self.text_offset + a..self.text_offset + b,
464            })
465        } else {
466            let a2 = a - self.cur_chunk_start;
467            let b2 = b - self.cur_chunk_start;
468            Some(Grapheme {
469                grapheme: Cow::Borrowed(&self.cur_chunk[a2..b2]),
470                text_bytes: self.text_offset + a..self.text_offset + b,
471            })
472        }
473    }
474}
475
476#[derive(Debug)]
477pub(crate) struct RevRopeGraphemes<'a> {
478    it: RopeGraphemes<'a>,
479}
480
481impl<'a> Iterator for RevRopeGraphemes<'a> {
482    type Item = Grapheme<'a>;
483
484    #[inline]
485    fn next(&mut self) -> Option<Self::Item> {
486        self.it.prev()
487    }
488}
489
490impl Cursor for RevRopeGraphemes<'_> {
491    #[inline]
492    fn prev(&mut self) -> Option<Self::Item> {
493        self.it.next()
494    }
495
496    #[inline]
497    fn rev_cursor(self) -> impl Cursor<Item = Self::Item> {
498        self.it
499    }
500
501    fn text_offset(&self) -> usize {
502        self.it.text_offset()
503    }
504}
505
506impl SkipLine for RevRopeGraphemes<'_> {
507    fn skip_line(&mut self) -> Result<(), TextError> {
508        unimplemented!("no skip_line()")
509    }
510
511    fn skip_to(&mut self, _byte_pos: usize) -> Result<(), TextError> {
512        unimplemented!("no skip_to()")
513    }
514}
515
516#[cfg(test)]
517mod test_str {
518    use crate::Cursor;
519    use crate::grapheme::StrGraphemes;
520
521    #[test]
522    fn test_str_graphemes0() {
523        let s = String::from("\r\n");
524        let mut s0 = StrGraphemes::new(0, &s);
525        assert_eq!(s0.next().unwrap(), "\r\n");
526    }
527
528    #[test]
529    fn test_str_graphemes1() {
530        // basic graphemes
531        let s = String::from("qwertz");
532
533        let mut s0 = StrGraphemes::new(0, &s);
534        assert_eq!(s0.next().unwrap(), "q");
535        assert_eq!(s0.next().unwrap(), "w");
536        assert_eq!(s0.next().unwrap(), "e");
537        assert_eq!(s0.next().unwrap(), "r");
538        assert_eq!(s0.next().unwrap(), "t");
539        assert_eq!(s0.next().unwrap(), "z");
540        assert!(s0.next().is_none());
541        assert_eq!(s0.prev().unwrap(), "z");
542        assert_eq!(s0.prev().unwrap(), "t");
543        assert_eq!(s0.prev().unwrap(), "r");
544        assert_eq!(s0.prev().unwrap(), "e");
545        assert_eq!(s0.prev().unwrap(), "w");
546        assert_eq!(s0.prev().unwrap(), "q");
547
548        let mut s0 = StrGraphemes::new(1, &s[1..s.len() - 1]);
549        assert_eq!(s0.next().unwrap(), "w");
550        assert_eq!(s0.next().unwrap(), "e");
551        assert_eq!(s0.next().unwrap(), "r");
552        assert_eq!(s0.next().unwrap(), "t");
553        assert!(s0.next().is_none());
554        assert_eq!(s0.prev().unwrap(), "t");
555        assert_eq!(s0.prev().unwrap(), "r");
556        assert_eq!(s0.prev().unwrap(), "e");
557        assert_eq!(s0.prev().unwrap(), "w");
558
559        let mut s0 = StrGraphemes::new(3, &s[3..3]);
560        assert!(s0.next().is_none());
561        assert!(s0.prev().is_none());
562    }
563
564    #[test]
565    fn test_str_graphemes2() {
566        // complicated graphemes
567        let s = String::from("w🤷‍♂️xw🤷‍♀️xw🤦‍♂️xw❤️xw🤦‍♀️xw💕🙍🏿‍♀️x");
568
569        let mut s0 = StrGraphemes::new(0, &s);
570        assert_eq!(s0.next().unwrap(), "w");
571        assert_eq!(s0.next().unwrap(), "🤷‍♂️");
572        assert_eq!(s0.next().unwrap(), "x");
573        assert_eq!(s0.next().unwrap(), "w");
574        assert_eq!(s0.next().unwrap(), "🤷‍♀️");
575        assert_eq!(s0.next().unwrap(), "x");
576        assert_eq!(s0.next().unwrap(), "w");
577        assert_eq!(s0.next().unwrap(), "🤦‍♂️");
578        assert_eq!(s0.next().unwrap(), "x");
579        assert_eq!(s0.next().unwrap(), "w");
580        assert_eq!(s0.next().unwrap(), "❤️");
581        assert_eq!(s0.next().unwrap(), "x");
582        assert_eq!(s0.next().unwrap(), "w");
583        assert_eq!(s0.next().unwrap(), "🤦‍♀️");
584        assert_eq!(s0.next().unwrap(), "x");
585        assert_eq!(s0.next().unwrap(), "w");
586        assert_eq!(s0.next().unwrap(), "💕");
587        assert_eq!(s0.next().unwrap(), "🙍🏿‍♀️");
588        assert_eq!(s0.next().unwrap(), "x");
589        assert!(s0.next().is_none());
590        assert_eq!(s0.prev().unwrap(), "x");
591        assert_eq!(s0.prev().unwrap(), "🙍🏿‍♀️");
592        assert_eq!(s0.prev().unwrap(), "💕");
593        assert_eq!(s0.prev().unwrap(), "w");
594        assert_eq!(s0.prev().unwrap(), "x");
595        assert_eq!(s0.prev().unwrap(), "🤦‍♀️");
596        assert_eq!(s0.prev().unwrap(), "w");
597        assert_eq!(s0.prev().unwrap(), "x");
598        assert_eq!(s0.prev().unwrap(), "❤️");
599        assert_eq!(s0.prev().unwrap(), "w");
600        assert_eq!(s0.prev().unwrap(), "x");
601        assert_eq!(s0.prev().unwrap(), "🤦‍♂️");
602        assert_eq!(s0.prev().unwrap(), "w");
603        assert_eq!(s0.prev().unwrap(), "x");
604        assert_eq!(s0.prev().unwrap(), "🤷‍♀️");
605        assert_eq!(s0.prev().unwrap(), "w");
606        assert_eq!(s0.prev().unwrap(), "x");
607        assert_eq!(s0.prev().unwrap(), "🤷‍♂️");
608        assert_eq!(s0.prev().unwrap(), "w");
609    }
610
611    #[test]
612    fn test_str_graphemes3() {
613        // complicated slices
614        let s = String::from("qwertz");
615        let mut s0 = StrGraphemes::new_offset(0, &s, 3);
616        assert_eq!(s0.next().unwrap(), "r");
617        assert_eq!(s0.prev().unwrap(), "r");
618        assert_eq!(s0.prev().unwrap(), "e");
619
620        let mut s0 = StrGraphemes::new_offset(0, &s, 3);
621        assert_eq!(s0.next().unwrap().text_bytes(), 3..4);
622        assert_eq!(s0.prev().unwrap().text_bytes(), 3..4);
623        assert_eq!(s0.prev().unwrap().text_bytes(), 2..3);
624
625        let s = String::from("w🤷‍♂️🤷‍♀️🤦‍♂️❤️🤦‍♀️💕🙍🏿‍♀️x");
626        let mut s0 = StrGraphemes::new_offset(0, &s, 21);
627        assert_eq!(s0.next().unwrap(), "♀\u{fe0f}");
628        assert_eq!(s0.next().unwrap(), "🤦\u{200d}♂\u{fe0f}");
629        assert_eq!(s0.prev().unwrap(), "🤦\u{200d}♂\u{fe0f}");
630        assert_eq!(s0.prev().unwrap(), "🤷\u{200d}♀\u{fe0f}");
631
632        let s = String::from("w🤷‍♂️🤷‍♀️🤦‍♂️❤️🤦‍♀️💕🙍🏿‍♀️x");
633        let mut s0 = StrGraphemes::new_offset(0, &s, 21);
634        assert_eq!(s0.next().unwrap().text_bytes(), 21..27);
635        assert_eq!(s0.next().unwrap().text_bytes(), 27..40);
636        assert_eq!(s0.prev().unwrap().text_bytes(), 27..40);
637        assert_eq!(s0.prev().unwrap().text_bytes(), 14..27);
638    }
639
640    #[test]
641    fn test_str_graphemes4() {
642        // offsets and partial slices
643        let s = String::from("qwertz");
644        let mut s0 = StrGraphemes::new_offset(1, &s[1..5], 2);
645        s0.next();
646        assert_eq!(s0.text_offset(), 4);
647        s0.next();
648        assert_eq!(s0.text_offset(), 5);
649        s0.next();
650        assert_eq!(s0.text_offset(), 5);
651        s0.next();
652        assert_eq!(s0.text_offset(), 5);
653        s0.prev();
654        assert_eq!(s0.text_offset(), 4);
655        s0.prev();
656        assert_eq!(s0.text_offset(), 3);
657        s0.prev();
658        assert_eq!(s0.text_offset(), 2);
659        s0.prev();
660        assert_eq!(s0.text_offset(), 1);
661        s0.prev();
662        assert_eq!(s0.text_offset(), 1);
663    }
664
665    #[test]
666    fn test_str_graphemes5() {
667        // offsets and partial slices
668        let s = String::from("qwertz");
669        let mut s0 = StrGraphemes::new_offset(1, &s[1..5], 2).rev_cursor();
670        assert_eq!(s0.next().unwrap(), "e");
671        assert_eq!(s0.text_offset(), 2);
672
673        assert_eq!(s0.next().unwrap(), "w");
674        assert_eq!(s0.text_offset(), 1);
675
676        assert_eq!(s0.prev().unwrap(), "w");
677        assert_eq!(s0.text_offset(), 2);
678
679        assert_eq!(s0.prev().unwrap(), "e");
680        assert_eq!(s0.text_offset(), 3);
681
682        assert_eq!(s0.prev().unwrap(), "r");
683        assert_eq!(s0.text_offset(), 4);
684
685        assert_eq!(s0.prev().unwrap(), "t");
686        assert_eq!(s0.text_offset(), 5);
687    }
688}
689
690#[cfg(test)]
691mod test_rope {
692    use crate::Cursor;
693    use crate::grapheme::{RopeGraphemes, StrGraphemes};
694    use ropey::Rope;
695
696    #[test]
697    fn test_rope_graphemes1() {
698        // basic graphemes
699        let s = Rope::from("qwertz");
700
701        let mut s0 = RopeGraphemes::new(0, s.byte_slice(..));
702        assert_eq!(s0.next().unwrap(), "q");
703        assert_eq!(s0.next().unwrap(), "w");
704        assert_eq!(s0.next().unwrap(), "e");
705        assert_eq!(s0.next().unwrap(), "r");
706        assert_eq!(s0.next().unwrap(), "t");
707        assert_eq!(s0.next().unwrap(), "z");
708        assert!(s0.next().is_none());
709        assert_eq!(s0.prev().unwrap(), "z");
710        assert_eq!(s0.prev().unwrap(), "t");
711        assert_eq!(s0.prev().unwrap(), "r");
712        assert_eq!(s0.prev().unwrap(), "e");
713        assert_eq!(s0.prev().unwrap(), "w");
714        assert_eq!(s0.prev().unwrap(), "q");
715
716        let mut s0 = RopeGraphemes::new(1, s.byte_slice(1..s.len_bytes() - 1));
717        assert_eq!(s0.next().unwrap(), "w");
718        assert_eq!(s0.next().unwrap(), "e");
719        assert_eq!(s0.next().unwrap(), "r");
720        assert_eq!(s0.next().unwrap(), "t");
721        assert!(s0.next().is_none());
722        assert_eq!(s0.prev().unwrap(), "t");
723        assert_eq!(s0.prev().unwrap(), "r");
724        assert_eq!(s0.prev().unwrap(), "e");
725        assert_eq!(s0.prev().unwrap(), "w");
726
727        let mut s0 = RopeGraphemes::new(3, s.byte_slice(3..3));
728        assert!(s0.next().is_none());
729        assert!(s0.prev().is_none());
730    }
731
732    #[test]
733    fn test_rope_graphemes2() {
734        // complicated graphemes
735        let s = Rope::from("w🤷‍♂️xw🤷‍♀️xw🤦‍♂️xw❤️xw🤦‍♀️xw💕🙍🏿‍♀️x");
736
737        let mut s0 = RopeGraphemes::new(0, s.byte_slice(..));
738        assert_eq!(s0.next().unwrap(), "w");
739        assert_eq!(s0.next().unwrap(), "🤷‍♂️");
740        assert_eq!(s0.next().unwrap(), "x");
741        assert_eq!(s0.next().unwrap(), "w");
742        assert_eq!(s0.next().unwrap(), "🤷‍♀️");
743        assert_eq!(s0.next().unwrap(), "x");
744        assert_eq!(s0.next().unwrap(), "w");
745        assert_eq!(s0.next().unwrap(), "🤦‍♂️");
746        assert_eq!(s0.next().unwrap(), "x");
747        assert_eq!(s0.next().unwrap(), "w");
748        assert_eq!(s0.next().unwrap(), "❤️");
749        assert_eq!(s0.next().unwrap(), "x");
750        assert_eq!(s0.next().unwrap(), "w");
751        assert_eq!(s0.next().unwrap(), "🤦‍♀️");
752        assert_eq!(s0.next().unwrap(), "x");
753        assert_eq!(s0.next().unwrap(), "w");
754        assert_eq!(s0.next().unwrap(), "💕");
755        assert_eq!(s0.next().unwrap(), "🙍🏿‍♀️");
756        assert_eq!(s0.next().unwrap(), "x");
757        assert!(s0.next().is_none());
758        assert_eq!(s0.prev().unwrap(), "x");
759        assert_eq!(s0.prev().unwrap(), "🙍🏿‍♀️");
760        assert_eq!(s0.prev().unwrap(), "💕");
761        assert_eq!(s0.prev().unwrap(), "w");
762        assert_eq!(s0.prev().unwrap(), "x");
763        assert_eq!(s0.prev().unwrap(), "🤦‍♀️");
764        assert_eq!(s0.prev().unwrap(), "w");
765        assert_eq!(s0.prev().unwrap(), "x");
766        assert_eq!(s0.prev().unwrap(), "❤️");
767        assert_eq!(s0.prev().unwrap(), "w");
768        assert_eq!(s0.prev().unwrap(), "x");
769        assert_eq!(s0.prev().unwrap(), "🤦‍♂️");
770        assert_eq!(s0.prev().unwrap(), "w");
771        assert_eq!(s0.prev().unwrap(), "x");
772        assert_eq!(s0.prev().unwrap(), "🤷‍♀️");
773        assert_eq!(s0.prev().unwrap(), "w");
774        assert_eq!(s0.prev().unwrap(), "x");
775        assert_eq!(s0.prev().unwrap(), "🤷‍♂️");
776        assert_eq!(s0.prev().unwrap(), "w");
777    }
778
779    #[test]
780    fn test_rope_graphemes3() {
781        // complicated graphemes
782        let s = Rope::from("qwertz");
783        let mut s0 = RopeGraphemes::new_offset(0, s.byte_slice(..), 3).expect("fine");
784        assert_eq!(s0.next().unwrap(), "r");
785        assert_eq!(s0.prev().unwrap(), "r");
786        assert_eq!(s0.prev().unwrap(), "e");
787
788        let mut s0 = RopeGraphemes::new_offset(0, s.byte_slice(..), 3).expect("fine");
789        assert_eq!(s0.next().unwrap().text_bytes(), 3..4);
790        assert_eq!(s0.prev().unwrap().text_bytes(), 3..4);
791        assert_eq!(s0.prev().unwrap().text_bytes(), 2..3);
792
793        let s = Rope::from("w🤷‍♂️🤷‍♀️🤦‍♂️❤️🤦‍♀️💕🙍🏿‍♀️x");
794        let mut s0 = RopeGraphemes::new_offset(0, s.byte_slice(..), 21).expect("fine");
795        assert_eq!(s0.next().unwrap(), "♀\u{fe0f}");
796        assert_eq!(s0.next().unwrap(), "🤦\u{200d}♂\u{fe0f}");
797        assert_eq!(s0.prev().unwrap(), "🤦\u{200d}♂\u{fe0f}");
798        assert_eq!(s0.prev().unwrap(), "🤷\u{200d}♀\u{fe0f}");
799
800        let s = Rope::from("w🤷‍♂️🤷‍♀️🤦‍♂️❤️🤦‍♀️💕🙍🏿‍♀️x");
801        let mut s0 = RopeGraphemes::new_offset(0, s.byte_slice(..), 21).expect("fine");
802        assert_eq!(s0.next().unwrap().text_bytes(), 21..27);
803        assert_eq!(s0.next().unwrap().text_bytes(), 27..40);
804        assert_eq!(s0.prev().unwrap().text_bytes(), 27..40);
805        assert_eq!(s0.prev().unwrap().text_bytes(), 14..27);
806    }
807
808    #[test]
809    fn test_rope_graphemes4() {
810        // offsets and partial slices
811        let s = Rope::from("qwertz");
812        let mut s0 = RopeGraphemes::new_offset(1, s.byte_slice(1..5), 2).expect("fine");
813        s0.next();
814        assert_eq!(s0.text_offset(), 4);
815        s0.next();
816        assert_eq!(s0.text_offset(), 5);
817        s0.next();
818        assert_eq!(s0.text_offset(), 5);
819        s0.next();
820        assert_eq!(s0.text_offset(), 5);
821        s0.prev();
822        assert_eq!(s0.text_offset(), 4);
823        s0.prev();
824        assert_eq!(s0.text_offset(), 3);
825        s0.prev();
826        assert_eq!(s0.text_offset(), 2);
827        s0.prev();
828        assert_eq!(s0.text_offset(), 1);
829        s0.prev();
830        assert_eq!(s0.text_offset(), 1);
831    }
832
833    #[test]
834    fn test_rope_graphemes5() {
835        // offsets and partial slices
836        let s = Rope::from("qwertz");
837        let mut s0 = RopeGraphemes::new_offset(1, s.byte_slice(1..5), 2)
838            .expect("fine")
839            .rev_cursor();
840        assert_eq!(s0.next().unwrap(), "e");
841        assert_eq!(s0.text_offset(), 2);
842
843        assert_eq!(s0.next().unwrap(), "w");
844        assert_eq!(s0.text_offset(), 1);
845
846        assert_eq!(s0.prev().unwrap(), "w");
847        assert_eq!(s0.text_offset(), 2);
848
849        assert_eq!(s0.prev().unwrap(), "e");
850        assert_eq!(s0.text_offset(), 3);
851
852        assert_eq!(s0.prev().unwrap(), "r");
853        assert_eq!(s0.text_offset(), 4);
854
855        assert_eq!(s0.prev().unwrap(), "t");
856        assert_eq!(s0.text_offset(), 5);
857    }
858
859    #[test]
860    fn test_rope_graphemes6() {
861        // text rope boundary
862        let s = Rope::from(
863            "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
864             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
865             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
866             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
867             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
868             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
869             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
870             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
871             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
872             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
873             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
874             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
875             ",
876        );
877        assert_eq!(s.len_bytes(), 1200);
878        let mut s0 = RopeGraphemes::new_offset(1, s.byte_slice(1..1199), 0).expect("fine");
879        assert_eq!(s0.nth(598).unwrap(), "J");
880
881        assert_eq!(s0.next().unwrap(), "0");
882        assert_eq!(s0.text_offset(), 601);
883        assert_eq!(s0.next().unwrap(), "1");
884        assert_eq!(s0.text_offset(), 602);
885        assert_eq!(s0.prev().unwrap(), "1");
886        assert_eq!(s0.text_offset(), 601);
887        assert_eq!(s0.prev().unwrap(), "0");
888        assert_eq!(s0.text_offset(), 600);
889        assert_eq!(s0.prev().unwrap(), "J");
890        assert_eq!(s0.text_offset(), 599);
891    }
892
893    #[test]
894    fn test_rope_graphemes7() {
895        // test complicated grapheme at rope boundary
896        let s = Rope::from(
897            "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
898             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
899             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
900             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
901             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
902             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghi🤷‍♂️\
903             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
904             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
905             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
906             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
907             012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678)\
908             abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghiJ\
909             ",
910        );
911        assert_eq!(s.len_bytes(), 1212);
912        assert_eq!(s.chunks().next().unwrap().len(), 606);
913        let mut s0 = RopeGraphemes::new_offset(1, s.byte_slice(1..1199), 0).expect("fine");
914        assert_eq!(s0.nth(598).unwrap(), "🤷‍♂️");
915
916        assert_eq!(s0.next().unwrap(), "0");
917        assert_eq!(s0.text_offset(), 613);
918        assert_eq!(s0.next().unwrap(), "1");
919        assert_eq!(s0.text_offset(), 614);
920        assert_eq!(s0.prev().unwrap(), "1");
921        assert_eq!(s0.text_offset(), 613);
922        assert_eq!(s0.prev().unwrap(), "0");
923        assert_eq!(s0.text_offset(), 612);
924        assert_eq!(s0.prev().unwrap(), "🤷‍♂️");
925        assert_eq!(s0.text_offset(), 599);
926        assert_eq!(s0.prev().unwrap(), "i");
927        assert_eq!(s0.text_offset(), 598);
928
929        assert_eq!(s0.next().unwrap(), "i");
930        assert_eq!(s0.text_offset(), 599);
931        assert_eq!(s0.next().unwrap(), "🤷‍♂️");
932        assert_eq!(s0.text_offset(), 612);
933        assert_eq!(s0.next().unwrap(), "0");
934        assert_eq!(s0.text_offset(), 613);
935        assert_eq!(s0.next().unwrap(), "1");
936        assert_eq!(s0.text_offset(), 614);
937    }
938
939    #[test]
940    fn test_rev_graphemes() {
941        let mut it = StrGraphemes::new_offset(0, "\r\n", 2);
942        assert_eq!(it.prev().unwrap(), "\r\n");
943
944        let mut it = StrGraphemes::new_offset(0, "\r\r\n", 3);
945        assert_eq!(it.prev().unwrap(), "\r\n");
946        assert_eq!(it.prev().unwrap(), "\r");
947
948        let mut it = StrGraphemes::new_offset(0, "\r\r\n\n", 4);
949        assert_eq!(it.prev().unwrap(), "\n");
950        assert_eq!(it.prev().unwrap(), "\r\n");
951        assert_eq!(it.prev().unwrap(), "\r");
952    }
953}