duat_term/area/
mod.rs

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