duat_core/context/
mod.rs

1//! Access to widgets and other other parts of the state of Duat
2//!
3//! This module lets you access and mutate some things:
4//!
5//! # Buffers
6use std::any::TypeId;
7
8pub use self::{cache::*, global::*, handles::*, log::*};
9use crate::{
10    buffer::Buffer,
11    data::{Pass, RwData},
12    ui::{Area, Node, Widget},
13};
14
15mod cache;
16mod handles;
17mod log;
18
19mod global {
20    use std::{
21        path::PathBuf,
22        sync::{
23            LazyLock, Mutex, OnceLock,
24            atomic::{AtomicBool, Ordering},
25            mpsc,
26        },
27    };
28
29    use super::{CurWidgetNode, DynBuffer};
30    use crate::{
31        context::Handle,
32        data::{DataMap, Pass, RwData},
33        session::DuatEvent,
34        text::Text,
35        ui::{Widget, Window, Windows},
36    };
37
38    static WINDOWS: OnceLock<&Windows> = OnceLock::new();
39    static MODE_NAME: LazyLock<RwData<&str>> = LazyLock::new(RwData::default);
40
41    static WILL_RELOAD_OR_QUIT: AtomicBool = AtomicBool::new(false);
42    static CUR_DIR: OnceLock<Mutex<PathBuf>> = OnceLock::new();
43    static SENDER: OnceLock<mpsc::Sender<DuatEvent>> = OnceLock::new();
44
45    /// Queues a function to be done on the main thread with a
46    /// [`Pass`]
47    ///
48    /// You can use this whenever you don't have access to a `Pass`,
49    /// in order to execute an action on the main thread, gaining
50    /// access to Duat's global state within that function.
51    pub fn queue(f: impl FnOnce(&mut Pass) + Send + 'static) {
52        sender()
53            .send(DuatEvent::QueuedFunction(Box::new(f)))
54            .unwrap();
55    }
56
57    ////////// Internal setters meant to be called once
58
59    /// Attempts to set the current [`Handle`]
60    ///
61    /// Fails if said [`Handle`] was already deleted.
62    pub(crate) fn set_current_node(pa: &mut Pass, node: crate::ui::Node) {
63        if let Err(err) = windows().set_current_node(pa, node) {
64            super::warn!("{err}");
65        }
66    }
67
68    /// Sets the [`Window`]s for Duat
69    pub(crate) fn set_windows(windows: Windows) {
70        if WINDOWS.set(Box::leak(Box::new(windows))).is_err() {
71            panic!("Setup ran twice");
72        }
73    }
74
75    /// Orders to quit Duat
76    pub(crate) fn order_reload_or_quit() {
77        WILL_RELOAD_OR_QUIT.store(true, Ordering::Relaxed);
78    }
79
80    /// Sets the sender for [`DuatEvent`]s
81    ///
82    /// ONLY MEANT TO BE USED BY THE DUAT EXECUTABLE
83    #[doc(hidden)]
84    pub fn set_sender(sender: mpsc::Sender<DuatEvent>) {
85        SENDER.set(sender).expect("setup ran twice");
86    }
87
88    ////////// Widget Handle getters
89
90    /// Returns a "fixed" [`Handle`] for the currently active
91    /// [`Buffer`]
92    ///
93    /// This `Handle` will always point to the same `Buffer`,
94    /// even when it is not active. If you want a `Handle` that
95    /// always points to the current Buffer, see dyn_buffer
96    ///
97    /// [`Buffer`]: crate::buffer::Buffer
98    pub fn current_buffer(pa: &Pass) -> &Handle {
99        windows().current_buffer(pa).read(pa)
100    }
101
102    /// Returns a "dynamic" [`Handle`] for the active [`Buffer`]
103    ///
104    /// This `Handle` will change to point to the current `Buffer`,
105    /// whenever the user swicthes which `Buffer` is active. If you
106    /// want a `Handle` that will stay on the current `Buffer`, see
107    /// [`current_buffer`].
108    ///
109    /// [`Buffer`]: crate::buffer::Buffer
110    pub fn dynamic_buffer(pa: &Pass) -> DynBuffer {
111        let dyn_buffer = windows().current_buffer(pa).clone();
112        let cur_buffer = RwData::new(dyn_buffer.read(pa).clone());
113        DynBuffer {
114            cur_buffer: dyn_buffer,
115            saved_buffer: cur_buffer,
116        }
117    }
118
119    /// Returns a [`Handle`] for a [`Buffer`] with the given name
120    ///
121    /// [`Buffer`]: crate::buffer::Buffer
122    pub fn get_buffer(pa: &Pass, name: impl ToString) -> Result<Handle, Text> {
123        let (.., handle) = windows().named_buffer_entry(pa, &name.to_string())?;
124
125        Ok(handle)
126    }
127
128    /// Returns the current active [`Handle`]
129    ///
130    /// Unlike [`current_buffer`], this function will return a
131    /// [`Handle<dyn Widget>`], which means it could be any
132    /// [`Widget`], not just a [`Buffer`].
133    ///
134    /// [`Buffer`]: crate::buffer::Buffer
135    pub fn current_widget(pa: &Pass) -> &Handle<dyn Widget> {
136        windows().current_widget(pa).read(pa).handle()
137    }
138
139    /// The [`CurWidgetNode`]
140    pub(crate) fn current_widget_node(pa: &Pass) -> CurWidgetNode {
141        CurWidgetNode(windows().current_widget(pa).clone())
142    }
143
144    ////////// Other getters
145
146    /// The [`Window`]s of Duat
147    ///
148    /// This struct gives you reading access to every [`Window`] in
149    /// Duat with [`Windows::get`], you also get access to every
150    /// [`Handle<dyn Widget>`], including every [`Handle<Buffer>`],
151    /// through the [`Windows::handles`], [`Window::handles`] and
152    /// [`Window::buffers`] function
153    pub fn windows() -> &'static Windows {
154        WINDOWS.get().unwrap()
155    }
156
157    /// The current [`Window`]
158    ///
159    /// You can iterate through all [`Handle<Buffer>`]s and
160    /// [`Handle<dyn Widget>`] with [`Window::buffers`] and
161    /// [`Window::handles`] respectively.
162    ///
163    /// If you wish to access other [`Window`]s, you can use
164    /// `context::windows().get(pa, n)` to get the `n`th `Window`.
165    /// The current window number can be found with
166    /// [`context::current_win_index`]
167    ///
168    /// [`context::current_win_index`]: current_win_index
169    pub fn current_window(pa: &Pass) -> &Window {
170        let win = current_win_index(pa);
171        WINDOWS.get().unwrap().get(pa, win).unwrap()
172    }
173
174    /// The index of the currently active window
175    pub fn current_win_index(pa: &Pass) -> usize {
176        windows().current_window(pa)
177    }
178
179    /// The name of the current [`Mode`]
180    ///
181    /// This uses a [`DataMap`] in order to prevent mutation of said
182    /// name.
183    ///
184    /// [`Mode`]: crate::mode::Mode
185    pub fn mode_name() -> DataMap<&'static str, &'static str> {
186        MODE_NAME.map(|name| *name)
187    }
188
189    // pub(crate) in order to keep just the DataMap one public
190    pub(crate) fn raw_mode_name() -> RwData<&'static str> {
191        MODE_NAME.clone()
192    }
193
194    /// The current directory
195    pub fn current_dir() -> PathBuf {
196        CUR_DIR
197            .get_or_init(|| Mutex::new(std::env::current_dir().unwrap()))
198            .lock()
199            .unwrap()
200            .clone()
201    }
202
203    /// A [`mpsc::Sender`] for [`DuatEvent`]s in the main loop
204    pub(crate) fn sender() -> mpsc::Sender<DuatEvent> {
205        SENDER.get().unwrap().clone()
206    }
207
208    ////////// Functions for synchronization
209
210    /// Returns `true` if Duat is about to reload
211    pub fn will_reload_or_quit() -> bool {
212        WILL_RELOAD_OR_QUIT.load(Ordering::Relaxed)
213    }
214}
215
216/// A "dynamic" [`Handle`] wrapper for [`Buffer`]s
217///
218/// This `Handle` wrapper will always point to the presently active
219/// `Buffer`. It can also detect when that `Buffer` has been changed
220/// or when another `Buffer` becomes the active `Buffer`.
221pub struct DynBuffer {
222    cur_buffer: RwData<Handle>,
223    saved_buffer: RwData<Handle>,
224}
225
226impl DynBuffer {
227    /// Wether the [`Buffer`] pointed to has changed or swapped with
228    /// another
229    pub fn has_changed(&self, pa: &Pass) -> bool {
230        if self.cur_buffer.has_changed() {
231            true
232        } else {
233            self.saved_buffer.read(pa).has_changed(pa)
234        }
235    }
236
237    /// Swaps the [`DynBuffer`] to the currently active [`Buffer`]
238    pub fn swap_to_current(&mut self) {
239        // SAFETY: Since this struct uses deep Cloning, no mutable
240        // references to the RwData exist.
241        let pa = unsafe { &mut Pass::new() };
242        if self.cur_buffer.has_changed() {
243            *self.saved_buffer.write(pa) = self.cur_buffer.read(pa).clone();
244        }
245    }
246
247    /// Reads the presently active [`Buffer`]
248    pub fn read<'a>(&'a mut self, pa: &'a Pass) -> &'a Buffer {
249        self.saved_buffer.read(pa).read(pa)
250    }
251
252    /// The [`Handle<Buffer>`] currently being pointed to
253    pub fn handle(&self) -> &Handle {
254        // SAFETY: Since this struct uses deep Cloning, no mutable
255        // references to the RwData exist.
256        static INTERNAL_PASS: &Pass = unsafe { &Pass::new() };
257        self.saved_buffer.read(INTERNAL_PASS)
258    }
259
260    /// Simulates a [`read`] without actually reading
261    ///
262    /// This is useful if you want to tell Duat that you don't want
263    /// [`has_changed`] to return `true`, but you don't have a
264    /// [`Pass`] available to [`read`] the value.
265    ///
266    /// This assumes that you don't care about the active [`Buffer`]
267    /// possibly being swapped.
268    ///
269    /// [`read`]: Self::read
270    /// [`has_changed`]: Self::has_changed
271    pub fn declare_as_read(&self) {
272        // SAFETY: Since this struct uses deep Cloning, no mutable
273        // references to the RwData exist.
274        static INTERNAL_PASS: &Pass = unsafe { &Pass::new() };
275        self.cur_buffer.declare_as_read();
276        self.saved_buffer.read(INTERNAL_PASS).declare_as_read();
277    }
278
279    ////////// Writing functions
280
281    /// Reads the presently active [`Buffer`]
282    pub fn write<'a>(&'a self, pa: &'a mut Pass) -> &'a mut Buffer {
283        // SAFETY: Because I already got a &mut Pass, the RwData can't be
284        // accessed anyways.
285        static INTERNAL_PASS: &Pass = unsafe { &Pass::new() };
286
287        self.saved_buffer.read(INTERNAL_PASS).write(pa)
288    }
289
290    /// Writes to the [`Buffer`] and [`Area`], making use of a
291    /// [`Pass`]
292    ///
293    /// [`Area`]: crate::ui::Area
294    pub fn write_with_area<'a>(&'a self, pa: &'a mut Pass) -> (&'a mut Buffer, &'a mut Area) {
295        // SAFETY: Because I already got a &mut Pass, the RwData can't be
296        // accessed anyways.
297        static INTERNAL_PASS: &Pass = unsafe { &Pass::new() };
298
299        self.saved_buffer.read(INTERNAL_PASS).write_with_area(pa)
300    }
301
302    /// Simulates a [`write`] without actually writing
303    ///
304    /// This is useful if you want to tell Duat that you want
305    /// [`has_changed`] to return `true`, but you don't have a
306    /// [`Pass`] available to `write` the value with.
307    ///
308    /// [`write`]: Self::write
309    /// [`has_changed`]: Self::has_changed
310    pub fn declare_written(&self) {
311        // SAFETY: Since this struct uses deep Cloning, no other references to
312        // the RwData exist.
313        static INTERNAL_PASS: &Pass = unsafe { &Pass::new() };
314        self.cur_buffer.read(INTERNAL_PASS).declare_written();
315    }
316}
317
318impl Clone for DynBuffer {
319    /// Returns a _deep cloned_ duplicate of the value
320    ///
321    /// In this case, what this means is that the clone and `self`
322    /// will have different internal pointers for the current
323    /// [`Buffer`]. So if, for example, you call
324    /// [`DynBuffer::swap_to_current`] on `self`, that will switch
325    /// `self` to point to the current `Buffer`, but the same will not
326    /// be done in the clone.
327    fn clone(&self) -> Self {
328        // SAFETY: Because I already got a &mut Pass, the RwData can't be
329        // accessed anyways.
330        static INTERNAL_PASS: &Pass = unsafe { &Pass::new() };
331
332        Self {
333            cur_buffer: RwData::new(self.cur_buffer.read(INTERNAL_PASS).clone()),
334            saved_buffer: self.saved_buffer.clone(),
335        }
336    }
337}
338
339/// The current [`Widget`]
340pub(crate) struct CurWidgetNode(RwData<Node>);
341
342impl CurWidgetNode {
343    /// The [`Widget`]'s [`TypeId`]
344    pub fn type_id(&self, pa: &Pass) -> TypeId {
345        self.0.read(pa).widget().type_id()
346    }
347
348    /// Reads the [`Widget`] and its [`Area`]
349    pub fn _read<R>(&self, pa: &Pass, f: impl FnOnce(&dyn Widget, &Area) -> R) -> R {
350        let node = self.0.read(pa);
351        f(node.handle().read(pa), node.area().read(pa))
352    }
353
354    /// Reads the [`Widget`] as `W` and its
355    /// [`Area`]
356    pub fn _read_as<W: Widget, R>(&self, pa: &Pass, f: impl FnOnce(&W, &Area) -> R) -> Option<R> {
357        let node = self.0.read(pa);
358        Some(f(node.read_as(pa)?, node.area().read(pa)))
359    }
360
361    /// Mutates the [`RwData<dyn Widget>`], its
362    /// [`Area`], and related [`Widget`]s
363    pub(crate) fn mutate_data<R>(&self, pa: &Pass, f: impl FnOnce(&Handle<dyn Widget>) -> R) -> R {
364        f(self.0.read(pa).handle())
365    }
366
367    /// Mutates the [`RwData<dyn Widget>`] as `W`, its
368    /// [`Area`], and related [`Widget`]s
369    pub(crate) fn mutate_data_as<W: Widget, R>(
370        &self,
371        pa: &Pass,
372        f: impl FnOnce(&Handle<W>) -> R,
373    ) -> Option<R> {
374        let inner = self.0.read(pa);
375        Some(f(&inner.try_downcast()?))
376    }
377
378    /// The inner [`Node`]
379    pub(crate) fn node(&self, pa: &Pass) -> Node {
380        self.0.read(pa).clone()
381    }
382}