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