1use std::{
16 iter::{Chain, Rev},
17 str::Chars,
18};
19
20use super::{
21 Point, SpawnId, Text, ToggleId,
22 tags::{self, RawTag},
23};
24use crate::{mode::Selection, text::TwoPoints};
25
26#[derive(Clone)]
31pub struct FwdIter<'a> {
32 text: &'a Text,
33 point: Point,
34 init_point: Point,
35 chars: FwdChars<'a>,
36 tags: tags::FwdTags<'a>,
37 conceals: u32,
38
39 main_iter: Option<(Point, FwdChars<'a>, tags::FwdTags<'a>)>,
41 ghost: Option<(Point, usize)>,
42
43 print_ghosts: bool,
45 _conceals: Conceal<'a>,
46}
47
48impl<'a> FwdIter<'a> {
49 pub(super) fn new_at(text: &'a Text, points: TwoPoints) -> Self {
52 let TwoPoints { real, ghost } = points;
53 let point = real.min(text.len());
54
55 let ghost = if let Some(offset) = ghost {
62 let points = text.ghost_max_points_at(real.byte());
63 points.ghost.map(|max| (max.min(offset), 0))
64 } else {
65 let points = text.ghost_max_points_at(real.byte());
66 points.ghost.zip(Some(0))
67 };
68
69 Self {
70 text,
71 point,
72 init_point: point,
73 chars: buf_chars_fwd(text, point.byte()),
74 tags: text.tags_fwd(point.byte(), None),
75 conceals: 0,
76
77 main_iter: None,
78 ghost,
79
80 print_ghosts: true,
81 _conceals: Conceal::All,
82 }
83 }
84
85 pub fn no_conceals(self) -> Self {
91 Self { _conceals: Conceal::None, ..self }
92 }
93
94 pub fn dont_conceal_containing(self, list: &'a [Selection]) -> Self {
101 Self {
102 _conceals: Conceal::Excluding(list),
103 ..self
104 }
105 }
106
107 pub fn no_ghosts(self) -> Self {
111 Self { print_ghosts: false, ..self }
112 }
113
114 pub fn no_tags(self) -> impl Iterator<Item = Item> + 'a {
124 self.filter(|item| item.part.is_char())
125 }
126
127 pub fn skip_to(&mut self, points: TwoPoints) {
131 *self = self.text.iter_fwd(points.max(self.points()))
132 }
133
134 #[inline(always)]
140 pub fn is_on_ghost(&self) -> bool {
141 self.main_iter.is_some()
142 }
143
144 #[inline(always)]
147 pub fn points(&self) -> TwoPoints {
148 if let Some((real, ..)) = self.main_iter.as_ref() {
149 TwoPoints::new(*real, self.ghost.map(|(tg, _)| tg).unwrap())
150 } else {
151 TwoPoints::new_after_ghost(self.point)
152 }
153 }
154
155 pub fn text(&self) -> &'a Text {
157 self.text
158 }
159
160 #[inline(always)]
164 fn handle_special_tag(&mut self, tag: &RawTag, b: usize) -> bool {
165 match tag {
166 RawTag::Ghost(_, id) => {
167 if !self.print_ghosts || b < self.point.byte() || self.conceals > 0 {
168 return true;
169 }
170 let text = self.text.get_ghost(*id).unwrap();
171
172 let (this_ghost, total_ghost) = if let Some((ghost, dist)) = &mut self.ghost {
173 if ghost.byte() >= *dist + text.len().byte() {
174 *dist += text.len().byte();
175 return true;
176 }
177 (text.point_at_byte(ghost.byte() - *dist), *ghost)
178 } else {
179 (Point::default(), Point::default())
180 };
181
182 let iter = text.iter_fwd(this_ghost.to_two_points_before());
183 let point = std::mem::replace(&mut self.point, this_ghost);
184 let chars = std::mem::replace(&mut self.chars, iter.chars);
185 let tags = std::mem::replace(&mut self.tags, iter.tags);
186
187 self.ghost = Some((total_ghost, total_ghost.byte()));
188 self.main_iter = Some((point, chars, tags));
189 }
190 RawTag::StartConceal(_) => {
191 self.conceals += 1;
192 }
193 RawTag::EndConceal(_) => {
194 self.conceals = self.conceals.saturating_sub(1);
195 if self.conceals == 0 {
196 self.ghost.take_if(|_| self.point.byte() < b);
199 self.point = self.point.max(self.text.point_at_byte(b));
200 self.chars = buf_chars_fwd(self.text, self.point.byte());
201 }
202 }
203 RawTag::ConcealUntil(b) => {
204 let point = self.text.point_at_byte(*b as usize);
205 *self = FwdIter::new_at(self.text, point.to_two_points_before());
206 return false;
207 }
208 RawTag::MainCaret(_)
209 | RawTag::ExtraCaret(_)
210 | RawTag::Spacer(_)
211 | RawTag::SpawnedWidget(..)
212 if b < self.init_point.byte() => {}
213 _ => return false,
214 }
215
216 true
217 }
218}
219
220impl Iterator for FwdIter<'_> {
221 type Item = Item;
222
223 #[inline]
224 fn next(&mut self) -> Option<Self::Item> {
225 let tag = self.tags.peek();
226
227 if let Some(&(b, tag)) = tag
228 && (b <= self.point.byte() || self.conceals > 0)
229 {
230 self.tags.next();
231
232 if self.handle_special_tag(&tag, b) {
233 self.next()
234 } else {
235 Some(Item::new(self.points(), Part::from_raw(tag)))
236 }
237 } else if let Some(char) = self.chars.next() {
238 let points = self.points();
239 self.point = self.point.fwd(char);
240
241 self.ghost = match self.main_iter {
242 Some(..) => self.ghost.map(|(g, d)| (g.fwd(char), d + 1)),
243 None => None,
244 };
245
246 Some(Item::new(points, Part::Char(char)))
247 } else if let Some(backup) = self.main_iter.take() {
248 (self.point, self.chars, self.tags) = backup;
249 self.next()
250 } else {
251 None
252 }
253 }
254}
255
256#[derive(Clone)]
261pub struct RevIter<'a> {
262 text: &'a Text,
263 point: Point,
264 init_point: Point,
265 chars: RevChars<'a>,
266 tags: tags::RevTags<'a>,
267 conceals: usize,
268
269 main_iter: Option<(Point, RevChars<'a>, tags::RevTags<'a>)>,
270 ghost: Option<(Point, usize)>,
271
272 print_ghosts: bool,
274 _conceals: Conceal<'a>,
275}
276
277impl<'a> RevIter<'a> {
278 pub(super) fn new_at(text: &'a Text, points: TwoPoints) -> Self {
281 let TwoPoints { real, ghost } = points;
282 let point = real.min(text.len());
283
284 let ghost = ghost.and_then(|offset| {
285 let points = text.ghost_max_points_at(real.byte());
286 points.ghost.map(|max| (max.min(offset), max.byte()))
287 });
288
289 Self {
290 text,
291 point,
292 init_point: point,
293 chars: buf_chars_rev(text, point.byte()),
294 tags: text.tags_rev(point.byte(), None),
295 conceals: 0,
296
297 main_iter: None,
298 ghost,
299
300 print_ghosts: true,
301 _conceals: Conceal::All,
302 }
303 }
304
305 pub fn no_conceals(self) -> Self {
311 Self { _conceals: Conceal::None, ..self }
312 }
313
314 pub fn no_ghosts(self) -> Self {
318 Self { print_ghosts: false, ..self }
319 }
320
321 pub fn no_tags(self) -> impl Iterator<Item = Item> + 'a {
331 self.filter(|item| item.part.is_char())
332 }
333
334 pub fn points(&self) -> TwoPoints {
338 if let Some((real, ..)) = self.main_iter.as_ref() {
339 TwoPoints::new(*real, self.point)
340 } else if let Some((ghost, _)) = self.ghost {
341 TwoPoints::new(self.point, ghost)
342 } else {
343 TwoPoints::new_after_ghost(self.point)
344 }
345 }
346
347 pub fn text(&self) -> &'a Text {
349 self.text
350 }
351
352 pub fn is_on_ghost(&self) -> bool {
356 self.main_iter.is_some()
357 }
358
359 #[inline]
363 fn handled_meta_tag(&mut self, tag: &RawTag, b: usize) -> bool {
364 match tag {
365 RawTag::Ghost(_, id) => {
366 if !self.print_ghosts || b > self.point.byte() || self.conceals > 0 {
367 return true;
368 }
369 let text = self.text.get_ghost(*id).unwrap();
370
371 let (ghost_b, offset) = if let Some((offset, dist)) = &mut self.ghost {
372 if *dist - text.len().byte() >= offset.byte() {
373 *dist -= text.len().byte();
374 return true;
375 }
376 (
377 text.point_at_byte(offset.byte() + text.len().byte() - *dist),
378 *offset,
379 )
380 } else {
381 let this = text.len();
382 let points = self.text.ghost_max_points_at(b);
383 (this, points.ghost.unwrap())
384 };
385
386 let iter = text.iter_rev(ghost_b.to_two_points_before());
387 let point = std::mem::replace(&mut self.point, offset);
388 let chars = std::mem::replace(&mut self.chars, iter.chars);
389 let tags = std::mem::replace(&mut self.tags, iter.tags);
390
391 self.ghost = Some((offset, offset.byte()));
392 self.main_iter = Some((point, chars, tags));
393 }
394
395 RawTag::StartConceal(_) => {
396 self.conceals = self.conceals.saturating_sub(1);
397 if self.conceals == 0 {
398 self.ghost.take_if(|_| b < self.point.byte());
399 self.point = self.point.min(self.text.point_at_byte(b));
400 self.chars = buf_chars_rev(self.text, self.point.byte());
401 }
402 }
403 RawTag::EndConceal(_) => self.conceals += 1,
404 RawTag::ConcealUntil(b) => {
405 let point = self.text.point_at_byte(*b as usize);
406 *self = RevIter::new_at(self.text, point.to_two_points_before());
407 return false;
408 }
409 RawTag::MainCaret(_)
410 | RawTag::ExtraCaret(_)
411 | RawTag::Spacer(_)
412 | RawTag::SpawnedWidget(..)
413 if b > self.init_point.byte() => {}
414 _ => return false,
415 }
416
417 true
418 }
419}
420
421impl Iterator for RevIter<'_> {
422 type Item = Item;
423
424 #[inline]
425 fn next(&mut self) -> Option<Self::Item> {
426 let tag = self.tags.peek();
427
428 if let Some(&(b, tag)) = tag
429 && (b >= self.point.byte() || self.conceals > 0)
430 {
431 self.tags.next();
432
433 if self.handled_meta_tag(&tag, b) {
434 self.next()
435 } else {
436 Some(Item::new(self.points(), Part::from_raw(tag)))
437 }
438 } else if let Some(char) = self.chars.next() {
439 self.point = self.point.rev(char);
440
441 self.ghost = match self.main_iter {
442 Some(..) => self.ghost.map(|(g, d)| (g.rev(char), d - 1)),
443 None => None,
444 };
445
446 Some(Item::new(self.points(), Part::Char(char)))
447 } else if let Some(last_iter) = self.main_iter.take() {
448 (self.point, self.chars, self.tags) = last_iter;
449 self.next()
450 } else {
451 None
452 }
453 }
454}
455
456fn buf_chars_fwd(text: &Text, b: usize) -> FwdChars<'_> {
457 let [s0, s1] = text
458 .slices(b..)
459 .to_array()
460 .map(|s| unsafe { std::str::from_utf8_unchecked(s) });
461 s0.chars().chain(s1.chars())
462}
463
464fn buf_chars_rev(text: &Text, b: usize) -> RevChars<'_> {
465 let [s0, s1] = text
466 .slices(..b)
467 .to_array()
468 .map(|s| unsafe { std::str::from_utf8_unchecked(s) });
469 s1.chars().rev().chain(s0.chars().rev())
470}
471
472#[derive(Debug, Clone, Copy)]
484pub struct Item {
485 pub real: Point,
487 pub ghost: Option<Point>,
497 pub part: Part,
501}
502
503impl Item {
504 #[inline]
506 const fn new(points: TwoPoints, part: Part) -> Self {
507 let TwoPoints { real, ghost } = points;
508 Self { real, ghost, part }
509 }
510
511 pub const fn is_real(&self) -> bool {
515 self.ghost.is_none()
516 }
517
518 pub const fn as_real_char(self) -> Option<(Point, char)> {
522 let Some(char) = self.part.as_char() else {
523 return None;
524 };
525 if self.ghost.is_none() {
526 Some((self.real, char))
527 } else {
528 None
529 }
530 }
531
532 pub const fn byte(&self) -> usize {
534 self.real.byte()
535 }
536
537 pub const fn char(&self) -> usize {
539 self.real.char()
540 }
541
542 pub const fn line(&self) -> usize {
544 self.real.line()
545 }
546
547 pub const fn points(&self) -> TwoPoints {
549 if let Some(ghost) = self.ghost {
550 TwoPoints::new(self.real, ghost)
551 } else {
552 TwoPoints::new_after_ghost(self.real)
553 }
554 }
555}
556
557#[allow(dead_code)]
559#[derive(Debug, Default, Clone)]
560enum Conceal<'a> {
561 #[default]
562 All,
563 None,
564 Excluding(&'a [Selection]),
565 NotOnLineOf(&'a [Selection]),
566}
567
568type FwdChars<'a> = Chain<Chars<'a>, Chars<'a>>;
569type RevChars<'a> = Chain<Rev<Chars<'a>>, Rev<Chars<'a>>>;
570
571use crate::form::FormId;
572
573#[derive(Debug, Clone, Copy, PartialEq, Eq)]
591pub enum Part {
592 Char(char),
596 PushForm(FormId, u8),
601 PopForm(FormId),
606 MainCaret,
612 ExtraCaret,
618 Spacer,
622 ToggleStart(ToggleId),
626 ToggleEnd(ToggleId),
630 SpawnedWidget(SpawnId),
634
635 ResetState,
648}
649
650impl Part {
651 #[inline]
653 pub(super) fn from_raw(value: RawTag) -> Self {
654 match value {
655 RawTag::PushForm(_, id, prio) => Part::PushForm(id, prio),
656 RawTag::PopForm(_, id) => Part::PopForm(id),
657 RawTag::MainCaret(_) => Part::MainCaret,
658 RawTag::ExtraCaret(_) => Part::ExtraCaret,
659 RawTag::Spacer(_) => Part::Spacer,
660 RawTag::StartToggle(_, id) => Part::ToggleStart(id),
661 RawTag::EndToggle(_, id) => Part::ToggleEnd(id),
662 RawTag::ConcealUntil(_) => Part::ResetState,
663 RawTag::SpawnedWidget(_, id) => Part::SpawnedWidget(id),
664 RawTag::StartConceal(_) | RawTag::EndConceal(_) | RawTag::Ghost(..) => {
665 unreachable!("These tags are automatically processed elsewhere.")
666 }
667 }
668 }
669
670 #[must_use]
674 #[inline]
675 pub const fn is_char(&self) -> bool {
676 matches!(self, Part::Char(_))
677 }
678
679 #[inline]
683 pub const fn is_tag(&self) -> bool {
684 !self.is_char()
685 }
686
687 #[inline]
691 pub const fn as_char(&self) -> Option<char> {
692 if let Self::Char(v) = self {
693 Some(*v)
694 } else {
695 None
696 }
697 }
698}