duat_core/ui/
window.rs

1//! The [`Window`]s of Duat
2//!
3//! In Duat, there is a [`Windows`] struct (accessible via
4//! [`context::windows`]), which holds [`Window`]s. Each `Window`
5//! represents a set of [`Widget`]s that should be displayed at the
6//! same time, like a browser tab.
7//!
8//! These [`Widget`]s will be contained in [`Node`]s, which are an
9//! anonymized version of [`Handle`]s, which the end user interacts
10//! with through the [`Pass`] struct, allowing for massively
11//! desynchronized global state accessibility.
12use std::{
13    any::type_name,
14    iter::Chain,
15    sync::{Arc, Mutex},
16};
17
18use super::{Node, Widget, layout::Layout};
19use crate::{
20    buffer::{Buffer, PathKind},
21    context::{self, Cache, Handle},
22    data::{Pass, RwData},
23    hook::{self, BufferClosed, WidgetCreated, WindowCreated},
24    mode,
25    opts::PrintOpts,
26    session::UiMouseEvent,
27    text::{SpawnId, Text, txt},
28    ui::{DynSpawnSpecs, PushSpecs, RwArea, Ui},
29};
30
31/// A list of all [`Window`]s in Duat
32pub struct Windows {
33    inner: RwData<InnerWindows>,
34    spawns_to_remove: Mutex<Vec<SpawnId>>,
35    ui: Ui,
36}
37
38/// Inner holder of [`Window`]s
39struct InnerWindows {
40    layout: Box<Mutex<dyn Layout>>,
41    list: Vec<Window>,
42    new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
43    cur_buffer: RwData<Handle>,
44    cur_widget: RwData<Node>,
45    cur_win: usize,
46    buffer_history: BufferHistory,
47}
48
49impl Windows {
50    /// Initializes the `Windows`, returning a [`Node`] for the first
51    /// [`Buffer`]
52    pub(crate) fn initialize(
53        pa: &mut Pass,
54        buffer: Buffer,
55        layout: Box<Mutex<dyn Layout>>,
56        ui: Ui,
57    ) {
58        let new_additions = Arc::new(Mutex::default());
59        let (window, node) = Window::new(0, pa, ui, buffer, new_additions.clone());
60
61        context::set_windows(Self {
62            inner: RwData::new(InnerWindows {
63                layout,
64                list: vec![window.clone()],
65                new_additions,
66                cur_buffer: RwData::new(node.try_downcast().unwrap()),
67                cur_widget: RwData::new(node.clone()),
68                cur_win: 0,
69                buffer_history: BufferHistory::default(),
70            }),
71            spawns_to_remove: Mutex::new(Vec::new()),
72            ui,
73        });
74
75        hook::trigger(
76            pa,
77            WidgetCreated(node.handle().try_downcast::<Buffer>().unwrap()),
78        );
79        hook::trigger(pa, WindowCreated(window));
80    }
81
82    ////////// Functions for new Widgets
83
84    /// Creates a new list of [`Window`]s, with a main one
85    /// initialiazed
86    pub(crate) fn new_window(&self, pa: &mut Pass, buffer: Buffer) -> Node {
87        let win = self.inner.read(pa).list.len();
88        let new_additions = self.inner.read(pa).new_additions.clone();
89        let (window, node) = Window::new(win, pa, self.ui, buffer, new_additions);
90
91        let inner = self.inner.write(pa);
92        inner.list.push(window);
93
94        hook::trigger(
95            pa,
96            WidgetCreated(node.handle().try_downcast::<Buffer>().unwrap()),
97        );
98        hook::trigger(pa, WindowCreated(self.inner.read(pa).list[win].clone()));
99
100        node
101    }
102
103    /// Push a [`Widget`] to [`Handle`]
104    pub(crate) fn push_widget<W: Widget>(
105        &self,
106        pa: &mut Pass,
107        (target, on_buffers, specs): (&RwArea, Option<bool>, PushSpecs),
108        widget: W,
109        master: Option<&RwArea>,
110    ) -> Option<Handle<W>> {
111        self.push(pa, (target, on_buffers, specs), widget, master)?
112            .handle()
113            .try_downcast()
114    }
115
116    /// Spawn a [`Widget`] on a [`Handle`]
117    ///
118    /// Can fail if the `Handle` in question was already removed.
119    pub(crate) fn spawn_on_widget<W: Widget>(
120        &self,
121        pa: &mut Pass,
122        (target, specs): (&RwArea, DynSpawnSpecs),
123        widget: W,
124    ) -> Option<Handle<W>> {
125        let (win, cluster_master, master) =
126            self.inner
127                .read(pa)
128                .list
129                .iter()
130                .enumerate()
131                .find_map(|(win, window)| {
132                    let inner = window.0.read(pa);
133                    let master = window.nodes(pa).find_map(|node| {
134                        node.area()
135                            .area_is_eq(pa, target)
136                            .then(|| node.handle().clone())
137                    });
138
139                    if inner.master_area.is_master_of(pa, target) {
140                        Some((win, None, master))
141                    } else if let Some((_, node)) = inner
142                        .spawned
143                        .iter()
144                        .find(|(_, node)| node.area().is_master_of(pa, target))
145                    {
146                        Some((win, node.area().get_cluster_master(pa), master))
147                    } else {
148                        None
149                    }
150                })?;
151
152        let widget = RwData::new(widget);
153        let id = SpawnId::new();
154
155        let path = widget
156            .read_as::<Buffer>(pa)
157            .and_then(|buffer| buffer.path_set());
158        let spawned = cluster_master.as_ref().unwrap_or(target).spawn(
159            pa,
160            path.as_ref().map(|p| p.as_ref()),
161            id,
162            specs,
163        )?;
164
165        let node = Node::new(widget, spawned, master);
166
167        let window = self.inner.write(pa).list.remove(win);
168        window.add(pa, node.clone(), None, Location::Spawned(id));
169        self.inner.write(pa).list.insert(win, window);
170
171        hook::trigger(
172            pa,
173            WidgetCreated(node.handle().try_downcast::<W>().unwrap()),
174        );
175
176        node.handle().try_downcast()
177    }
178
179    /// Spawns a [`Widget`]
180    pub(crate) fn spawn_on_text<W: Widget>(
181        &self,
182        pa: &mut Pass,
183        (id, specs): (SpawnId, DynSpawnSpecs),
184        widget: W,
185        win: usize,
186        master: Handle<dyn Widget>,
187    ) -> Handle<W> {
188        let widget = RwData::new(widget);
189        let path = widget
190            .read_as::<Buffer>(pa)
191            .and_then(|buffer| buffer.path_set());
192        let spawned = self
193            .ui
194            .new_spawned(path.as_ref().map(|p| p.as_ref()), id, specs, win);
195
196        let node = Node::new(widget, spawned, Some(master));
197
198        let window = self.inner.write(pa).list.remove(win);
199        window.add(pa, node.clone(), None, Location::Spawned(id));
200        self.inner.write(pa).list.insert(win, window);
201
202        hook::trigger(
203            pa,
204            WidgetCreated(node.handle().try_downcast::<W>().unwrap()),
205        );
206
207        node.handle().try_downcast().unwrap()
208    }
209
210    /// Pushes a [`Buffer`] to the buffer's parent
211    ///
212    /// This function will push to the edge of `self.buffers_parent`
213    /// This is an area, usually in the center, that contains all
214    /// [`Buffer`]s, and their associated [`Widget`]s,
215    /// with others being at the perifery of this area.
216    pub(crate) fn new_buffer(&self, pa: &mut Pass, buffer: Buffer) -> Node {
217        let inner = self.inner.read(pa);
218        let (handle, specs) = inner.layout.lock().unwrap().new_buffer(pa, &inner.list);
219
220        let specs = PushSpecs { cluster: false, ..specs };
221
222        if let Some(master) = handle.area().get_cluster_master(pa) {
223            self.push(pa, (&master, Some(true), specs), buffer, None)
224                .unwrap()
225        } else {
226            self.push(pa, (&handle.area, Some(true), specs), buffer, None)
227                .unwrap()
228        }
229    }
230
231    /// Pushes a [`Widget`] to the [`Window`]s
232    ///
233    /// May return [`None`] if the [`Area`] was already deleted.
234    fn push<W: Widget>(
235        &self,
236        pa: &mut Pass,
237        (target, on_buffers, mut specs): (&RwArea, Option<bool>, PushSpecs),
238        widget: W,
239        master: Option<&RwArea>,
240    ) -> Option<Node> {
241        let inner = self.inner.read(pa);
242        let win = inner
243            .list
244            .iter()
245            .position(|window| {
246                window.0.read(pa).master_area.is_master_of(pa, target)
247                    || window
248                        .nodes(pa)
249                        .any(|node| node.area().is_master_of(pa, target))
250            })
251            .unwrap();
252
253        let inner_window = inner.list[win].0.read(pa);
254        let target_is_on_buffers = inner_window.buffers_area.is_master_of(pa, target);
255
256        let on_buffers = on_buffers.unwrap_or(target_is_on_buffers) && target_is_on_buffers;
257
258        if target_is_on_buffers && !on_buffers {
259            specs.cluster = false;
260        }
261
262        let location = if on_buffers {
263            Location::OnBuffers
264        } else if let Some((id, _)) = inner_window
265            .spawned
266            .iter()
267            .find(|(_, node)| node.area().area_is_eq(pa, target))
268        {
269            Location::Spawned(*id)
270        } else {
271            Location::Regular
272        };
273
274        let widget = RwData::new(widget);
275        let path = widget
276            .read_as::<Buffer>(pa)
277            .and_then(|buffer| buffer.path_set());
278        let (pushed, parent) =
279            target.push(pa, path.as_ref().map(|p| p.as_ref()), specs, on_buffers)?;
280
281        let master = master.and_then(|area| {
282            self.entries(pa).find_map(|(.., node)| {
283                node.area()
284                    .area_is_eq(pa, area)
285                    .then(|| node.handle().clone())
286            })
287        });
288
289        let node = Node::new(widget, pushed, master);
290
291        let window = self.inner.write(pa).list.remove(win);
292        window.add(pa, node.clone(), parent, location);
293        self.inner.write(pa).list.insert(win, window);
294
295        hook::trigger(
296            pa,
297            WidgetCreated(node.handle().try_downcast::<W>().unwrap()),
298        );
299
300        Some(node)
301    }
302
303    ////////// Existing Widget manipulation
304
305    /// Closes a [`Handle`], removing it from the ui
306    pub(crate) fn close<W: Widget + ?Sized, S>(
307        &self,
308        pa: &mut Pass,
309        handle: &Handle<W, S>,
310    ) -> Result<(), Text> {
311        let win = self.handle_window(pa, handle)?;
312
313        // If it's a Buffer, swap all buffers ahead, so this one becomes the
314        // last.
315        if let Some(buf_handle) = handle.try_downcast::<Buffer>() {
316            hook::trigger(pa, BufferClosed((buf_handle.clone(), Cache::new())));
317
318            let buffers_ahead: Vec<Node> = self.inner.read(pa).list[win]
319                .nodes(pa)
320                .filter(|node| {
321                    node.handle().read_as::<Buffer>(pa).is_some_and(|buffer| {
322                        buffer.layout_order > buf_handle.read(pa).layout_order
323                    })
324                })
325                .cloned()
326                .collect();
327
328            for buffer_ahead in buffers_ahead {
329                self.swap(pa, handle, buffer_ahead.handle())?;
330            }
331        }
332
333        // Actually removing the Handle.
334        let mut list = std::mem::take(&mut self.inner.write(pa).list);
335
336        if list[win].close(pa, handle) {
337            list.remove(win);
338            self.ui.remove_window(win);
339            let cur_win = context::current_win_index(pa);
340            if cur_win > win {
341                self.inner.write(pa).cur_win -= 1;
342            }
343        }
344
345        let inner = self.inner.write(pa);
346        inner.list = list;
347        inner.new_additions.lock().unwrap().get_or_insert_default();
348
349        // If this is the active Handle, pick another one to make active.
350        let inner = self.inner.read(pa);
351        if handle == inner.cur_widget.read(pa).handle() || handle == inner.cur_buffer.read(pa) {
352            if let Some(handle) = handle.try_downcast::<Buffer>() {
353                self.inner.write(pa).buffer_history.remove(&handle);
354
355                let entry = self
356                    .inner
357                    .write(pa)
358                    .buffer_history
359                    .jump_by(handle.clone(), -1)
360                    .or_else(|| self.buffers(pa).next())
361                    .and_then(|handle| {
362                        self.entries(pa).find_map(|(win, node)| {
363                            (*node.handle() == handle).then(|| (win, node.clone()))
364                        })
365                    });
366
367                if let Some((_, node)) = entry {
368                    crate::mode::reset_to(node.handle().clone());
369                } else {
370                    // If there is no previous Buffer, just quit.
371                    context::sender()
372                        .send(crate::session::DuatEvent::Quit)
373                        .unwrap();
374                    return Ok(());
375                }
376            } else {
377                crate::mode::reset_to(inner.cur_buffer.read(pa).to_dyn());
378            }
379        }
380
381        Ok(())
382    }
383
384    /// Swaps two [`Handle`]'s positions
385    pub(crate) fn swap<W1: Widget + ?Sized, S1, W2: Widget + ?Sized, S2>(
386        &self,
387        pa: &mut Pass,
388        lhs: &Handle<W1, S1>,
389        rhs: &Handle<W2, S2>,
390    ) -> Result<(), Text> {
391        let lhs_win = self.handle_window(pa, lhs)?;
392        let rhs_win = self.handle_window(pa, rhs)?;
393
394        let [lhs_buffer, rhs_buffer] = [lhs.try_downcast::<Buffer>(), rhs.try_downcast()];
395
396        if let [Some(lhs), Some(rhs)] = [lhs_buffer, rhs_buffer] {
397            let lhs_lo = lhs.read(pa).layout_order;
398            let rhs_lo = std::mem::replace(&mut rhs.write(pa).layout_order, lhs_lo);
399            lhs.write(pa).layout_order = rhs_lo
400        }
401
402        let windows = std::mem::take(&mut self.inner.write(pa).list);
403
404        let lhs_nodes = windows[lhs_win].take_with_related_nodes(pa, lhs);
405        windows[rhs_win].insert_nodes(pa, lhs_nodes);
406
407        let rhs_nodes = windows[rhs_win].take_with_related_nodes(pa, rhs);
408        windows[lhs_win].insert_nodes(pa, rhs_nodes);
409
410        let wins = self.inner.write(pa);
411        wins.list = windows;
412        wins.new_additions.lock().unwrap().get_or_insert_default();
413
414        lhs.area().swap(pa, rhs.area());
415
416        let cur_buffer = context::current_buffer(pa);
417        if lhs_win != rhs_win {
418            if lhs == cur_buffer {
419                self.inner.write(pa).cur_win = lhs_win;
420                self.ui.switch_window(lhs_win);
421            } else if rhs == cur_buffer {
422                self.inner.write(pa).cur_win = rhs_win;
423                self.ui.switch_window(rhs_win);
424            }
425        }
426
427        Ok(())
428    }
429
430    /// Opens a new [`Buffer`] on a new [`Window`], or moves it there,
431    /// if it is already open
432    pub(crate) fn open_or_move_to_new_window(
433        &self,
434        pa: &mut Pass,
435        pk: PathKind,
436        default_buffer_cfg: PrintOpts,
437    ) -> Node {
438        let node = match self.buffer_entry(pa, pk.clone()) {
439            Ok((win, handle)) if self.get(pa, win).unwrap().buffers(pa).len() > 1 => {
440                // Take the nodes in the original Window
441                handle.write(pa).layout_order = 0;
442
443                let nodes = {
444                    let old_window = self.inner.write(pa).list.remove(win);
445                    let nodes = old_window.take_with_related_nodes(pa, &handle.to_dyn());
446                    self.inner.write(pa).list.insert(win, old_window);
447
448                    nodes
449                };
450
451                // Create a new Window Swapping the new root with buffers_area
452                let path = handle.read(pa).path_set();
453                let new_root = self.ui.new_root(path.as_ref().map(|p| p.as_ref()));
454                handle.area().swap(pa, &new_root);
455                let window = Window::new_from_raw(
456                    pa,
457                    win,
458                    handle.area.clone(),
459                    nodes,
460                    self.inner.read(pa).new_additions.clone(),
461                );
462
463                self.inner.write(pa).list.push(window.clone());
464
465                hook::trigger(pa, WindowCreated(window));
466
467                // Swap the Buffers ahead of the swapped new_root
468                let lo = handle.read(pa).layout_order;
469
470                for handle in &self.inner.read(pa).list[win].buffers(pa)[lo..] {
471                    new_root.swap(pa, handle.area());
472                }
473
474                // Delete the new_root, which should be the last "Buffer" in the
475                // list of the original Window.
476                new_root.delete(pa);
477
478                self.inner
479                    .write(pa)
480                    .new_additions
481                    .lock()
482                    .unwrap()
483                    .get_or_insert_default();
484
485                Node::from_handle(handle)
486            }
487            // The Handle in question is already in its own window, so no need
488            // to move it to another one.
489            Ok((.., handle)) => Node::from_handle(handle),
490            Err(_) => self.new_window(pa, Buffer::new(pk.as_path(), default_buffer_cfg)),
491        };
492
493        if context::current_buffer(pa).read(pa).path_kind() != pk {
494            mode::reset_to(node.handle().clone());
495        }
496
497        node
498    }
499
500    /// Sets the current active [`Handle`]
501    pub(crate) fn set_current_node(&self, pa: &mut Pass, node: Node) -> Result<(), Text> {
502        // SAFETY: This Pass is only used when I'm already reborrowing a &mut
503        // Pass, and it is known that it only writes to other types.
504        let internal_pass = &mut unsafe { Pass::new() };
505
506        let win = self.handle_window(pa, node.handle())?;
507        let inner = self.inner.write(pa);
508
509        if let Some(handle) = node.try_downcast::<Buffer>() {
510            let current = std::mem::replace(inner.cur_buffer.write(internal_pass), handle.clone());
511            inner.buffer_history.insert(current, handle);
512        }
513        *inner.cur_widget.write(internal_pass) = node.clone();
514        inner.cur_win = win;
515        self.ui.switch_window(win);
516
517        Ok(())
518    }
519
520    ////////// Spawned Widget cleanup
521
522    /// Adds a [`SpawnId`] to be removed when a [`Pass`] is available
523    pub(crate) fn queue_close_spawned(&self, id: SpawnId) {
524        let mut spawns_to_remove = self.spawns_to_remove.lock().unwrap();
525        if !spawns_to_remove.contains(&id) {
526            spawns_to_remove.push(id)
527        }
528    }
529
530    /// Removes all [`SpawnId`]'s [`Widget`]s which were queued for
531    /// closure
532    pub(crate) fn cleanup_despawned(&self, pa: &mut Pass) {
533        let spawns_to_remove = std::mem::take(&mut *self.spawns_to_remove.lock().unwrap());
534        for id in spawns_to_remove {
535            if let Some((_, node)) = self
536                .iter(pa)
537                .flat_map(|window| &window.0.read(pa).spawned)
538                .find(|(other, _)| *other == id)
539            {
540                self.close(pa, &node.handle().clone()).unwrap();
541            }
542        }
543    }
544
545    ////////// Entry lookup
546
547    /// An entry for a [`Handle`]
548    pub(crate) fn handle_window<W: Widget + ?Sized, S>(
549        &self,
550        pa: &Pass,
551        handle: &Handle<W, S>,
552    ) -> Result<usize, Text> {
553        self.entries(pa)
554            .find_map(|(win, node)| (node.handle() == handle).then_some(win))
555            .ok_or_else(|| txt!("The Handle was already closed"))
556    }
557
558    /// An entry for a buffer with the given name
559    pub(crate) fn buffer_entry(&self, pa: &Pass, pk: PathKind) -> Result<(usize, Handle), Text> {
560        self.entries(pa)
561            .find_map(|(win, node)| {
562                (node.read_as(pa).filter(|f: &&Buffer| f.path_kind() == pk))
563                    .and_then(|_| node.try_downcast().map(|handle| (win, handle)))
564            })
565            .ok_or_else(|| txt!("Buffer {pk} not found"))
566    }
567
568    /// An entry for a buffer with the given name
569    pub(crate) fn named_buffer_entry(
570        &self,
571        pa: &Pass,
572        name: &str,
573    ) -> Result<(usize, Handle), Text> {
574        self.entries(pa)
575            .find_map(|(win, node)| {
576                (node.read_as(pa).filter(|f: &&Buffer| f.name() == name))
577                    .and_then(|_| node.try_downcast().map(|handle| (win, handle)))
578            })
579            .ok_or_else(|| txt!("Buffer [buffer]{name}[] not found"))
580    }
581
582    /// An entry for a widget of a specific type
583    ///
584    /// Returns the index of the window, the index of the [`Widget`],
585    /// and the [`Widget`]'s [`Node`]
586    pub(crate) fn node_of<'a, W: Widget>(&'a self, pa: &'a Pass) -> Result<&'a Node, Text> {
587        let handle = context::current_buffer(pa);
588
589        if let Some((handle, _)) = handle.get_related::<W>(pa).next() {
590            self.entries(pa)
591                .find_map(|(.., node)| node.ptr_eq(handle.widget()).then_some(node))
592        } else {
593            let cur_win = self.inner.read(pa).cur_win;
594            let list = &self.inner.read(pa).list;
595            list[cur_win]
596                .nodes(pa)
597                .chain(list[cur_win + 1..].iter().flat_map(|win| win.nodes(pa)))
598                .chain(list[..cur_win].iter().flat_map(|win| win.nodes(pa)))
599                .find(|node| node.data_is::<W>())
600        }
601        .ok_or(txt!("No widget of type [a]{}[] found", type_name::<W>()))
602    }
603
604    ////////// Entry iterators
605
606    /// Iterates over all widget entries, with window indices
607    pub(crate) fn entries<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = (usize, &'a Node)> {
608        self.inner
609            .read(pa)
610            .list
611            .iter()
612            .enumerate()
613            .flat_map(|(win, window)| {
614                let inner = window.0.read(pa);
615                inner
616                    .nodes
617                    .iter()
618                    .chain(inner.spawned.iter().map(|(_, node)| node))
619                    .map(move |node| (win, node))
620            })
621    }
622
623    /// Iterates around a specific widget, going forwards
624    pub(crate) fn iter_around<'a>(
625        &'a self,
626        pa: &'a Pass,
627        win: usize,
628        wid: usize,
629    ) -> impl Iterator<Item = (usize, &'a Node)> + 'a {
630        let window_entries =
631            |(w, window): (usize, &'a Window)| window.nodes(pa).map(move |node| (w, node));
632
633        let windows = &self.inner.read(pa).list;
634
635        let prev_len: usize = windows
636            .iter()
637            .take(win)
638            .map(|win| win.len_widgets(pa))
639            .sum();
640
641        windows
642            .iter()
643            .enumerate()
644            .skip(win)
645            .flat_map(window_entries)
646            .skip(wid + 1)
647            .chain(
648                windows
649                    .iter()
650                    .enumerate()
651                    .take(win + 1)
652                    .flat_map(window_entries)
653                    .take(prev_len + wid),
654            )
655    }
656
657    /// Iterates around a specific widget, going backwards
658    pub(crate) fn iter_around_rev<'a>(
659        &'a self,
660        pa: &'a Pass,
661        win: usize,
662        wid: usize,
663    ) -> impl Iterator<Item = (usize, &'a Node)> + 'a {
664        let entries =
665            |(w, window): (usize, &'a Window)| window.nodes(pa).map(move |node| (w, node));
666
667        let windows = &self.inner.read(pa).list;
668
669        let next_len: usize = windows
670            .iter()
671            .skip(win)
672            .map(|win| win.len_widgets(pa))
673            .sum();
674
675        windows
676            .iter()
677            .enumerate()
678            .rev()
679            .skip(windows.len() - (win + 1))
680            .flat_map(move |(w, win)| entries((w, win)).rev().skip(win.len_widgets(pa) - wid))
681            .chain(
682                windows
683                    .iter()
684                    .enumerate()
685                    .rev()
686                    .take(windows.len() - win)
687                    .flat_map(move |(i, win)| entries((i, win)).rev())
688                    .take(next_len - (wid + 1)),
689            )
690    }
691
692    ////////// Buffer switching
693
694    /// Jumps around in the buffer history
695    ///
696    /// This will jump forwards if `number` is positive, backwards
697    /// otherwise.
698    pub fn jump_buffers_by(&self, pa: &mut Pass, jumps: i32) {
699        let current = self.inner.read(pa).cur_buffer.read(pa).clone();
700        if let Some(handle) = self.inner.write(pa).buffer_history.jump_by(current, jumps) {
701            mode::reset_to(handle.to_dyn());
702        } else {
703            context::warn!("No buffer [a]{jumps}[] jumps away from the current one");
704        }
705    }
706
707    /// Jumps to the last buffer
708    ///
709    /// Calling this repeatedly
710    pub fn last_buffer(&self, pa: &mut Pass) -> Result<Handle, Text> {
711        let current = self.inner.read(pa).cur_buffer.read(pa).clone();
712        if let Some(handle) = self.inner.write(pa).buffer_history.last(current) {
713            mode::reset_to(handle.to_dyn());
714            Ok(handle)
715        } else {
716            Err(txt!("No last buffer"))
717        }
718    }
719
720    ////////// Querying functions
721
722    /// The number of open [`Window`]s
723    ///
724    /// Should never be 0, as that is not a valid state of affairs.
725    pub fn len(&self, pa: &Pass) -> usize {
726        self.inner.read(pa).list.len()
727    }
728
729    /// get's the `win`th [`Window`]
730    pub fn get<'a>(&'a self, pa: &'a Pass, win: usize) -> Option<&'a Window> {
731        self.inner.read(pa).list.get(win)
732    }
733
734    /// Iterates through every [`Window`]
735    pub fn iter<'a>(&'a self, pa: &'a Pass) -> std::slice::Iter<'a, Window> {
736        self.inner.read(pa).list.iter()
737    }
738
739    /// Returns an [`Iterator`] over the [`Handle`]s of Duat
740    pub fn handles<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = &'a Handle<dyn Widget>> {
741        self.inner
742            .read(pa)
743            .list
744            .iter()
745            .flat_map(|w| w.nodes(pa).map(|n| n.handle()))
746    }
747
748    /// Returns an [`Iterator`] over the [`Handle`]s of Duat
749    pub fn handles_of<'a, W: Widget>(
750        &'a self,
751        pa: &'a Pass,
752    ) -> impl Iterator<Item = Handle<W>> + 'a {
753        self.inner
754            .read(pa)
755            .list
756            .iter()
757            .flat_map(|w| w.nodes(pa).filter_map(|n| n.handle().try_downcast()))
758    }
759
760    /// Iterates over all [`Handle<Buffer>`]s in Duat
761    pub fn buffers<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = Handle> + 'a {
762        self.inner.read(pa).list.iter().flat_map(|w| w.buffers(pa))
763    }
764
765    /// The index of the currently active [`Window`]
766    pub fn current_window(&self, pa: &Pass) -> usize {
767        self.inner.read(pa).cur_win
768    }
769
770    /// The [`RwData`] that points to the currently active [`Buffer`]
771    pub(crate) fn current_buffer<'a>(&'a self, pa: &'a Pass) -> &'a RwData<Handle> {
772        &self.inner.read(pa).cur_buffer
773    }
774
775    /// The [`RwData`] that points to the currently active [`Widget`]
776    pub(crate) fn current_widget<'a>(&'a self, pa: &'a Pass) -> &'a RwData<Node> {
777        &self.inner.read(pa).cur_widget
778    }
779
780    /// Gets the new additions to the [`Windows`]
781    pub(crate) fn get_additions(&self, pa: &mut Pass) -> Option<Vec<(usize, Node)>> {
782        self.inner.write(pa).new_additions.lock().unwrap().take()
783    }
784}
785
786/// A region containing [`Handle`]s
787///
788/// This is like a browser tab, it can contain any number of regular
789/// and spawned [`Handle`]s.
790#[derive(Clone)]
791pub struct Window(RwData<InnerWindow>);
792
793struct InnerWindow {
794    index: usize,
795    nodes: Vec<Node>,
796    spawned: Vec<(SpawnId, Node)>,
797    buffers_area: RwArea,
798    master_area: RwArea,
799    new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
800}
801
802impl Window {
803    /// Returns a new instance of [`Window`]
804    fn new<W: Widget>(
805        index: usize,
806        pa: &mut Pass,
807        ui: Ui,
808        widget: W,
809        new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
810    ) -> (Self, Node) {
811        let widget = RwData::new(widget);
812        let path = if let Some(buffer) = widget.write_as::<Buffer>(pa) {
813            buffer.layout_order = get_layout_order();
814            buffer.path_set()
815        } else {
816            None
817        };
818
819        let area = ui.new_root(path.as_ref().map(|p| p.as_ref()));
820        let node = Node::new::<W>(widget, area.clone(), None);
821
822        new_additions
823            .lock()
824            .unwrap()
825            .get_or_insert_default()
826            .push((index, node.clone()));
827
828        let window = Self(RwData::new(InnerWindow {
829            index,
830            nodes: vec![node.clone()],
831            spawned: Vec::new(),
832            buffers_area: area.clone(),
833            master_area: area.clone(),
834            new_additions,
835        }));
836
837        (window, node)
838    }
839
840    /// Returns a new [`Window`] from raw elements
841    pub(crate) fn new_from_raw(
842        pa: &mut Pass,
843        index: usize,
844        master_area: RwArea,
845        nodes: Vec<Node>,
846        new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
847    ) -> Self {
848        let master_area = master_area
849            .get_cluster_master(pa)
850            .unwrap_or(master_area.clone());
851
852        Self(RwData::new(InnerWindow {
853            index,
854            nodes,
855            spawned: Vec::new(),
856            buffers_area: master_area.clone(),
857            master_area,
858            new_additions,
859        }))
860    }
861
862    ////////// Widget addition/removal
863
864    /// Pushes a widget to the "buffer area" of a `Window`
865    ///
866    /// If this [`Widget`] is being pushed to a [`Buffer`]'s group,
867    /// then this `Widget` will be included in that `Buffer`'s
868    /// group. This means that, if that `Buffer` is moved around
869    /// or deleted, this `Widget` (and all others in its group)
870    /// will follow suit.
871    ///
872    /// When you push a `Widget`, it is placed on an edge of the
873    /// area, and a new parent area may be created to hold both
874    /// widgets. If created, that new area will be used for pushing
875    /// widgets in the future.
876    ///
877    /// This means that, if you push widget *A* to the left, then you
878    /// push widget *B* to the bottom, you will get this layout:
879    ///
880    /// ```text
881    /// ╭───┬──────────╮
882    /// │   │          │
883    /// │ A │  Buffer  │
884    /// │   │          │
885    /// ├───┴──────────┤
886    /// │      B       │
887    /// ╰──────────────╯
888    /// ```
889    ///
890    /// Here's an example of such a layout:
891    ///
892    /// ```rust
893    /// # duat_core::doc_duat!(duat);
894    /// setup_duat!(setup);
895    /// use duat::prelude::*;
896    ///
897    /// fn setup() {
898    ///     hook::remove("BufferWidgets");
899    ///     hook::add::<Buffer>(|pa, handle| {
900    ///         LineNumbers::builder().push_on(pa, handle);
901    ///         status!("{name_txt} {selections_txt} {main_txt}").push_on(pa, handle);
902    ///         Ok(())
903    ///     });
904    /// }
905    /// ```
906    ///
907    /// In this case, each buffer will have [`LineNumbers`] with
908    /// relative/absolute numbering, and a [`StatusLine`] showing
909    /// the buffer's name, how many selections are in it, and its main
910    /// selection.
911    ///
912    /// [`Buffer`]: crate::buffer::Buffer
913    /// [`LineNumbers`]: https://docs.rs/duat/latest/duat/widgets/struct.LineNumbers.html
914    /// [`StatusLine`]: https://docs.rs/duat/latest/duat/widgets/struct.StatusLine.html
915    /// [`WindowCreated`]: crate::hook::WindowCreated
916    pub fn push_inner<W: Widget>(
917        &self,
918        pa: &mut Pass,
919        widget: W,
920        mut specs: PushSpecs,
921    ) -> Handle<W> {
922        let target = self.0.read(pa).buffers_area.clone();
923
924        specs.cluster = false;
925
926        context::windows()
927            .push_widget(pa, (&target, Some(false), specs), widget, None)
928            .unwrap()
929    }
930
931    /// Docs: TODO
932    pub fn push_outer<W: Widget>(
933        &self,
934        pa: &mut Pass,
935        widget: W,
936        mut specs: PushSpecs,
937    ) -> Handle<W> {
938        let target = self.0.read(pa).master_area.clone();
939
940        specs.cluster = false;
941
942        context::windows()
943            .push_widget(pa, (&target, Some(false), specs), widget, None)
944            .unwrap()
945    }
946
947    /// Adds a [`Widget`] to the list of widgets of this [`Window`]
948    fn add(&self, pa: &mut Pass, node: Node, parent: Option<RwArea>, location: Location) {
949        match location {
950            Location::OnBuffers => {
951                self.0.write(pa).nodes.push(node.clone());
952                if let Some(parent) = &parent
953                    && parent.is_master_of(pa, &self.0.read(pa).buffers_area)
954                {
955                    self.0.write(pa).buffers_area = parent.clone()
956                }
957            }
958            Location::Regular => self.0.write(pa).nodes.push(node.clone()),
959            Location::Spawned(id) => self.0.write(pa).spawned.push((id, node.clone())),
960        }
961
962        if let Some(parent) = &parent
963            && parent.is_master_of(pa, &self.0.read(pa).master_area)
964        {
965            self.0.write(pa).master_area = parent.clone()
966        }
967
968        let inner = self.0.write(pa);
969        inner
970            .new_additions
971            .lock()
972            .unwrap()
973            .get_or_insert_default()
974            .push((inner.index, node.clone()));
975    }
976
977    /// Closes the [`Handle`] and all related ones
978    ///
979    /// Returns `true` if this `Window` is supposed to be removed.
980    fn close<W: Widget + ?Sized, S>(&self, pa: &mut Pass, handle: &Handle<W, S>) -> bool {
981        let handle_eq = |node: &mut Node| node.handle() == handle;
982
983        let inner = self.0.write(pa);
984
985        let node = if let Some(node) = inner.nodes.extract_if(.., handle_eq).next() {
986            node
987        } else if let Some((_, node)) = inner.spawned.extract_if(.., |(_, n)| handle_eq(n)).next() {
988            node
989        } else {
990            unreachable!("This isn't supposed to fail");
991        };
992
993        node.handle().declare_closed(pa);
994
995        let (do_rm_window, rm_areas) = node.area().delete(pa);
996        if do_rm_window {
997            for handle in self.handles(pa).cloned().collect::<Vec<_>>() {
998                handle.declare_closed(pa);
999            }
1000            return true;
1001        }
1002
1003        let (mut nodes, mut spawned) = {
1004            let inner = self.0.write(pa);
1005            let nodes = std::mem::take(&mut inner.nodes);
1006            let spawned = std::mem::take(&mut inner.spawned);
1007            (nodes, spawned)
1008        };
1009
1010        nodes.retain(|node| {
1011            if rm_areas
1012                .iter()
1013                .any(|a| a.area_is_eq(pa, node.handle().area()))
1014            {
1015                node.handle().declare_closed(pa);
1016                false
1017            } else {
1018                true
1019            }
1020        });
1021        spawned.retain(|(_, node)| {
1022            if rm_areas
1023                .iter()
1024                .any(|a| a.area_is_eq(pa, node.handle().area()))
1025            {
1026                node.handle().declare_closed(pa);
1027                false
1028            } else {
1029                true
1030            }
1031        });
1032
1033        let inner = self.0.write(pa);
1034        inner.nodes = nodes;
1035        inner.spawned = spawned;
1036
1037        let buffers = self.buffers(pa);
1038        if buffers.len() == 1 {
1039            let handle = buffers.first().unwrap();
1040
1041            let master_area = handle
1042                .area()
1043                .get_cluster_master(pa)
1044                .unwrap_or(handle.area.clone());
1045
1046            self.0.write(pa).buffers_area = master_area;
1047        }
1048
1049        if self.buffers(pa).is_empty() {
1050            for handle in self.handles(pa).cloned().collect::<Vec<_>>() {
1051                handle.declare_closed(pa);
1052            }
1053            true
1054        } else {
1055            false
1056        }
1057    }
1058
1059    /// Takes all [`Node`]s related to a given [`Node`]
1060    fn take_with_related_nodes<W: Widget + ?Sized, S>(
1061        &self,
1062        pa: &mut Pass,
1063        handle: &Handle<W, S>,
1064    ) -> Vec<Node> {
1065        let related = handle.related();
1066
1067        let (related, inner) = pa.read_and_write(related, &self.0);
1068
1069        inner
1070            .nodes
1071            .extract_if(.., |node| {
1072                related.iter().any(|(handle, _)| handle == node.handle()) || node.handle() == handle
1073            })
1074            .collect()
1075    }
1076
1077    /// Inserts [`Buffer`] nodes orderly
1078    fn insert_nodes(&self, pa: &mut Pass, nodes: Vec<Node>) {
1079        self.0.write(pa).nodes.extend(nodes);
1080    }
1081
1082    ////////// Querying functions
1083
1084    /// An [`Iterator`] over the [`Node`]s in a [`Window`]
1085    pub(crate) fn nodes<'a>(&'a self, pa: &'a Pass) -> Nodes<'a> {
1086        let inner = self.0.read(pa);
1087
1088        let spawned = SpawnedNodes { iter: inner.spawned.iter() };
1089
1090        Nodes {
1091            iter: inner.nodes.iter().chain(spawned),
1092            len: inner.nodes.len() + inner.spawned.len(),
1093            taken: 0,
1094        }
1095    }
1096
1097    /// An [`Iterator`] over all [`Handle`]s in a `Window`
1098    ///
1099    /// Each `Handle` takes care of one [`Widget`], if you want to see
1100    /// which one exactly is being used, you can use the
1101    /// [`Handle::try_downcast`] and [`Handle::read_as`] methods.
1102    ///
1103    /// If you just want an iterator over the [`Buffer`]s, then check
1104    /// out [`Window::buffers`].
1105    pub fn handles<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = &'a Handle<dyn Widget>> {
1106        self.nodes(pa).map(|node| node.handle())
1107    }
1108
1109    /// The [`Buffer`]s in a single `Window`
1110    ///
1111    /// They will be ordered by where the `"next-buffer"` [command]
1112    /// focus on. This usually follows the order by which they were
1113    /// created, but it can be altered if you use the `"swap"`
1114    /// command.
1115    ///
1116    /// If you want an [`Iterator`] over all [`Handle`]s, see
1117    /// [`Window::handles`].
1118    ///
1119    /// [command]: crate::cmd
1120    pub fn buffers(&self, pa: &Pass) -> Vec<Handle> {
1121        let inner = self.0.read(pa);
1122        let mut buffers: Vec<Handle> = inner
1123            .nodes
1124            .iter()
1125            .filter_map(|node| node.try_downcast())
1126            .collect();
1127
1128        buffers.sort_unstable_by_key(|buffer| buffer.read(pa).layout_order);
1129
1130        buffers.extend(
1131            inner
1132                .spawned
1133                .iter()
1134                .filter_map(|(_, node)| node.try_downcast()),
1135        );
1136
1137        buffers
1138    }
1139
1140    pub(crate) fn send_mouse_event(&self, pa: &mut Pass, mouse_event: UiMouseEvent) {
1141        let inner = self.0.read(pa);
1142        let node = inner
1143            .spawned
1144            .iter()
1145            .rev()
1146            .map(|(_, node)| node)
1147            .chain(&inner.nodes)
1148            .find(|node| {
1149                let tl = node.handle().area().top_left(pa);
1150                let br = node.handle().area().bottom_right(pa);
1151                (tl.x <= mouse_event.coord.x && tl.y <= mouse_event.coord.y)
1152                    && (mouse_event.coord.x < br.x && mouse_event.coord.y < br.y)
1153            })
1154            .cloned();
1155
1156        if let Some(node) = node {
1157            node.on_mouse_event(pa, mouse_event);
1158        }
1159    }
1160
1161    /// How many [`Widget`]s are in this [`Window`]
1162    pub(crate) fn len_widgets(&self, pa: &Pass) -> usize {
1163        let inner = self.0.read(pa);
1164        inner.nodes.len() + inner.spawned.len()
1165    }
1166}
1167
1168#[derive(Default)]
1169struct BufferHistory {
1170    current_i: usize,
1171    list: Vec<Handle>,
1172    last: Option<Handle>,
1173}
1174
1175impl BufferHistory {
1176    /// Returns the previous [`Handle`], if there is one
1177    fn jump_by(&mut self, current: Handle, by: i32) -> Option<Handle> {
1178        let new_i = self
1179            .current_i
1180            .saturating_add_signed(by as isize)
1181            .min(self.list.len());
1182        let new_handle = self.list.get(new_i)?.clone();
1183
1184        self.last = Some(current);
1185        self.current_i = new_i;
1186        Some(new_handle)
1187    }
1188
1189    /// Returns the last [`Handle`]
1190    ///
1191    /// Repeatedly calling this function will return the same two
1192    /// [`Handle`]s.
1193    fn last(&mut self, current: Handle) -> Option<Handle> {
1194        if let Some(last) = self.last.as_mut() {
1195            Some(std::mem::replace(last, current))
1196        } else if let Some(last) = self.list.get(self.current_i.checked_sub(1)?) {
1197            self.last = Some(current);
1198            Some(last.clone())
1199        } else {
1200            None
1201        }
1202    }
1203
1204    /// Inserts a new entry, but only if it is different from both of
1205    /// the surrounding entries
1206    fn insert(&mut self, current: Handle, handle: Handle) {
1207        if self
1208            .current_i
1209            .checked_sub(1)
1210            .is_none_or(|prev_i| self.list[prev_i] != handle)
1211            && self
1212                .list
1213                .get(self.current_i)
1214                .is_none_or(|other| *other != handle)
1215        {
1216            self.list.insert(self.current_i, handle);
1217            self.last = Some(current);
1218            self.current_i += 1;
1219        }
1220    }
1221
1222    /// Clears all instances of a given [`Handle`], signaling that it
1223    /// has been closed
1224    fn remove(&mut self, handle: &Handle) {
1225        let mut i = 0;
1226        self.list.retain(|other| {
1227            if other == handle {
1228                if i < self.current_i {
1229                    self.current_i -= 1;
1230                }
1231                false
1232            } else {
1233                i += 1;
1234                true
1235            }
1236        });
1237    }
1238}
1239
1240/// Returns a new layout order, which will be different from every
1241/// other
1242fn get_layout_order() -> usize {
1243    use std::sync::atomic::{AtomicUsize, Ordering};
1244
1245    static LAYOUT_ORDER: AtomicUsize = AtomicUsize::new(0);
1246    LAYOUT_ORDER.fetch_add(1, Ordering::Relaxed)
1247}
1248
1249enum Location {
1250    OnBuffers,
1251    Regular,
1252    Spawned(SpawnId),
1253}
1254
1255#[derive(Debug, Clone)]
1256pub(crate) struct Nodes<'a> {
1257    iter: Chain<std::slice::Iter<'a, Node>, SpawnedNodes<'a>>,
1258    len: usize,
1259    taken: usize,
1260}
1261
1262impl<'a> Iterator for Nodes<'a> {
1263    type Item = &'a Node;
1264
1265    fn next(&mut self) -> Option<Self::Item> {
1266        let next = self.iter.next();
1267        self.taken += next.is_some() as usize;
1268        next
1269    }
1270
1271    fn size_hint(&self) -> (usize, Option<usize>) {
1272        (self.len - self.taken, Some(self.len - self.taken))
1273    }
1274}
1275
1276impl<'a> DoubleEndedIterator for Nodes<'a> {
1277    fn next_back(&mut self) -> Option<Self::Item> {
1278        let next = self.iter.next_back();
1279        self.taken += next.is_some() as usize;
1280        next
1281    }
1282}
1283
1284impl ExactSizeIterator for Nodes<'_> {}
1285
1286#[derive(Debug, Clone)]
1287struct SpawnedNodes<'a> {
1288    iter: std::slice::Iter<'a, (SpawnId, Node)>,
1289}
1290
1291impl<'a> Iterator for SpawnedNodes<'a> {
1292    type Item = &'a Node;
1293
1294    fn next(&mut self) -> Option<Self::Item> {
1295        self.iter.next().map(|(_, node)| node)
1296    }
1297}
1298
1299impl DoubleEndedIterator for SpawnedNodes<'_> {
1300    fn next_back(&mut self) -> Option<Self::Item> {
1301        self.iter.next_back().map(|(_, node)| node)
1302    }
1303}