duat_term/area/
mod.rs

1mod iter;
2
3use std::{fmt::Alignment, sync::Arc};
4
5use crossterm::cursor;
6use duat_core::{
7    cache::bincode::{Decode, Encode},
8    cfg::PrintCfg,
9    form::Painter,
10    text::{FwdIter, Item, Part, Point, RevIter, Text, err},
11    ui::{self, Axis, Caret, Constraint, DuatPermission, PushSpecs},
12};
13use iter::{print_iter, print_iter_indented, rev_print_iter};
14
15use crate::{
16    AreaId, Mutex,
17    layout::{Layout, Rect, transfer_vars},
18    print::Gaps,
19    queue, style,
20};
21
22#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
23pub struct Coord {
24    pub y: u32,
25    pub x: u32,
26}
27
28impl std::fmt::Debug for Coord {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        f.write_fmt(format_args!("x: {}, y: {}", self.x, self.y))
31    }
32}
33
34impl Coord {
35    pub fn new(x: u32, y: u32) -> Coord {
36        Coord { x, y }
37    }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
41pub struct Coords {
42    pub tl: Coord,
43    pub br: Coord,
44}
45impl Coords {
46    pub fn new(tl: Coord, br: Coord) -> Self {
47        Coords { tl, br }
48    }
49
50    pub fn width(&self) -> u32 {
51        self.br.x - self.tl.x
52    }
53
54    pub fn height(&self) -> u32 {
55        self.br.y - self.tl.y
56    }
57
58    pub fn intersects(&self, other: Self) -> bool {
59        let and_tl = self.tl.max(other.tl);
60        let and_br = self.br.min(other.br);
61        if and_tl.x > and_br.x || and_tl.y > and_br.y {
62            return false;
63        }
64
65        let and_coords = Coords::new(and_tl, and_br);
66        and_coords.width() > 0 && and_coords.height() > 0
67    }
68}
69
70#[derive(Clone)]
71pub struct Area {
72    layouts: Arc<Mutex<Vec<Layout>>>,
73    pub id: AreaId,
74}
75
76impl PartialEq for Area {
77    fn eq(&self, other: &Self) -> bool {
78        self.id == other.id
79    }
80}
81
82impl Area {
83    pub fn new(id: AreaId, layouts: Arc<Mutex<Vec<Layout>>>) -> Self {
84        Self { layouts, id }
85    }
86
87    fn print<'a>(
88        &self,
89        text: &mut Text,
90        cfg: PrintCfg,
91        mut painter: Painter,
92        mut f: impl FnMut(&Caret, &Item) + 'a,
93    ) {
94        let layouts = self.layouts.lock();
95        let start = |_: &Text| layouted::first_points(self, &layouts).0;
96        let end = |text: &Text| layouted::last_points(self, &layouts, text, cfg).0;
97        text.update_range(start, end);
98
99        let layout = get_layout(&layouts, self.id).unwrap();
100        let is_active = layout.active_id() == self.id;
101
102        let (mut lines, iter) = {
103            let rect = layout.get(self.id).unwrap();
104
105            let info = {
106                let mut info = rect.print_info().unwrap().write();
107                info.fix(text);
108                *info
109            };
110
111            let lines = layout.printer.lines(rect.var_points(), info.x_shift, cfg);
112            if lines.coords().width() == 0 || lines.coords().height() == 0 {
113                return;
114            }
115
116            let iter = {
117                let line_start = text.visual_line_start(info.points);
118                let iter = text.iter_fwd(line_start);
119                print_iter(iter, lines.cap(), cfg, info.points)
120            };
121
122            (lines, iter)
123        };
124
125        let mut cur_style = None;
126        enum Cursor {
127            Main,
128            Extra,
129        }
130
131        let lines_left = {
132            // The y here represents the bottom of the current row of cells.
133            let tl_y = lines.coords().tl.y;
134            let mut y = tl_y;
135            let mut cursor = None;
136
137            for (caret, item) in iter {
138                f(&caret, &item);
139
140                let Caret { x, len, wrap } = caret;
141                let Item { part, .. } = item;
142
143                if wrap {
144                    if y > lines.coords().tl.y {
145                        lines.end_line(&painter);
146                    }
147                    if y == lines.coords().br.y {
148                        break;
149                    }
150                    (0..x).for_each(|_| lines.push_char(' ', 1));
151                    style!(lines, painter.make_style());
152                    y += 1
153                }
154
155                match part {
156                    Part::Char(char) => {
157                        painter.confirm_printing();
158                        if let Some(style) = cur_style.take() {
159                            style!(lines, style);
160                        }
161                        match char {
162                            '\t' => (0..len).for_each(|_| lines.push_char(' ', 1)),
163                            '\n' => {}
164                            char => lines.push_char(char, len),
165                        }
166                        if let Some(cursor) = cursor.take() {
167                            style!(lines, match cursor {
168                                Cursor::Main => painter.remove_main_cursor(),
169                                Cursor::Extra => painter.remove_extra_cursor(),
170                            })
171                        }
172                    }
173                    Part::PushForm(id) => {
174                        cur_style = Some(painter.apply(id));
175                    }
176                    Part::PopForm(id) => {
177                        cur_style = Some(painter.remove(id));
178                    }
179                    Part::MainCursor => {
180                        if let Some(shape) = painter.main_cursor()
181                            && is_active
182                        {
183                            lines.show_real_cursor();
184                            queue!(lines, shape, cursor::SavePosition);
185                        } else {
186                            cursor = Some(Cursor::Main);
187                            lines.hide_real_cursor();
188                            cur_style = Some(painter.apply_main_cursor());
189                        }
190                    }
191                    Part::ExtraCursor => {
192                        cursor = Some(Cursor::Extra);
193                        cur_style = Some(painter.apply_extra_cursor());
194                    }
195                    Part::AlignLeft if !cfg.wrap_method.is_no_wrap() => {
196                        lines.realign(Alignment::Left)
197                    }
198                    Part::AlignCenter if !cfg.wrap_method.is_no_wrap() => {
199                        lines.realign(Alignment::Center)
200                    }
201                    Part::AlignRight if !cfg.wrap_method.is_no_wrap() => {
202                        lines.realign(Alignment::Right)
203                    }
204                    Part::Spacer if !cfg.wrap_method.is_no_wrap() => {
205                        lines.add_spacer();
206                    }
207                    Part::ResetState => {
208                        style!(lines, painter.reset())
209                    }
210                    Part::ToggleStart(_) | Part::ToggleEnd(_) => todo!(),
211                    _ => {}
212                }
213            }
214
215            if !lines.is_empty() {
216                lines.end_line(&painter);
217            }
218
219            lines.coords().br.y - y
220        };
221
222        for _ in 0..lines_left {
223            lines.end_line(&painter);
224        }
225
226        layout.printer.send(self.id, lines);
227    }
228}
229
230impl ui::Area for Area {
231    type Cache = PrintInfo;
232    type PrintInfo = PrintInfo;
233    type Ui = crate::Ui;
234
235    /////////// Modification
236
237    fn bisect(
238        &self,
239        specs: PushSpecs,
240        cluster: bool,
241        on_files: bool,
242        cache: PrintInfo,
243        _: DuatPermission,
244    ) -> (Area, Option<Area>) {
245        let mut layouts = self.layouts.lock();
246        let layout = get_layout_mut(&mut layouts, self.id).unwrap();
247
248        let (child, parent) = layout.bisect(self.id, specs, cluster, on_files, cache);
249
250        (
251            Area::new(child, self.layouts.clone()),
252            parent.map(|parent| Area::new(parent, self.layouts.clone())),
253        )
254    }
255
256    fn delete(&self, _: DuatPermission) -> Option<Self> {
257        let mut layouts = self.layouts.lock();
258        // This Area may have already been deleted, so a Layout may not be
259        // found.
260        let layout = get_layout_mut(&mut layouts, self.id)?;
261        layout
262            .delete(self.id)
263            .map(|id| Area::new(id, self.layouts.clone()))
264    }
265
266    fn swap(&self, rhs: &Self, _: DuatPermission) {
267        let mut layouts = self.layouts.lock();
268        let lhs_lay = get_layout_pos(&layouts, self.id).unwrap();
269        let rhs_lay = get_layout_pos(&layouts, rhs.id).unwrap();
270
271        if lhs_lay == rhs_lay {
272            let layout = &mut layouts[lhs_lay];
273            let lhs_id = layout.rects.get_cluster_master(self.id).unwrap_or(self.id);
274            let rhs_id = layout.rects.get_cluster_master(rhs.id).unwrap_or(rhs.id);
275            if lhs_id == rhs_id {
276                return;
277            }
278            layout.swap(lhs_id, rhs_id);
279        } else {
280            let [lhs_lay, rhs_lay] = layouts.get_disjoint_mut([lhs_lay, rhs_lay]).unwrap();
281            let lhs_id = lhs_lay.rects.get_cluster_master(self.id).unwrap_or(self.id);
282            let rhs_id = rhs_lay.rects.get_cluster_master(rhs.id).unwrap_or(rhs.id);
283
284            let lhs_rect = lhs_lay.rects.get_mut(lhs_id).unwrap();
285            let rhs_rect = rhs_lay.rects.get_mut(rhs_id).unwrap();
286
287            let lhs_p = &lhs_lay.printer;
288            let rhs_p = &rhs_lay.printer;
289            transfer_vars(lhs_p, rhs_p, lhs_rect);
290            transfer_vars(rhs_p, lhs_p, rhs_rect);
291
292            std::mem::swap(lhs_rect, rhs_rect);
293
294            lhs_lay.reset_eqs(rhs_id);
295            rhs_lay.reset_eqs(lhs_id);
296        }
297
298        for lay in [lhs_lay, rhs_lay] {
299            layouts[lay].printer.update(false);
300        }
301    }
302
303    fn spawn_floating(
304        &self,
305        at: impl duat_core::text::TwoPoints,
306        specs: PushSpecs,
307        text: &Text,
308        cfg: PrintCfg,
309        _: DuatPermission,
310    ) -> Self {
311        let points = at.to_points();
312        let mut coord = {
313            let layouts = self.layouts.lock();
314            let layout = get_layout(&layouts, self.id).unwrap();
315            let rect = layout.get(self.id).unwrap();
316            layout.printer.coords(rect.var_points(), false).tl
317        };
318        let mut iter = self.print_iter_from_top(text, cfg);
319        while let Some((caret, item)) = iter.next()
320            && item.points() <= points
321        {
322            coord.x = caret.x;
323            coord.y += caret.wrap as u32;
324        }
325
326        let mut layouts = self.layouts.lock();
327        let layout = get_layout_mut(&mut layouts, self.id).unwrap();
328
329        let _floating = layout.new_floating(at, specs, text, cfg);
330
331        todo!();
332    }
333
334    fn constrain_hor(&self, cons: impl IntoIterator<Item = Constraint>) -> Result<(), Text> {
335        let cons = {
336            let mut cons: Vec<Constraint> = cons.into_iter().collect();
337            cons.sort_unstable();
338            cons
339        };
340
341        let mut layouts = self.layouts.lock();
342        let layout = get_layout_mut(&mut layouts, self.id).unwrap();
343        let old_cons = layout
344            .rects
345            .get_constraints_mut(self.id)
346            .ok_or_else(|| err!("Area has no parents, so it can't be constrained"))?
347            .clone();
348
349        if old_cons.on(Axis::Horizontal).eq(cons.iter().cloned()) {
350            return Ok(());
351        };
352
353        *layout.rects.get_constraints_mut(self.id).unwrap() = {
354            let (cons, old_eqs) = old_cons.replace(cons.into_iter(), Axis::Horizontal);
355
356            let (_, parent) = layout.get_parent(self.id).unwrap();
357            let rect = layout.get(self.id).unwrap();
358
359            let (cons, new_eqs) = cons.apply(rect, parent.id(), &layout.rects);
360            layout.printer.replace_and_update(old_eqs, new_eqs, false);
361            cons
362        };
363
364        Ok(())
365    }
366
367    fn constrain_ver(&self, cons: impl IntoIterator<Item = Constraint>) -> Result<(), Text> {
368        let cons = {
369            let mut cons: Vec<Constraint> = cons.into_iter().collect();
370            cons.sort_unstable();
371            cons
372        };
373
374        let mut layouts = self.layouts.lock();
375        let layout = get_layout_mut(&mut layouts, self.id).unwrap();
376        let old_cons = layout
377            .rects
378            .get_constraints_mut(self.id)
379            .ok_or_else(|| err!("Area has no parents, so it can't be constrained"))?
380            .clone();
381
382        if old_cons.on(Axis::Vertical).eq(cons.iter().cloned()) {
383            return Ok(());
384        };
385
386        *layout.rects.get_constraints_mut(self.id).unwrap() = {
387            let (cons, old_eqs) = old_cons.replace(cons.into_iter(), Axis::Vertical);
388
389            let (_, parent) = layout.get_parent(self.id).unwrap();
390            let rect = layout.get(self.id).unwrap();
391
392            let (cons, new_eqs) = cons.apply(rect, parent.id(), &layout.rects);
393            layout.printer.replace_and_update(old_eqs, new_eqs, false);
394            cons
395        };
396
397        Ok(())
398    }
399
400    fn restore_constraints(&self) -> Result<(), Text> {
401        todo!();
402    }
403
404    fn request_width_to_fit(&self, _text: &str) -> Result<(), Text> {
405        todo!();
406    }
407
408    fn scroll_around_point(&self, text: &Text, point: Point, cfg: PrintCfg) {
409        let layouts = self.layouts.lock();
410        let layout = get_layout(&layouts, self.id).unwrap();
411        let rect = layout.get(self.id).unwrap();
412
413        let (mut info, w, h) = {
414            let coords = layout.printer.coords(rect.var_points(), false);
415            let info = rect.print_info().unwrap();
416            (info.write(), coords.width(), coords.height())
417        };
418
419        if w > 0 && h > 0 {
420            scroll_ver_around(&mut info, w, h, point, text, cfg);
421            scroll_hor_around(&mut info, w, point, text, cfg);
422        }
423
424        info.prev_main = point;
425        info.last_points = None;
426    }
427
428    fn set_as_active(&self) {
429        let mut layouts = self.layouts.lock();
430        get_layout_mut(&mut layouts, self.id).unwrap().active_id = self.id;
431    }
432
433    ////////// Printing
434
435    fn print(&self, text: &mut Text, cfg: PrintCfg, painter: Painter) {
436        self.print(text, cfg, painter, |_, _| {})
437    }
438
439    fn print_with<'a>(
440        &self,
441        text: &mut Text,
442        cfg: PrintCfg,
443        painter: Painter,
444        f: impl FnMut(&Caret, &Item) + 'a,
445    ) {
446        self.print(text, cfg, painter, f)
447    }
448
449    fn set_print_info(&self, info: Self::PrintInfo) {
450        let layouts = self.layouts.lock();
451        let layout = get_layout(&layouts, self.id).unwrap();
452        *layout.get(self.id).unwrap().print_info().unwrap().write() = info;
453    }
454
455    fn print_iter<'a>(
456        &self,
457        iter: FwdIter<'a>,
458        cfg: PrintCfg,
459    ) -> impl Iterator<Item = (Caret, Item)> + Clone + 'a {
460        let points = iter.points();
461        print_iter(iter, cfg.wrap_width(self.width()), cfg, points)
462    }
463
464    fn print_iter_from_top<'a>(
465        &self,
466        text: &'a Text,
467        cfg: PrintCfg,
468    ) -> impl Iterator<Item = (Caret, Item)> + Clone + 'a {
469        let (info, width) = {
470            let layouts = self.layouts.lock();
471            let layout = get_layout(&layouts, self.id).unwrap();
472            let rect = get_rect(&layouts, self.id).unwrap();
473
474            let info = rect.print_info().unwrap();
475            let info = info.read();
476
477            let coords = layout.printer.coords(rect.var_points(), false);
478
479            (*info, coords.width())
480        };
481        let line_start = text.visual_line_start(info.points);
482        let iter = text.iter_fwd(line_start);
483
484        print_iter(iter, cfg.wrap_width(width), cfg, info.points)
485    }
486
487    fn rev_print_iter<'a>(
488        &self,
489        iter: RevIter<'a>,
490        cfg: PrintCfg,
491    ) -> impl Iterator<Item = (Caret, Item)> + Clone + 'a {
492        rev_print_iter(iter, cfg.wrap_width(self.width()), cfg)
493    }
494
495    fn has_changed(&self) -> bool {
496        let layouts = self.layouts.lock();
497        let layout = get_layout(&layouts, self.id).unwrap();
498        let rect = layout.get(self.id).unwrap();
499        rect.has_changed(layout)
500    }
501
502    ////////// Queries
503
504    fn is_master_of(&self, other: &Self) -> bool {
505        if other.id == self.id {
506            return true;
507        }
508        let layouts = self.layouts.lock();
509        let layout = get_layout(&layouts, self.id).unwrap();
510        let mut parent_id = other.id;
511        while let Some((_, parent)) = layout.get_parent(parent_id) {
512            parent_id = parent.id();
513            if parent.id() == self.id {
514                return true;
515            }
516        }
517
518        parent_id == self.id
519    }
520
521    fn get_cluster_master(&self) -> Option<Self> {
522        let layouts = self.layouts.lock();
523        get_layout(&layouts, self.id)
524            .unwrap()
525            .rects
526            .get_cluster_master(self.id)
527            .map(|id| Area::new(id, self.layouts.clone()))
528    }
529
530    fn cache(&self) -> Option<Self::Cache> {
531        let layouts = self.layouts.lock();
532        get_rect(&layouts, self.id)
533            .unwrap()
534            .print_info()
535            .map(|info| *info.read())
536    }
537
538    fn width(&self) -> u32 {
539        let layouts = self.layouts.lock();
540        let layout = get_layout(&layouts, self.id).unwrap();
541        let rect = layout.get(self.id).unwrap();
542        let coords = layout.printer.coords(rect.var_points(), false);
543        coords.width()
544    }
545
546    fn height(&self) -> u32 {
547        let layouts = self.layouts.lock();
548        let layout = get_layout(&layouts, self.id).unwrap();
549        let rect = layout.get(self.id).unwrap();
550        let coords = layout.printer.coords(rect.var_points(), false);
551        coords.height()
552    }
553
554    fn first_points(&self, _text: &Text, _cfg: PrintCfg) -> (Point, Option<Point>) {
555        let layouts = self.layouts.lock();
556        layouted::first_points(self, &layouts)
557    }
558
559    fn last_points(&self, text: &Text, cfg: PrintCfg) -> (Point, Option<Point>) {
560        let layouts = self.layouts.lock();
561        layouted::last_points(self, &layouts, text, cfg)
562    }
563
564    fn print_info(&self) -> Self::PrintInfo {
565        let layouts = self.layouts.lock();
566        *get_rect(&layouts, self.id)
567            .unwrap()
568            .print_info()
569            .unwrap()
570            .read()
571    }
572
573    fn is_active(&self) -> bool {
574        get_layout(&self.layouts.lock(), self.id).unwrap().active_id == self.id
575    }
576}
577
578// NOTE: The defaultness in here, when it comes to `last_main`, may
579// cause issues in the future.
580/// Information about how to print the file on the `Label`.
581#[derive(Default, Debug, Clone, Copy, Encode, Decode)]
582#[bincode(crate = "duat_core::cache::bincode")]
583pub struct PrintInfo {
584    points: (Point, Option<Point>),
585    x_shift: u32,
586    prev_main: Point,
587    last_points: Option<(Point, Option<Point>)>,
588}
589
590impl PrintInfo {
591    fn fix(&mut self, text: &Text) {
592        let max = text.len().min(self.points.0);
593        let (_, max_ghost) = text.ghost_max_points_at(max.byte());
594        self.points = (max, self.points.1.min(max_ghost))
595    }
596}
597
598/// Scrolls down until the gap between the main cursor and the
599/// bottom of the widget is equal to `config.scrolloff.y_gap`.
600fn scroll_ver_around(
601    info: &mut PrintInfo,
602    width: u32,
603    height: u32,
604    point: Point,
605    text: &Text,
606    cfg: PrintCfg,
607) {
608    if info.prev_main == point {
609        return;
610    }
611
612    let points = text.ghost_max_points_at(point.byte());
613    let after = text.points_after(points).unwrap_or_else(|| text.len_points());
614
615    let cap = cfg.wrap_width(width);
616    let mut iter = rev_print_iter(text.iter_rev(after), cap, cfg)
617        .filter_map(|(caret, item)| caret.wrap.then_some(item.points()));
618
619    let target = if info.prev_main > point {
620        cfg.scrolloff.y()
621    } else {
622        height.saturating_sub(cfg.scrolloff.y() + 1)
623    };
624    let first = iter.nth(target as usize).unwrap_or_default();
625
626    if (info.prev_main > point && first <= info.points)
627        || (info.prev_main < point && first >= info.points)
628    {
629        info.points = first;
630    }
631}
632
633/// Scrolls the file horizontally, usually when no wrapping is
634/// being used.
635fn scroll_hor_around(info: &mut PrintInfo, width: u32, p: Point, text: &Text, cfg: PrintCfg) {
636    let cap = cfg.wrap_width(width);
637    // Quick shortcut to avoid iteration.
638    if cap <= width {
639        info.x_shift = 0;
640        return;
641    }
642
643    let (max_shift, start, end) = {
644        let points = text.ghost_max_points_at(p.byte());
645        let after = text.points_after(points).unwrap_or_else(|| text.len_points());
646
647        let mut iter = rev_print_iter(text.iter_rev(after), cap, cfg);
648
649        let (points, start, end, wrap) = iter
650            .find_map(|(Caret { x, len, wrap }, item)| {
651                let points = item.points();
652                item.part.as_char().and(Some((points, x, x + len, wrap)))
653            })
654            .unwrap_or(((Point::default(), None), 0, 0, true));
655
656        let (line_len, gaps) = {
657            let mut gaps = Gaps::OnRight;
658            let (indent, points) = if wrap {
659                (start, points)
660            } else {
661                iter.find_map(|(caret, item)| caret.wrap.then_some((caret.x, item.points())))
662                    .unwrap()
663            };
664
665            let len = print_iter_indented(text.iter_fwd(points), cap, cfg, indent)
666                .inspect(|(_, Item { part, real, .. })| match part {
667                    Part::AlignLeft => gaps = Gaps::OnRight,
668                    Part::AlignCenter => gaps = Gaps::OnSides,
669                    Part::AlignRight => gaps = Gaps::OnLeft,
670                    Part::Spacer => gaps.add_spacer(real.byte()),
671                    _ => {}
672                })
673                .take_while(|(caret, item)| !caret.wrap || item.points() == points)
674                .last()
675                .map(|(Caret { x, len, .. }, _)| x + len)
676                .unwrap_or(0);
677
678            (len, gaps)
679        };
680
681        let diff = match &gaps {
682            Gaps::OnRight => 0,
683            Gaps::OnLeft => cap - line_len,
684            Gaps::OnSides => (cap - line_len) / 2,
685            Gaps::Spacers(bytes) => {
686                let spaces = gaps.get_spaces(cap - line_len);
687                bytes
688                    .iter()
689                    .take_while(|b| **b <= p.byte())
690                    .zip(spaces)
691                    .fold(0, |prev_len, (_, len)| prev_len + len)
692            }
693        };
694
695        (line_len + diff, start + diff, end + diff)
696    };
697
698    info.x_shift = info
699        .x_shift
700        .min(start.saturating_sub(cfg.scrolloff.x()))
701        .max(if cfg.force_scrolloff {
702            (end + cfg.scrolloff.x()).saturating_sub(width)
703        } else {
704            (end + cfg.scrolloff.x())
705                .min(max_shift)
706                .saturating_sub(width)
707        });
708}
709
710mod layouted {
711    use duat_core::{
712        cfg::PrintCfg,
713        text::{Item, Point, Text},
714        ui::Caret,
715    };
716
717    use super::{Area, get_layout, get_rect, iter::print_iter};
718    use crate::layout::Layout;
719
720    pub fn first_points(area: &Area, layouts: &[Layout]) -> (Point, Option<Point>) {
721        let rect = get_rect(layouts, area.id).unwrap();
722        let info = rect.print_info().unwrap();
723        let info = info.read();
724        info.points
725    }
726
727    pub fn last_points(
728        area: &Area,
729        layouts: &[Layout],
730        text: &Text,
731        cfg: PrintCfg,
732    ) -> (Point, Option<Point>) {
733        let (mut info, coords) = {
734            let layout = get_layout(layouts, area.id).unwrap();
735            let rect = layout.get(area.id).unwrap();
736            let info = rect.print_info().unwrap();
737            (
738                info.write(),
739                layout.printer.coords(rect.var_points(), false),
740            )
741        };
742
743        if let Some(last) = info.last_points {
744            return last;
745        }
746
747        let line_start = text.visual_line_start(info.points);
748        let iter = text.iter_fwd(line_start);
749
750        let iter = print_iter(iter, cfg.wrap_width(coords.width()), cfg, info.points);
751        let mut points = info.points;
752        let mut y = 0;
753
754        for (Caret { wrap, .. }, Item { part, real, ghost }) in iter {
755            if wrap {
756                if y == coords.height() {
757                    break;
758                }
759                if part.is_char() {
760                    y += 1
761                }
762            } else {
763                points = (real, ghost);
764            }
765        }
766
767        info.last_points = Some(points);
768
769        points
770    }
771}
772
773fn get_rect(layouts: &[Layout], id: AreaId) -> Option<&Rect> {
774    layouts.iter().find_map(|l| l.get(id))
775}
776
777fn get_layout(layouts: &[Layout], id: AreaId) -> Option<&Layout> {
778    layouts.iter().find(|l| l.get(id).is_some())
779}
780
781fn get_layout_mut(layouts: &mut [Layout], id: AreaId) -> Option<&mut Layout> {
782    layouts.iter_mut().find(|l| l.get(id).is_some())
783}
784
785fn get_layout_pos(layouts: &[Layout], id: AreaId) -> Option<usize> {
786    layouts.iter().position(|l| l.get(id).is_some())
787}