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