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