1mod iter;
2
3use std::{fmt::Alignment, io::Write};
4
5use crossterm::cursor;
6use duat_core::{
7 cache::{Deserialize, Serialize},
8 cfg::{IterCfg, PrintCfg},
9 data::RwData,
10 form::Painter,
11 text::{Item, Iter, Part, Point, RevIter, Text},
12 ui::{self, Area as UiArea, Axis, Caret, Constraint, DuatPermission, PushSpecs},
13};
14use iter::{print_iter, print_iter_indented, rev_print_iter};
15
16use crate::{
17 AreaId, ConstraintErr,
18 layout::{Layout, Rect},
19 print::Printer,
20 queue, style,
21};
22
23#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
24pub struct Coord {
25 pub y: u32,
26 pub x: u32,
27}
28
29impl std::fmt::Debug for Coord {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 f.write_fmt(format_args!("x: {}, y: {}", self.x, self.y))
32 }
33}
34
35impl Coord {
36 pub fn new(x: u32, y: u32) -> Coord {
37 Coord { x, y }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
42pub struct Coords {
43 tl: Coord,
44 br: Coord,
45}
46impl Coords {
47 pub fn new(tl: Coord, br: Coord) -> Self {
48 Coords { tl, br }
49 }
50
51 pub fn width(&self) -> u32 {
52 self.br.x - self.tl.x
53 }
54
55 pub fn height(&self) -> u32 {
56 self.br.y - self.tl.y
57 }
58
59 pub fn tl(&self) -> Coord {
60 self.tl
61 }
62
63 pub fn br(&self) -> Coord {
64 self.br
65 }
66}
67
68#[derive(Clone)]
69pub struct Area {
70 layouts: RwData<Vec<Layout>>,
71 pub id: AreaId,
72}
73
74impl PartialEq for Area {
75 fn eq(&self, other: &Self) -> bool {
76 self.id == other.id
77 }
78}
79
80impl Area {
81 pub fn new(id: AreaId, layouts: RwData<Vec<Layout>>) -> Self {
82 Self { layouts, id }
83 }
84
85 fn print<'a>(
86 &self,
87 text: &mut Text,
88 cfg: PrintCfg,
89 painter: Painter,
90 f: impl FnMut(&Caret, &Item) + 'a,
91 ) {
92 if text.needs_update() {
93 let (first_point, _) = self.first_points(text, cfg);
94 let (last_point, _) = self.last_points(text, cfg);
95 text.update_range((first_point, last_point));
96 }
97
98 let layouts = self.layouts.read();
99 let layout = get_layout(&layouts, self.id).unwrap();
100 let is_active = layout.active_id() == self.id;
101 let Some((sender, info)) = layout.get(self.id).and_then(|rect| {
102 let sender = rect.sender();
103 let info = rect.print_info();
104 sender.zip(info).map(|(sender, info)| {
105 let mut info = info.write();
106 info.fix(text);
107 (sender, *info)
108 })
109 }) else {
110 return;
111 };
112
113 let (iter, cfg) = {
114 let line_start = text.visual_line_start(info.points);
115 (text.iter_fwd(line_start), IterCfg::new(cfg).outsource_lfs())
116 };
117
118 let cap = cfg.wrap_width(sender.coords().width());
119 let iter = print_iter(iter, cap, cfg, info.points);
120
121 let mut lines = sender.lines(info.x_shift, cap);
122 let mut cur_style = None;
123
124 enum Cursor {
125 Main,
126 Extra,
127 }
128
129 let lines_left = {
130 let (mut painter, mut f) = (painter, f);
131 let tl_y = sender.coords().tl.y;
133 let mut y = tl_y;
134 let mut cursor = None;
135
136 for (caret, item) in iter {
137 f(&caret, &item);
138
139 let Caret { x, len, wrap } = caret;
140 let Item { part, .. } = item;
141
142 if wrap {
143 if y > sender.coords().tl.y {
144 lines.flush().unwrap();
145 }
146 if y == sender.coords().br.y {
147 break;
148 }
149 (0..x).for_each(|_| lines.push_char(' ', 1));
150 style!(lines, painter.make_style());
151 y += 1
152 }
153
154 match part {
155 Part::Char(char) => {
156 painter.confirm_printing();
157 if let Some(style) = cur_style.take() {
158 style!(lines, style);
159 }
160 match char {
161 '\t' => (0..len).for_each(|_| lines.push_char(' ', 1)),
162 '\n' => {}
163 char => lines.push_char(char, len),
164 }
165 if let Some(cursor) = cursor.take() {
166 style!(lines, match cursor {
167 Cursor::Main => painter.remove_main_cursor(),
168 Cursor::Extra => painter.remove_extra_cursor(),
169 })
170 }
171 }
172 Part::PushForm(id) => {
173 cur_style = Some(painter.apply(id));
174 }
175 Part::PopForm(id) => {
176 cur_style = Some(painter.remove(id));
177 }
178 Part::MainCursor => {
179 if let Some(shape) = painter.main_cursor()
180 && is_active
181 {
182 lines.show_real_cursor();
183 queue!(lines, shape, cursor::SavePosition);
184 } else {
185 cursor = Some(Cursor::Main);
186 lines.hide_real_cursor();
187 cur_style = Some(painter.apply_main_cursor());
188 }
189 }
190 Part::ExtraCursor => {
191 cursor = Some(Cursor::Extra);
192 cur_style = Some(painter.apply_extra_cursor());
193 }
194 Part::AlignLeft if !cfg.wrap_method().is_no_wrap() => {
195 lines.realign(Alignment::Left)
196 }
197 Part::AlignCenter if !cfg.wrap_method().is_no_wrap() => {
198 lines.realign(Alignment::Center)
199 }
200 Part::AlignRight if !cfg.wrap_method().is_no_wrap() => {
201 lines.realign(Alignment::Right)
202 }
203 Part::ResetState => {
204 style!(lines, painter.reset())
205 }
206 Part::ToggleStart(_) => todo!(),
207 Part::ToggleEnd(_) => todo!(),
208 _ => {}
209 }
210 }
211
212 if !lines.is_empty() {
213 lines.flush().unwrap();
214 }
215
216 sender.coords().br.y - y
217 };
218
219 for _ in 0..lines_left {
220 lines.flush().unwrap();
221 }
222
223 sender.send(lines);
224 }
225}
226
227impl ui::Area for Area {
228 type Cache = PrintInfo;
229 type ConstraintChangeErr = ConstraintErr;
230 type PrintInfo = PrintInfo;
231 type Ui = crate::Ui;
232
233 fn bisect(
236 &self,
237 specs: PushSpecs,
238 cluster: bool,
239 on_files: bool,
240 cache: PrintInfo,
241 _: DuatPermission,
242 ) -> (Area, Option<Area>) {
243 let mut layouts = self.layouts.write();
244 let layout = get_layout_mut(&mut layouts, self.id).unwrap();
245
246 let (child, parent) = layout.bisect(self.id, specs, cluster, on_files, cache);
247
248 (
249 Area::new(child, self.layouts.clone()),
250 parent.map(|parent| Area::new(parent, self.layouts.clone())),
251 )
252 }
253
254 fn delete(&self, _: DuatPermission) -> Option<Self> {
255 let mut layouts = self.layouts.write();
256 get_layout_mut(&mut layouts, self.id)?
259 .delete(self.id)
260 .map(|id| Area::new(id, self.layouts.clone()))
261 }
262
263 fn swap(&self, rhs: &Self, _: DuatPermission) {
264 let mut layouts = self.layouts.write();
265 let lhs_win = get_layout_pos(&layouts, self.id).unwrap();
266 let rhs_win = get_layout_pos(&layouts, rhs.id).unwrap();
267
268 if lhs_win == rhs_win {
269 let layout = get_layout_mut(&mut layouts, self.id).unwrap();
270 let lhs_id = layout.rects.get_cluster_master(self.id).unwrap_or(self.id);
271 let rhs_id = layout.rects.get_cluster_master(rhs.id).unwrap_or(rhs.id);
272 if lhs_id == rhs_id {
273 return;
274 }
275 layout.swap(lhs_id, rhs_id);
276 } else {
277 let [lhs_lay, rhs_lay] = layouts.get_disjoint_mut([lhs_win, rhs_win]).unwrap();
278 let lhs_id = lhs_lay.rects.get_cluster_master(self.id).unwrap_or(self.id);
279 let rhs_id = rhs_lay.rects.get_cluster_master(rhs.id).unwrap_or(rhs.id);
280
281 let lhs_rect = lhs_lay.rects.get_mut(lhs_id).unwrap();
282 let rhs_rect = rhs_lay.rects.get_mut(rhs_id).unwrap();
283
284 let mut lhs_p = lhs_lay.printer.write();
285 let mut rhs_p = rhs_lay.printer.write();
286 transfer_vars_and_recvs(&mut lhs_p, &mut rhs_p, lhs_rect);
287 transfer_vars_and_recvs(&mut rhs_p, &mut lhs_p, rhs_rect);
288 drop((lhs_p, rhs_p));
289
290 std::mem::swap(lhs_rect, rhs_rect);
291
292 lhs_lay.reset_eqs(rhs_id);
293 rhs_lay.reset_eqs(lhs_id);
294 }
295 }
296
297 fn constrain_ver(&self, con: Constraint) -> Result<(), ConstraintErr> {
298 let mut layouts = self.layouts.write();
299 let layout = get_layout_mut(&mut layouts, self.id).unwrap();
300 let cons = layout
301 .rects
302 .get_constraints_mut(self.id)
303 .ok_or(ConstraintErr::NoParent)?
304 .clone();
305
306 if let Some(ver) = cons.on(Axis::Vertical)
307 && ver == con
308 {
309 return Ok(());
310 };
311
312 *layout.rects.get_constraints_mut(self.id).unwrap() = {
313 let mut p = layout.printer.write();
314 let cons = cons.replace(con, Axis::Vertical, &mut p);
315
316 let (_, parent) = layout.get_parent(self.id).unwrap();
317 let rect = layout.get(self.id).unwrap();
318
319 let cons = cons.apply(rect, parent.id(), &layout.rects, &mut p);
320 p.flush_equalities().unwrap();
321 cons
322 };
323
324 Ok(())
325 }
326
327 fn constrain_hor(&self, con: Constraint) -> Result<(), ConstraintErr> {
328 let mut layouts = self.layouts.write();
329 let layout = get_layout_mut(&mut layouts, self.id).unwrap();
330 let cons = layout
331 .rects
332 .get_constraints_mut(self.id)
333 .ok_or(ConstraintErr::NoParent)?
334 .clone();
335
336 if let Some(hor) = cons.on(Axis::Horizontal)
337 && hor == con
338 {
339 return Ok(());
340 };
341
342 *layout.rects.get_constraints_mut(self.id).unwrap() = {
343 let mut p = layout.printer.write();
344 let cons = cons.replace(con, Axis::Horizontal, &mut p);
345
346 let (_, parent) = layout.get_parent(self.id).unwrap();
347 let rect = layout.get(self.id).unwrap();
348
349 let cons = cons.apply(rect, parent.id(), &layout.rects, &mut p);
350 p.flush_equalities().unwrap();
351 cons
352 };
353
354 Ok(())
355 }
356
357 fn restore_constraints(&self) -> Result<(), Self::ConstraintChangeErr> {
358 todo!();
359 }
360
361 fn request_width_to_fit(&self, _text: &str) -> Result<(), Self::ConstraintChangeErr> {
362 todo!();
363 }
364
365 fn scroll_around_point(&self, text: &Text, point: Point, cfg: PrintCfg) {
366 let (info, w, h) = {
367 let layouts = self.layouts.read();
368 let rect = get_rect(&layouts, self.id).unwrap();
369 let info = rect.print_info().unwrap();
370 let info = info.read();
371 let width = rect.br().x - rect.tl().x;
372 let height = rect.br().y - rect.tl().y;
373 (*info, width, height)
374 };
375
376 let info = scroll_ver_around(info, w, h, point, text, IterCfg::new(cfg).outsource_lfs());
377 let info = scroll_hor_around(info, w, point, text, IterCfg::new(cfg).outsource_lfs());
378
379 let layouts = self.layouts.read();
380 let rect = get_rect(&layouts, self.id).unwrap();
381 let mut old_info = rect.print_info().unwrap().write();
382 *old_info = info;
383 old_info.prev_main = point;
384 old_info.last_points = None;
385 }
386
387 fn set_as_active(&self) {
388 let mut layouts = self.layouts.write();
389 get_layout_mut(&mut layouts, self.id).unwrap().active_id = self.id;
390 }
391
392 fn print(&self, text: &mut Text, cfg: PrintCfg, painter: Painter) {
395 self.print(text, cfg, painter, |_, _| {})
396 }
397
398 fn print_with<'a>(
399 &self,
400 text: &mut Text,
401 cfg: PrintCfg,
402 painter: Painter,
403 f: impl FnMut(&Caret, &Item) + 'a,
404 ) {
405 self.print(text, cfg, painter, f)
406 }
407
408 fn set_print_info(&self, info: Self::PrintInfo) {
409 let layouts = self.layouts.read();
410 let layout = get_layout(&layouts, self.id).unwrap();
411 *layout.get(self.id).unwrap().print_info().unwrap().write() = info;
412 }
413
414 fn print_iter<'a>(
415 &self,
416 iter: Iter<'a>,
417 cfg: IterCfg,
418 ) -> impl Iterator<Item = (Caret, Item)> + Clone + 'a {
419 let points = iter.points();
420 print_iter(iter, cfg.wrap_width(self.width()), cfg, points)
421 }
422
423 fn print_iter_from_top<'a>(
424 &self,
425 text: &'a Text,
426 cfg: IterCfg,
427 ) -> impl Iterator<Item = (Caret, Item)> + Clone + 'a {
428 let (info, width) = {
429 let layouts = self.layouts.read();
430 let rect = get_rect(&layouts, self.id).unwrap();
431 let info = rect.print_info().unwrap();
432 let info = info.read();
433 (*info, rect.width())
434 };
435 let line_start = text.visual_line_start(info.points);
436 let iter = text.iter_fwd(line_start);
437
438 print_iter(iter, cfg.wrap_width(width), cfg, info.points)
439 }
440
441 fn rev_print_iter<'a>(
442 &self,
443 iter: RevIter<'a>,
444 cfg: IterCfg,
445 ) -> impl Iterator<Item = (Caret, Item)> + Clone + 'a {
446 rev_print_iter(iter, cfg.wrap_width(self.width()), cfg)
447 }
448
449 fn print_info(&self) -> Self::PrintInfo {
450 let layouts = self.layouts.read();
451 *get_rect(&layouts, self.id)
452 .unwrap()
453 .print_info()
454 .unwrap()
455 .read()
456 }
457
458 fn has_changed(&self) -> bool {
461 let layouts = self.layouts.read();
462 get_rect(&layouts, self.id).unwrap().has_changed()
463 }
464
465 fn is_master_of(&self, other: &Self) -> bool {
466 if other.id == self.id {
467 return true;
468 }
469 let layouts = self.layouts.read();
470 let layout = get_layout(&layouts, self.id).unwrap();
471 let mut parent_id = other.id;
472 while let Some((_, parent)) = layout.get_parent(parent_id) {
473 parent_id = parent.id();
474 if parent.id() == self.id {
475 return true;
476 }
477 }
478
479 parent_id == self.id
480 }
481
482 fn get_cluster_master(&self) -> Option<Self> {
483 let layouts = self.layouts.read();
484 get_layout(&layouts, self.id)
485 .unwrap()
486 .rects
487 .get_cluster_master(self.id)
488 .map(|id| Area::new(id, self.layouts.clone()))
489 }
490
491 fn cache(&self) -> Option<Self::Cache> {
492 let layouts = self.layouts.read();
493 get_rect(&layouts, self.id)
494 .unwrap()
495 .print_info()
496 .map(|info| *info.read())
497 }
498
499 fn width(&self) -> u32 {
500 get_rect(&self.layouts.read(), self.id).unwrap().width()
501 }
502
503 fn height(&self) -> u32 {
504 get_rect(&self.layouts.read(), self.id).unwrap().height()
505 }
506
507 fn first_points(&self, _text: &Text, _cfg: PrintCfg) -> (Point, Option<Point>) {
508 let layouts = self.layouts.read();
509 let rect = get_rect(&layouts, self.id).unwrap();
510 let info = rect.print_info().unwrap();
511 let info = info.read();
512 info.points
513 }
514
515 fn last_points(&self, text: &Text, cfg: PrintCfg) -> (Point, Option<Point>) {
516 let layouts = self.layouts.read();
517 let rect = get_rect(&layouts, self.id).unwrap();
518 let (height, width) = (rect.height(), rect.width());
519 let info = rect.print_info().unwrap();
520 let mut info = info.write();
521
522 if let Some(last) = info.last_points {
523 return last;
524 }
525
526 let line_start = text.visual_line_start(info.points);
527 let iter = text.iter_fwd(line_start);
528 let cfg = IterCfg::new(cfg);
529
530 let iter = print_iter(iter, cfg.wrap_width(width), cfg, info.points);
531 let mut points = info.points;
532 let mut y = 0;
533
534 for (Caret { wrap, .. }, Item { part, real, ghost }) in iter {
535 if wrap {
536 if y == height {
537 break;
538 }
539 if part.is_char() {
540 y += 1
541 }
542 } else {
543 points = (real, ghost);
544 }
545 }
546
547 info.last_points = Some(points);
548
549 points
550 }
551
552 fn is_active(&self) -> bool {
553 get_layout(&self.layouts.read(), self.id).unwrap().active_id == self.id
554 }
555}
556
557#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
561#[serde(crate = "duat_core::cache::serde")]
562pub struct PrintInfo {
563 points: (Point, Option<Point>),
566 x_shift: u32,
568 prev_main: Point,
570 last_points: Option<(Point, Option<Point>)>,
571}
572
573impl PrintInfo {
574 fn fix(&mut self, text: &Text) {
575 let max = text.len().min(self.points.0);
576 let (_, max_ghost) = text.ghost_max_points_at(max.byte());
577 self.points = (max, self.points.1.min(max_ghost))
578 }
579}
580
581fn scroll_ver_around(
584 mut info: PrintInfo,
585 width: u32,
586 height: u32,
587 point: Point,
588 text: &Text,
589 cfg: IterCfg,
590) -> PrintInfo {
591 let points = text.ghost_max_points_at(point.byte());
592 let after = text.points_after(points).unwrap_or(text.len_points());
593
594 let cap = cfg.wrap_width(width);
595 let mut iter = rev_print_iter(text.iter_rev(after), cap, cfg)
596 .filter_map(|(caret, item)| caret.wrap.then_some(item.points()));
597
598 let target = match info.prev_main > point {
599 true => cfg.scrolloff().y(),
600 false => height.saturating_sub(cfg.scrolloff().y() + 1),
601 };
602 let first = iter.nth(target as usize).unwrap_or_default();
603
604 if (info.prev_main > point && first <= info.points)
605 || (info.prev_main < point && first >= info.points)
606 {
607 info.points = first;
608 }
609 info
610}
611
612fn scroll_hor_around(
615 mut info: PrintInfo,
616 width: u32,
617 point: Point,
618 text: &Text,
619 cfg: IterCfg,
620) -> PrintInfo {
621 let cap = cfg.wrap_width(width);
622
623 let (max_shift, start, end) = {
624 let points = text.ghost_max_points_at(point.byte());
625 let after = text.points_after(points).unwrap_or(text.len_points());
626
627 let mut iter = rev_print_iter(text.iter_rev(after), cap, cfg);
628
629 let (points, start, end, wrap) = iter
630 .find_map(|(Caret { x, len, wrap }, item)| {
631 let points = item.points();
632 item.part.as_char().and(Some((points, x, x + len, wrap)))
633 })
634 .unwrap_or(((Point::default(), None), 0, 0, true));
635
636 let (line_len, align) = {
637 let mut align = Alignment::Left;
638 let (indent, points) = if wrap {
639 (start, points)
640 } else {
641 iter.find_map(|(caret, item)| caret.wrap.then_some((caret.x, item.points())))
642 .unwrap()
643 };
644
645 let len = print_iter_indented(text.iter_fwd(points), cap, cfg, indent)
646 .inspect(|(_, Item { part, .. })| match part {
647 Part::AlignLeft => align = Alignment::Left,
648 Part::AlignCenter => align = Alignment::Center,
649 Part::AlignRight => align = Alignment::Right,
650 _ => {}
651 })
652 .take_while(|(caret, item)| !caret.wrap || item.points() == points)
653 .last()
654 .map(|(Caret { x, len, .. }, _)| x + len)
655 .unwrap_or(0);
656
657 (len, align)
658 };
659
660 let diff = match align {
661 Alignment::Left => 0,
662 Alignment::Right => cap - line_len,
663 Alignment::Center => (cap - line_len) / 2,
664 };
665
666 (line_len + diff, start + diff, end + diff)
667 };
668
669 info.x_shift = info
670 .x_shift
671 .min(start.saturating_sub(cfg.scrolloff().x()))
672 .max(if cfg.forced_scrollof() {
673 (end + cfg.scrolloff().x()).saturating_sub(width)
674 } else {
675 (end + cfg.scrolloff().x())
676 .min(max_shift)
677 .saturating_sub(width)
678 });
679 info
680}
681
682fn get_rect(layouts: &[Layout], id: AreaId) -> Option<&Rect> {
683 layouts.iter().find_map(|l| l.get(id))
684}
685
686fn get_layout(layouts: &[Layout], id: AreaId) -> Option<&Layout> {
687 layouts.iter().find(|l| l.get(id).is_some())
688}
689
690fn get_layout_mut(layouts: &mut [Layout], id: AreaId) -> Option<&mut Layout> {
691 layouts.iter_mut().find(|l| l.get(id).is_some())
692}
693
694fn get_layout_pos(layouts: &[Layout], id: AreaId) -> Option<usize> {
695 layouts.iter().position(|l| l.get(id).is_some())
696}
697
698fn transfer_vars_and_recvs(from_p: &mut Printer, to_p: &mut Printer, rect: &Rect) {
699 let (vars, recv) = from_p.take_rect_parts(rect);
700 to_p.insert_rect_parts(vars, recv);
701
702 for (child, _) in rect.children().into_iter().flatten() {
703 transfer_vars_and_recvs(from_p, to_p, child)
704 }
705}