1use std::{
16 iter::{Chain, Rev},
17 str::Chars,
18};
19
20use super::{
21 Point, Text, ToggleId, TwoPoints,
22 tags::{self, RawTag},
23};
24use crate::mode::Selection;
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, tp: impl TwoPoints) -> Self {
52 let (r, g) = tp.to_points();
53 let point = r.min(text.len());
54
55 let ghost = g.and_then(|offset| {
56 let (_, max) = text.ghost_max_points_at(r.byte());
57 max.map(|max| (max.min(offset), 0))
58 });
59
60 Self {
61 text,
62 point,
63 init_point: point,
64 chars: buf_chars_fwd(text, point.byte()),
65 tags: text.tags_fwd(point.byte()),
66 conceals: 0,
67
68 main_iter: None,
69 ghost,
70
71 print_ghosts: true,
72 _conceals: Conceal::All,
73 }
74 }
75
76 pub fn no_conceals(self) -> Self {
82 Self { _conceals: Conceal::None, ..self }
83 }
84
85 pub fn dont_conceal_containing(self, list: &'a [Selection]) -> Self {
92 Self {
93 _conceals: Conceal::Excluding(list),
94 ..self
95 }
96 }
97
98 pub fn no_ghosts(self) -> Self {
102 Self { print_ghosts: false, ..self }
103 }
104
105 pub fn no_tags(self) -> impl Iterator<Item = Item> + 'a {
114 self.filter(|item| item.part.is_char())
115 }
116
117 pub fn skip_to(&mut self, tp: impl TwoPoints) {
121 *self = self.text.iter_fwd(tp.to_points().max(self.points()))
122 }
123
124 #[inline(always)]
130 pub fn is_on_ghost(&self) -> bool {
131 self.main_iter.is_some()
132 }
133
134 #[inline(always)]
137 pub fn points(&self) -> (Point, Option<Point>) {
138 if let Some((real, ..)) = self.main_iter.as_ref() {
139 (*real, self.ghost.map(|(tg, _)| tg))
140 } else {
141 (self.point, self.ghost.map(|(p, _)| p))
142 }
143 }
144
145 #[inline(always)]
149 fn handle_special_tag(&mut self, tag: &RawTag, b: usize) -> bool {
150 match tag {
151 RawTag::Ghost(_, id) => {
152 if !self.print_ghosts || b < self.point.byte() || self.conceals > 0 {
153 return true;
154 }
155 let text = self.text.get_ghost(*id).unwrap();
156
157 let (this_ghost, total_ghost) = if let Some((ghost, dist)) = &mut self.ghost {
158 if ghost.byte() >= *dist + text.len().byte() {
159 *dist += text.len().byte();
160 return true;
161 }
162 (text.point_at(ghost.byte() - *dist), *ghost)
163 } else {
164 (Point::default(), Point::default())
165 };
166
167 let iter = text.iter_fwd(this_ghost);
168 let point = std::mem::replace(&mut self.point, this_ghost);
169 let chars = std::mem::replace(&mut self.chars, iter.chars);
170 let tags = std::mem::replace(&mut self.tags, iter.tags);
171
172 self.ghost = Some((total_ghost, total_ghost.byte()));
173 self.main_iter = Some((point, chars, tags));
174 }
175 RawTag::StartConceal(_) => {
176 self.conceals += 1;
177 }
178 RawTag::EndConceal(_) => {
179 self.conceals = self.conceals.saturating_sub(1);
180 if self.conceals == 0 {
181 self.ghost.take_if(|_| self.point.byte() < b);
184 self.point = self.point.max(self.text.point_at(b));
185 self.chars = buf_chars_fwd(self.text, self.point.byte());
186 }
187 }
188 RawTag::ConcealUntil(b) => {
189 let point = self.text.point_at(*b as usize);
190 *self = FwdIter::new_at(self.text, point);
191 return false;
192 }
193 RawTag::MainCaret(_) | RawTag::ExtraCaret(_) | RawTag::Spacer(_)
194 if b < self.init_point.byte() => {}
195 _ => return false,
196 }
197
198 true
199 }
200}
201
202impl Iterator for FwdIter<'_> {
203 type Item = Item;
204
205 #[inline]
206 fn next(&mut self) -> Option<Self::Item> {
207 let tag = self.tags.peek();
208
209 if let Some(&(b, tag)) = tag
210 && (b <= self.point.byte() || self.conceals > 0)
211 {
212 self.tags.next();
213
214 if self.handle_special_tag(&tag, b) {
215 self.next()
216 } else {
217 Some(Item::new(self.points(), Part::from_raw(tag)))
218 }
219 } else if let Some(char) = self.chars.next() {
220 let points = self.points();
221 self.point = self.point.fwd(char);
222
223 self.ghost = match self.main_iter {
224 Some(..) => self.ghost.map(|(g, d)| (g.fwd(char), d + char.len_utf8())),
225 None => None,
226 };
227
228 Some(Item::new(points, Part::Char(char)))
229 } else if let Some(backup) = self.main_iter.take() {
230 (self.point, self.chars, self.tags) = backup;
231 self.next()
232 } else {
233 None
234 }
235 }
236}
237
238#[derive(Clone)]
243pub struct RevIter<'a> {
244 text: &'a Text,
245 point: Point,
246 init_point: Point,
247 chars: RevChars<'a>,
248 tags: tags::RevTags<'a>,
249 conceals: usize,
250
251 main_iter: Option<(Point, RevChars<'a>, tags::RevTags<'a>)>,
252 ghost: Option<(Point, usize)>,
253
254 print_ghosts: bool,
256 _conceals: Conceal<'a>,
257}
258
259impl<'a> RevIter<'a> {
260 pub(super) fn new_at(text: &'a Text, tp: impl TwoPoints) -> Self {
263 let (r, g) = tp.to_points();
264 let point = r.min(text.len());
265
266 let ghost = g.and_then(|offset| {
267 let (_, max) = text.ghost_max_points_at(r.byte());
268 max.map(|max| (max.min(offset), max.byte()))
269 });
270
271 Self {
272 text,
273 point,
274 init_point: point,
275 chars: buf_chars_rev(text, point.byte()),
276 tags: text.tags_rev(point.byte()),
277 conceals: 0,
278
279 main_iter: None,
280 ghost,
281
282 print_ghosts: true,
283 _conceals: Conceal::All,
284 }
285 }
286
287 pub fn no_conceals(self) -> Self {
293 Self { _conceals: Conceal::None, ..self }
294 }
295
296 pub fn no_ghosts(self) -> Self {
300 Self { print_ghosts: false, ..self }
301 }
302
303 pub fn no_tags(self) -> impl Iterator<Item = Item> + 'a {
312 self.filter(|item| item.part.is_char())
313 }
314
315 pub fn points(&self) -> (Point, Option<Point>) {
319 if let Some((real, ..)) = self.main_iter.as_ref() {
320 (*real, Some(self.point))
321 } else {
322 (self.point, self.ghost.map(|(p, _)| p))
323 }
324 }
325
326 pub fn is_on_ghost(&self) -> bool {
330 self.main_iter.is_some()
331 }
332
333 #[inline]
337 fn handled_meta_tag(&mut self, tag: &RawTag, b: usize) -> bool {
338 match tag {
339 RawTag::Ghost(_, id) => {
340 if !self.print_ghosts || b > self.point.byte() || self.conceals > 0 {
341 return true;
342 }
343 let text = self.text.get_ghost(*id).unwrap();
344
345 let (ghost_b, offset) = if let Some((offset, dist)) = &mut self.ghost {
346 if *dist - text.len().byte() >= offset.byte() {
347 *dist -= text.len().byte();
348 return true;
349 }
350 (
351 text.point_at(offset.byte() + text.len().byte() - *dist),
352 *offset,
353 )
354 } else {
355 let this = text.len();
356 let (_, max) = self.text.ghost_max_points_at(b);
357 (this, max.unwrap())
358 };
359
360 let iter = text.iter_rev(ghost_b);
361 let point = std::mem::replace(&mut self.point, offset);
362 let chars = std::mem::replace(&mut self.chars, iter.chars);
363 let tags = std::mem::replace(&mut self.tags, iter.tags);
364
365 self.ghost = Some((offset, offset.byte()));
366 self.main_iter = Some((point, chars, tags));
367 }
368
369 RawTag::StartConceal(_) => {
370 self.conceals = self.conceals.saturating_sub(1);
371 if self.conceals == 0 {
372 self.ghost.take_if(|_| b < self.point.byte());
373 self.point = self.point.min(self.text.point_at(b));
374 self.chars = buf_chars_rev(self.text, self.point.byte());
375 }
376 }
377 RawTag::EndConceal(_) => self.conceals += 1,
378 RawTag::ConcealUntil(b) => {
379 let point = self.text.point_at(*b as usize);
380 *self = RevIter::new_at(self.text, point);
381 return false;
382 }
383 RawTag::MainCaret(_) | RawTag::ExtraCaret(_) | RawTag::Spacer(_)
384 if b > self.init_point.byte() => {}
385 _ => return false,
386 }
387
388 true
389 }
390}
391
392impl Iterator for RevIter<'_> {
393 type Item = Item;
394
395 #[inline]
396 fn next(&mut self) -> Option<Self::Item> {
397 let tag = self.tags.peek();
398
399 if let Some(&(b, tag)) = tag
400 && (b >= self.point.byte() || self.conceals > 0)
401 {
402 self.tags.next();
403
404 if self.handled_meta_tag(&tag, b) {
405 self.next()
406 } else {
407 Some(Item::new(self.points(), Part::from_raw(tag)))
408 }
409 } else if let Some(char) = self.chars.next() {
410 self.point = self.point.rev(char);
411
412 self.ghost = match self.main_iter {
413 Some(..) => self.ghost.map(|(g, d)| (g.rev(char), d - char.len_utf8())),
414 None => None,
415 };
416
417 Some(Item::new(self.points(), Part::Char(char)))
418 } else if let Some(last_iter) = self.main_iter.take() {
419 (self.point, self.chars, self.tags) = last_iter;
420 self.next()
421 } else {
422 None
423 }
424 }
425}
426
427fn buf_chars_fwd(text: &Text, b: usize) -> FwdChars {
428 let [s0, s1] = text.strs(b..).to_array();
429 s0.chars().chain(s1.chars())
430}
431
432fn buf_chars_rev(text: &Text, b: usize) -> RevChars {
433 let [s0, s1] = text.strs(..b).to_array();
434 s1.chars().rev().chain(s0.chars().rev())
435}
436
437#[derive(Debug, Clone, Copy)]
449pub struct Item {
450 pub real: Point,
452 pub ghost: Option<Point>,
462 pub part: Part,
466}
467
468impl Item {
469 #[inline]
471 fn new(tp: impl TwoPoints, part: Part) -> Self {
472 let (real, ghost) = tp.to_points();
473 Self { real, ghost, part }
474 }
475
476 pub fn is_real(&self) -> bool {
480 self.ghost.is_none()
481 }
482
483 pub fn as_real_char(self) -> Option<(Point, char)> {
487 if self.ghost.is_none() {
488 Some(self.real).zip(self.part.as_char())
489 } else {
490 None
491 }
492 }
493
494 pub fn byte(&self) -> usize {
496 self.real.byte()
497 }
498
499 pub fn char(&self) -> usize {
501 self.real.char()
502 }
503
504 pub fn line(&self) -> usize {
506 self.real.line()
507 }
508
509 pub fn points(&self) -> (Point, Option<Point>) {
511 (self.real, self.ghost)
512 }
513}
514
515#[allow(dead_code)]
517#[derive(Debug, Default, Clone)]
518enum Conceal<'a> {
519 #[default]
520 All,
521 None,
522 Excluding(&'a [Selection]),
523 NotOnLineOf(&'a [Selection]),
524}
525
526type FwdChars<'a> = Chain<Chars<'a>, Chars<'a>>;
527type RevChars<'a> = Chain<Rev<Chars<'a>>, Rev<Chars<'a>>>;
528
529use crate::form::FormId;
530
531#[derive(Debug, Clone, Copy, PartialEq, Eq)]
549pub enum Part {
550 Char(char),
554 PushForm(FormId),
559 PopForm(FormId),
564 MainCaret,
570 ExtraCaret,
576 AlignLeft,
578 AlignCenter,
580 AlignRight,
582 Spacer,
586 ToggleStart(ToggleId),
590 ToggleEnd(ToggleId),
594 ResetState,
605}
606
607impl Part {
608 #[inline]
610 pub(super) fn from_raw(value: RawTag) -> Self {
611 match value {
612 RawTag::PushForm(_, id, _) => Part::PushForm(id),
613 RawTag::PopForm(_, id) => Part::PopForm(id),
614 RawTag::MainCaret(_) => Part::MainCaret,
615 RawTag::ExtraCaret(_) => Part::ExtraCaret,
616 RawTag::StartAlignCenter(_) => Part::AlignCenter,
617 RawTag::EndAlignCenter(_) => Part::AlignLeft,
618 RawTag::StartAlignRight(_) => Part::AlignRight,
619 RawTag::EndAlignRight(_) => Part::AlignLeft,
620 RawTag::Spacer(_) => Part::Spacer,
621 RawTag::ToggleStart(_, id) => Part::ToggleStart(id),
622 RawTag::ToggleEnd(_, id) => Part::ToggleEnd(id),
623 RawTag::ConcealUntil(_) => Part::ResetState,
624 RawTag::StartConceal(_) | RawTag::EndConceal(_) | RawTag::Ghost(..) => {
625 unreachable!("These tags are automatically processed elsewhere.")
626 }
627 }
628 }
629
630 #[must_use]
634 #[inline]
635 pub fn is_char(&self) -> bool {
636 matches!(self, Part::Char(_))
637 }
638
639 #[inline]
643 pub fn as_char(&self) -> Option<char> {
644 if let Self::Char(v) = self {
645 Some(*v)
646 } else {
647 None
648 }
649 }
650
651 #[inline]
655 pub fn is_tag(&self) -> bool {
656 !self.is_char()
657 }
658}