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 #[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 #[inline]
67 pub fn grapheme(&'a self) -> &'a str {
68 self.grapheme.as_ref()
69 }
70
71 #[inline]
73 pub fn into_parts(self) -> (Cow<'a, str>, Range<usize>) {
74 (self.grapheme, self.text_bytes)
75 }
76
77 #[inline]
79 pub fn text_bytes(&self) -> Range<usize> {
80 self.text_bytes.clone()
81 }
82}
83
84#[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 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 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#[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 pub(crate) fn new(slice_offset: usize, slice: RopeSlice<'a>) -> RopeGraphemes<'a> {
233 let mut chunks = slice.chunks();
234
235 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}