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#[derive(Debug, PartialEq)]
13pub struct Grapheme<'a> {
14 grapheme: Cow<'a, str>,
16 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 #[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 #[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 #[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 #[inline]
77 pub fn grapheme(&'a self) -> &'a str {
78 self.grapheme.as_ref()
79 }
80
81 #[inline]
83 pub fn into_parts(self) -> (Cow<'a, str>, Range<usize>) {
84 (self.grapheme, self.text_bytes)
85 }
86
87 #[inline]
89 pub fn text_bytes(&self) -> Range<usize> {
90 self.text_bytes.clone()
91 }
92}
93
94#[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 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 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#[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 pub(crate) fn new(slice_offset: usize, slice: RopeSlice<'a>) -> RopeGraphemes<'a> {
243 let mut chunks = slice.chunks();
244
245 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}