Skip to main content

duat_core/
lib.rs

1//! The core of Duat, for use by Duat's built-in plugins.
2//!
3//! This crate isn't really meant for public use, since it is used
4//! only by a select few plugins. Configuration crates and plugins
5//! should make use of the [duat] crate.
6//!
7//! One thing to note about this "builti-in plugins" thing though, is
8//! that the api of `duat` is a superset of `duat-core`'s api, the
9//! only reason why this distinction exists is so I can include some
10//! other plugins in `duat`'s api, like `duat-base`,
11//! `duat-treesitter`, and `duat-lsp`.
12//!
13//! [duat]: https://crates.io/duat
14#![warn(rustdoc::unescaped_backticks)]
15#![allow(clippy::single_range_in_vec_init)]
16
17// This is because of the weird Strs pointer trickery that I'm doing,
18// usize _must_ be u64
19#[cfg(target_pointer_width = "16")]
20compile_error!("This crate does not support 16-bit systems.");
21#[cfg(target_pointer_width = "32")]
22compile_error!("This crate does not support 32-bit systems.");
23
24#[allow(unused_imports)]
25use dirs_next::cache_dir;
26
27pub use self::{namespace::Ns, ranges::Ranges};
28
29pub mod buffer;
30pub mod cmd;
31pub mod context;
32pub mod data;
33pub mod form;
34pub mod hook;
35pub mod mode;
36pub mod opts;
37mod ranges;
38#[doc(hidden)]
39pub mod session;
40pub mod text;
41pub mod ui;
42pub mod utils;
43
44mod namespace {
45    //! A namespace for Duat operations.
46
47    use std::{
48        ops::Range,
49        sync::{
50            LazyLock,
51            atomic::{AtomicU32, Ordering::Relaxed},
52        },
53    };
54
55    static NAMESPACE_COUNT: AtomicU32 = AtomicU32::new(3);
56
57    /// A namespace for Duat operations.
58    ///
59    /// This is a unique identifier which makes sure you're only
60    /// affecting the parts of Duat that you want to affect. It is
61    /// used in various places within duat:
62    ///
63    /// - For adding [`Tag`]s to [`Text`].
64    /// - For [adding] and [removing] [hooks].
65    /// - For dealing with the [`Gutter`]
66    ///
67    /// Here's an example of a namespace being used to add `Tag`s to
68    /// `Text`:
69    ///
70    /// ```rust
71    /// # duat_core::doc_duat!(duat);
72    /// # use duat::prelude::*;
73    /// let mut text = txt!("This is text with no tags in it");
74    /// // This key will be used to modify text.
75    /// let ns1 = Ns::new();
76    ///
77    /// let id = form::id_of!("invisible");
78    ///
79    /// // You can create an `impl Tag` directly from a `FormId`
80    /// text.insert_tag(ns1, 18..20, id.to_tag(0));
81    ///
82    /// assert_eq!(text, txt!("This is text with [invisible]no[] tags in it"));
83    ///
84    /// // ns2 != ns1, so it shouldn't be able to change what was done with ns1.
85    /// let ns2 = Ns::new();
86    /// text.remove_tags(ns2, 18);
87    ///
88    /// assert_eq!(text, txt!("This is text with [invisible]no[] tags in it"));
89    /// ```
90    ///
91    /// [`Tag`]: crate::text::Tag
92    /// [`Text`]: crate::text::Text
93    /// [adding]: crate::hook::add
94    /// [removing]: crate::hook::remove
95    /// [hooks]: crate::hook
96    /// [`Gutter`]: ../duat/widgets/struct.Gutter.html
97    #[derive(
98        Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, bincode::Decode, bincode::Encode,
99    )]
100    pub struct Ns(u32);
101
102    impl Ns {
103        /// Returns a new, unique namespace.
104        pub fn new() -> Self {
105            Self(NAMESPACE_COUNT.fetch_add(1, Relaxed))
106        }
107
108        /// Returns a new [`LazyLock<Ns>`].
109        ///
110        /// You can use this in order to create `static` namespaces by
111        /// calling something like:
112        ///
113        /// ```rust
114        /// # duat_core::doc_duat!(duat);
115        /// use std::sync::LazyLock;
116        ///
117        /// use duat::prelude::*;
118        ///
119        /// static NS: LazyLock<Ns> = Ns::new_lazy();
120        /// ```
121        pub const fn new_lazy() -> LazyLock<Self> {
122            LazyLock::new(Self::new)
123        }
124
125        /// Returns a number of new, unique namespaces
126        ///
127        /// You may want to do this if you expect to be placing and
128        /// removing a lot of tags, and you want the finest possible
129        /// control over what gets added and deleted from the
130        /// [`Text`].
131        ///
132        /// [`Text`]: crate::text::Text
133        pub fn new_many(amount: u32) -> Range<Self> {
134            let start = NAMESPACE_COUNT.fetch_add(amount + 1, Relaxed);
135            Self(start)..Self(start + amount)
136        }
137
138        /// A simple key with no uniqueness guarantee
139        ///
140        /// You should use this if you're editing widgets that are not
141        /// the [`Buffer`] widget, since you're probably the
142        /// only one that is going to be modifying said widget
143        /// anyway.
144        ///
145        /// The advantage of this function is speed. Since it is a
146        /// `const` function, it's value is just substituted in with
147        /// the code, so there is no need to store it in
148        /// structs or statics.
149        ///
150        /// [`Buffer`]: crate::buffer::Buffer
151        pub const fn basic() -> Self {
152            Self(0)
153        }
154
155        /// A [`Tagger`] specifically for remaps
156        pub(crate) const fn for_alias() -> Self {
157            Self(1)
158        }
159
160        pub(crate) const fn for_toggle() -> Self {
161            Self(2)
162        }
163    }
164
165    impl Default for Ns {
166        /// Returns a _new_ namespace.
167        ///
168        /// Not to be confused with [`Ns::basic`].
169        fn default() -> Self {
170            Self::new()
171        }
172    }
173
174    impl std::fmt::Debug for Ns {
175        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176            write!(f, "Ns({})", self.0)
177        }
178    }
179}
180
181pub mod clipboard {
182    //! Clipboard interaction for Duat.
183    //!
184    //! Just a regular clipboard, no image functionality.
185    use std::sync::Mutex;
186
187    use crate::session::{self, ipc::MsgFromChild};
188
189    static CLIPBOARD: Mutex<Option<String>> = Mutex::new(None);
190
191    /// Gets a [`String`] from the clipboard.
192    ///
193    /// This can fail if the clipboard does not contain UTF-8 encoded
194    /// text.
195    pub fn get() -> Option<String> {
196        let content = if cfg!(target_os = "android") {
197            None
198        } else {
199            session::ipc::send(MsgFromChild::RequestClipboard);
200            session::ipc::recv_clipboard()
201        };
202
203        let mut clipboard = CLIPBOARD.lock().unwrap();
204
205        if let Some(content) = content {
206            *clipboard = Some(content);
207        }
208
209        clipboard.clone()
210    }
211
212    /// Sets the content of the clipboard.
213    pub fn set(content: impl std::fmt::Display) {
214        let content = content.to_string();
215        *CLIPBOARD.lock().unwrap() = Some(content.clone());
216
217        #[cfg(not(target_os = "android"))]
218        {
219            session::ipc::send(MsgFromChild::UpdateClipboard(content));
220        }
221    }
222
223    /// Sets the content of the clipboard without changing the system
224    /// clipboard.
225    pub fn set_local(content: impl std::fmt::Display) {
226        let content = content.to_string();
227        *CLIPBOARD.lock().unwrap() = Some(content.clone());
228    }
229}
230
231pub mod notify {
232    //! File watching utility for Duat.
233    //!
234    //! Provides a simplified interface over the [`notify`] crate.
235    //!
236    //! [`notify`]: https://crates.io/crates/notify
237    use std::{
238        collections::HashMap,
239        path::{Path, PathBuf},
240        sync::{LazyLock, Mutex},
241        time::{Duration, Instant},
242    };
243
244    pub use notify::event;
245    use notify::{
246        Config, RecommendedWatcher, RecursiveMode, Watcher as NWatcher,
247        event::{AccessKind, AccessMode, Event, EventKind},
248    };
249
250    static DUAT_WRITES: LazyLock<Mutex<HashMap<PathBuf, DuatWrite>>> =
251        LazyLock::new(Mutex::default);
252
253    /// A record of write events that came from Duat.
254    #[derive(Default)]
255    struct DuatWrite {
256        count: usize,
257        last: Option<Instant>,
258    }
259
260    /// Wether an event came from Duat or not.
261    ///
262    /// This is only ever [`FromDuat::Yes`] if the event is a write
263    /// event resulting from [`Handle::<Buffer>::save`].
264    ///
265    /// This can be useful if you want to sort events based on
266    /// external or internal factors. For example, duat makes use of
267    /// this in order to calculate file diffs only if the file was
268    /// modified from outside of duat.
269    ///
270    /// [`Handle::<Buffer>::save`]: crate::context::Handle::save
271    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
272    pub enum FromDuat {
273        /// The event came from Duat, more specifically, it cam from a
274        /// function like [`Handle::<Buffer>::save`].
275        ///
276        /// Another thing to note is that this will only be this value
277        /// if _all_ the paths were written by Duat. If this is not
278        /// the case, then it will be [`FromDuat::No`]. This usually
279        /// isn't an issue, since the vast majority of events emmit
280        /// only one path, but it is something to keep in mind.
281        ///
282        /// [`Handle::<Buffer>::save`]: crate::context::Handle::save
283        Yes,
284        /// The event didn't come from Duat.
285        ///
286        /// Note that, even if the event actually came from Duat,
287        /// unless it is a write event, it will always be set to this.
288        No,
289    }
290
291    /// A [`Path`] watcher.
292    ///
293    /// If this struct is [`drop`]ped, the `Path`s it was watching
294    /// will no longer be watched by it.
295    pub struct Watcher(Mutex<RecommendedWatcher>);
296
297    impl Watcher {
298        /// Spawn a new `Watcher`, with a callback function
299        ///
300        /// You can add paths to watch through [`Watcher::watch`] and
301        /// [`Watcher::watch_recursive`].
302        pub fn new(
303            mut callback: impl FnMut(notify::Result<Event>, FromDuat) + Send + 'static,
304        ) -> notify::Result<Self> {
305            Ok(Self(Mutex::new(RecommendedWatcher::new(
306                move |event| {
307                    use FromDuat::*;
308                    let from_duat = if let Ok(Event {
309                        kind: EventKind::Access(AccessKind::Close(AccessMode::Write)),
310                        paths,
311                        ..
312                    }) = &event
313                        && !paths.is_empty()
314                    {
315                        let now = Instant::now();
316                        let mut duat_writes = DUAT_WRITES.lock().unwrap();
317                        let mut all_are_from_duat = true;
318
319                        for path in paths {
320                            if let Some(dw) = duat_writes.get_mut(path)
321                                && (dw.count > 0
322                                    || dw.last.is_some_and(|instant| {
323                                        now.duration_since(instant) < Duration::from_millis(2)
324                                    }))
325                            {
326                                dw.count = dw.count.saturating_sub(1);
327                                dw.last = Some(now);
328                            } else {
329                                all_are_from_duat = false;
330                            }
331                        }
332
333                        if all_are_from_duat { Yes } else { No }
334                    } else {
335                        No
336                    };
337
338                    callback(event, from_duat);
339                },
340                Config::default(),
341            )?)))
342        }
343
344        /// Watch a [`Path`] non-recursively.
345        pub fn watch(&self, path: &Path) -> notify::Result<()> {
346            self.0
347                .lock()
348                .unwrap()
349                .watch(path, RecursiveMode::NonRecursive)
350        }
351
352        /// Watch a [`Path`] recursively.
353        pub fn watch_recursive(&self, path: &Path) -> notify::Result<()> {
354            self.0.lock().unwrap().watch(path, RecursiveMode::Recursive)
355        }
356
357        /// Stop watching a [`Path`].
358        pub fn unwatch(&self, path: &Path) -> notify::Result<()> {
359            self.0.lock().unwrap().unwatch(path)
360        }
361    }
362
363    impl Drop for Watcher {
364        fn drop(&mut self) {}
365    }
366
367    /// A callback for Watcher events.
368    ///
369    /// **FOR USE BY THE DUAT EXECUTABLE ONLY**
370    #[doc(hidden)]
371    pub struct WatcherCallback {
372        callback: Box<dyn FnMut(std::io::Result<Event>) + Send + 'static>,
373        // This is required, so the WATCHER_COUNT is from the loaded config, not the duat
374        // executable.
375        drop: fn(),
376    }
377
378    impl WatcherCallback {
379        /// Calls the callback.
380        pub fn call(&mut self, event: std::io::Result<Event>) {
381            (self.callback)(event)
382        }
383    }
384
385    impl Drop for WatcherCallback {
386        fn drop(&mut self) {
387            (self.drop)();
388        }
389    }
390
391    /// Declares that the next write event actually came from Duat,
392    /// for a given path.
393    pub(crate) fn set_next_write_as_from_duat(path: PathBuf) {
394        DUAT_WRITES.lock().unwrap().entry(path).or_default().count += 1;
395    }
396
397    /// Declares that the next write event didn't come from Duat,
398    /// for a given path.
399    pub(crate) fn unset_next_write_as_from_duat(path: PathBuf) {
400        let mut duat_writes = DUAT_WRITES.lock().unwrap();
401        let dw = duat_writes.entry(path).or_default();
402        dw.count = dw.count.saturating_sub(1);
403    }
404}
405
406pub mod process {
407    //! Utilities for spawning processes that should outlive the
408    //! config.
409    use std::{
410        ffi::{OsStr, OsString},
411        io::{BufRead, BufWriter, Read, Write},
412        process::{Child, Command, Stdio},
413        sync::{
414            Mutex,
415            atomic::{AtomicUsize, Ordering},
416            mpsc,
417        },
418        time::Duration,
419    };
420
421    use bincode::{
422        Decode, Encode, config,
423        error::{DecodeError, EncodeError},
424    };
425    use interprocess::local_socket::prelude::*;
426    pub use interrupt_read::InterruptReader;
427
428    use crate::session::{
429        self,
430        ipc::{MsgFromChild, ProcessReader},
431    };
432
433    /// Spawn a new `PersistentChild`, which can be reused in
434    /// future config reloads.
435    ///
436    /// The command will forcibly make use of [`Stdio::piped`] for all
437    /// stdio. This is because stdin, stdout and stderr are
438    /// reserved for use by the [`Ui`] implementation, so something
439    /// like [`Stdio::inherit`] would interfere with that.
440    ///
441    /// [`Ui`]: crate::ui::Ui
442    pub fn spawn_persistent(command: &mut Command) -> std::io::Result<PersistentChild> {
443        let encode = |value: &OsStr| value.as_encoded_bytes().to_vec();
444
445        let args = command.get_args().map(encode).collect();
446        let envs = command
447            .get_envs()
448            .map(|(k, v)| (encode(k), v.map(encode)))
449            .collect();
450
451        session::ipc::send(MsgFromChild::SpawnProcess(PersistentSpawnRequest {
452            program: encode(command.get_program()),
453            args,
454            envs,
455        }));
456
457        match session::ipc::recv_spawn() {
458            Ok(id) => Ok(PersistentChild::new(id, Vec::new(), Vec::new())),
459            Err(err) => Err(std::io::Error::from_raw_os_error(err)),
460        }
461    }
462    /// A child process that will persist over multiple reload cycles.
463    ///
464    /// This child makes use of [`interprocess`]'s [local sockets] for
465    /// communication. This is because the process will be spawned by
466    /// the duat executor, and communication between it and the config
467    /// child process won't be possible by regular stdio.
468    ///
469    /// Unless you call [`PersistentChild::kill`], duat will assume
470    /// that you want it to be kept alive for future reloads.
471    ///
472    /// # Later retrieval
473    ///
474    /// If you want to retrieve this `PersistentChild` on a future
475    /// reload cycle. You will need to store it by calling
476    /// [`storage::store`], from duat's [`storage`] module. You can
477    /// only do this once, trying it again will (logically) cause a
478    /// panic.
479    ///
480    /// Since this struct implements [`Decode`] and
481    /// [`Encode`], it can be stored and retrieved, even if
482    /// it is part of another struct.
483    ///
484    /// If you don't call `storage::store`, it is assumed that you no
485    /// longer need the process, and it will be killed.
486    ///
487    /// # Unread bytes
488    ///
489    /// When reloading Duat, the stdin, stdout and stderr processes
490    /// are guaranteed to not lose any bytes.
491    ///
492    /// This is only the case, however, if you don't have some sort of
493    /// buffering and/or aren't doing a deserialization attempt with
494    /// said data.
495    ///
496    /// If you want to do deserialization (via [`Decode`]),
497    /// you will want to use [`PersistentReader::decode_bytes_as`].
498    /// This method will fail to decode if a reload is requested
499    /// midway through reading, but the bytes will be saved for
500    /// the next reload cycle, where you can start decoding again.
501    ///
502    /// [local sockets]: interprocess::local_socket::Stream
503    /// [`storage::store`]: crate::storage::store
504    /// [`storage`]: crate::storage
505    pub struct PersistentChild {
506        /// The standard input of the [`Child`].
507        ///
508        /// This struct will send the bytes to an ipc enabled
509        /// [`LocalSocketStream`], which will in turn be sent to the
510        /// process indirectly, since said process is owned by the
511        /// parent executor, not the child.
512        pub stdin: Option<PersistentWriter>,
513        stdout: Mutex<Option<PersistentReader>>,
514        stderr: Mutex<Option<PersistentReader>>,
515        stdout_rx: mpsc::Receiver<ReaderPair>,
516        stderr_rx: mpsc::Receiver<ReaderPair>,
517        id: usize,
518    }
519
520    impl PersistentChild {
521        fn new(id: usize, stdout_bytes: Vec<u8>, stderr_bytes: Vec<u8>) -> Self {
522            let (stdin, [stdout, stderr]) =
523                session::ipc::connect_process_channel(id, stdout_bytes, stderr_bytes).unwrap();
524            let (stdout_tx, stdout_rx) = mpsc::channel();
525            let (stderr_tx, stderr_rx) = mpsc::channel();
526
527            Self {
528                stdin: Some(PersistentWriter(RawPersistentWriter(BufWriter::new(stdin)))),
529                stdout: Mutex::new(Some(PersistentReader {
530                    pair: Some(ReaderPair { decode_bytes: Vec::new(), conn: stdout }),
531                    pair_tx: stdout_tx,
532                })),
533                stderr: Mutex::new(Some(PersistentReader {
534                    pair: Some(ReaderPair { decode_bytes: Vec::new(), conn: stderr }),
535                    pair_tx: stderr_tx,
536                })),
537                stdout_rx,
538                stderr_rx,
539                id,
540            }
541        }
542
543        /// The standard output of the [`Child`].
544        ///
545        /// This reader is already buffered, so you don't need to wrap
546        /// it in a [`BufReader`] to use it efficiently.
547        ///
548        /// In order to use this correctly, you must follow one of
549        /// three scenarios:
550        ///
551        /// - A reading loop that never stops. This is the most common
552        ///   usecase.
553        /// - If you are going to stop, make sure that the reader is
554        ///   dropped or that you have called
555        ///   [`PersistentReader::give_back`]. This is to ensure that
556        ///   any unread bytes are stored correctly when reloading
557        ///   Duat.
558        /// - If the child has been [killed], then you don't need to
559        ///   do anything in particular.
560        ///
561        /// For decoding [`bincode::Decode`] types, you should make
562        /// use of the [`PersistentReader::decode_bytes_as`] function,
563        /// since that one is not prone to losses if it is interrupted
564        /// by a reload.
565        ///
566        /// [killed]: PersistentChild::kill
567        /// [`BufReader`]: std::io::BufReader
568        pub fn get_stdout(&self) -> Option<PersistentReader> {
569            self.stdout.lock().unwrap().take()
570        }
571
572        /// The standard error of the [`Child`].
573        ///
574        /// This reader is already buffered, so you don't need to wrap
575        /// it in a [`BufReader`] to use it efficiently.
576        ///
577        /// In order to use this correctly, you must follow one of
578        /// three scenarios:
579        ///
580        /// - A reading loop that never stops. This is the most common
581        ///   usecase.
582        /// - If you are going to stop, make sure that the reader is
583        ///   dropped or that you have called
584        ///   [`PersistentReader::give_back`]. This is to ensure that
585        ///   any unread bytes are stored correctly when reloading
586        ///   Duat.
587        /// - If the child has been [killed], then you don't need to
588        ///   do anything in particular.
589        ///
590        /// [killed]: PersistentChild::kill
591        /// [`BufReader`]: std::io::BufReader
592        pub fn get_stderr(&self) -> Option<PersistentReader> {
593            self.stderr.lock().unwrap().take()
594        }
595
596        /// Kill the [`Child`] process.
597        pub fn kill(self) -> std::io::Result<()> {
598            session::ipc::send(MsgFromChild::KillProcess(self.id));
599            session::ipc::recv_kill().map_err(std::io::Error::from_raw_os_error)
600        }
601    }
602
603    impl<Context> Decode<Context> for PersistentChild {
604        fn decode<D: bincode::de::Decoder<Context = Context>>(
605            decoder: &mut D,
606        ) -> Result<Self, DecodeError> {
607            let stored = StoredPersistentChild::decode(decoder)?;
608            Ok(Self::new(
609                stored.id,
610                stored.stdout_bytes,
611                stored.stderr_bytes,
612            ))
613        }
614    }
615
616    impl Encode for PersistentChild {
617        /// Encodes the `PersistentChild`
618        ///
619        /// This can only be done once, trying to do it again will
620        /// result in a panic.
621        #[track_caller]
622        fn encode<E: bincode::enc::Encoder>(
623            &self,
624            encoder: &mut E,
625        ) -> Result<(), bincode::error::EncodeError> {
626            session::ipc::send(MsgFromChild::InterruptWrites(self.id));
627
628            let (stdout, stderr) = (
629                self.stdout.lock().unwrap().take(),
630                self.stderr.lock().unwrap().take(),
631            );
632
633            let (stdout_bytes, stderr_bytes) = match (stdout, stderr) {
634                (None, None) => {
635                    let stdout_bytes = self.stdout_rx.recv().unwrap().consume();
636                    let stderr_bytes = self.stderr_rx.recv().unwrap().consume();
637                    (stdout_bytes, stderr_bytes)
638                }
639                (None, Some(mut stderr)) => {
640                    let stdout_bytes = self.stdout_rx.recv().unwrap().consume();
641                    let stderr_bytes = stderr.pair.take().unwrap().consume();
642                    (stdout_bytes, stderr_bytes)
643                }
644                (Some(mut stdout), None) => {
645                    let stdout_bytes = stdout.pair.take().unwrap().consume();
646                    let stderr_bytes = self.stderr_rx.recv().unwrap().consume();
647                    (stderr_bytes, stdout_bytes)
648                }
649                (Some(mut stdout), Some(mut stderr)) => {
650                    let stdout_bytes = stdout.pair.take().unwrap().consume();
651                    let stderr_bytes = stderr.pair.take().unwrap().consume();
652                    (stderr_bytes, stdout_bytes)
653                }
654            };
655
656            StoredPersistentChild { id: self.id, stdout_bytes, stderr_bytes }.encode(encoder)
657        }
658    }
659
660    impl Drop for PersistentChild {
661        fn drop(&mut self) {}
662    }
663
664    /// A pair used for reading and decoding.
665    struct ReaderPair {
666        decode_bytes: Vec<u8>,
667        conn: ProcessReader,
668    }
669
670    impl ReaderPair {
671        /// Consumes the reader, returning all unread bytes.
672        fn consume(mut self) -> Vec<u8> {
673            _ = self.conn.read_to_end(&mut self.decode_bytes);
674            self.decode_bytes
675        }
676    }
677
678    /// A [`Read`]er which is meant to be used across multiple reload
679    /// cycles.
680    ///
681    /// This reader is _already buffered_, don't wrap it in a
682    /// [`BufReader`], or else you _will lose bytes on reloads_.
683    ///
684    /// [`BufReader`]: std::io::BufReader
685    pub struct PersistentReader {
686        pair: Option<ReaderPair>,
687        pair_tx: mpsc::Sender<ReaderPair>,
688    }
689
690    impl PersistentReader {
691        /// Attempts to decode the bytes as a type.
692        pub fn decode_bytes_as<D: Decode<()>>(&mut self) -> Result<D, DecodeError> {
693            struct RepeatReader<'p>(&'p mut PersistentReader);
694
695            impl<'p> Read for RepeatReader<'p> {
696                fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
697                    let reader = &mut self.0;
698                    let pair = reader.pair.as_mut().unwrap();
699
700                    match pair.conn.read(buf) {
701                        Ok(0) => {
702                            _ = reader.pair_tx.send(reader.pair.take().unwrap());
703                            // We loop forever, to abstract away the reloading of Duat in reading
704                            // loops.
705                            loop {
706                                std::thread::park();
707                            }
708                        }
709                        Ok(num_bytes) => {
710                            pair.decode_bytes.extend_from_slice(&buf[..num_bytes]);
711                            Ok(num_bytes)
712                        }
713                        Err(err) => Err(err),
714                    }
715                }
716            }
717
718            let value = bincode::decode_from_std_read(&mut RepeatReader(self), config::standard())?;
719            self.pair.as_mut().unwrap().decode_bytes.clear();
720
721            Ok(value)
722        }
723
724        /// Returns this [`Read`]er (and its bytes) to be retrieved
725        /// later on.
726        ///
727        /// Note that if the [`PersistentChild`] was already [killed],
728        /// this won't do anything.
729        ///
730        /// [killed]: PersistentChild::kill
731        pub fn give_back(self) {
732            drop(self)
733        }
734    }
735
736    impl Read for PersistentReader {
737        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
738            let pair = self.pair.as_mut().unwrap();
739            match pair.conn.read(buf) {
740                // This means that the equivalent Stream in the parent process was
741                // dropped, which means we're about to reload.
742                Ok(0) => {
743                    _ = self.pair_tx.send(self.pair.take().unwrap());
744                    // We loop forever, to abstract away the reloading of Duat in reading
745                    // loops.
746                    loop {
747                        std::thread::park();
748                    }
749                }
750                Ok(bytes) => Ok(bytes),
751                Err(err) => Err(err),
752            }
753        }
754    }
755
756    impl BufRead for PersistentReader {
757        fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
758            let pair = self.pair.as_mut().unwrap();
759            match pair.conn.fill_buf() {
760                Ok([]) => {
761                    _ = self.pair_tx.send(self.pair.take().unwrap());
762                    // We loop forever, to abstract away the reloading of Duat in reading
763                    // loops.
764                    loop {
765                        std::thread::park();
766                    }
767                }
768                Ok(_) => {
769                    let pair = self.pair.as_ref().unwrap();
770                    Ok(pair.conn.buffer())
771                }
772                Err(err) => Err(err),
773            }
774        }
775
776        fn consume(&mut self, amount: usize) {
777            let pair = self.pair.as_mut().unwrap();
778            pair.conn.consume(amount);
779        }
780    }
781
782    impl Drop for PersistentReader {
783        fn drop(&mut self) {
784            if let Some(pair) = self.pair.take() {
785                // The entry may have already been removed.
786                _ = self.pair_tx.send(pair);
787            }
788        }
789    }
790
791    /// A [`Write`]r "lock" for a [`PersistentChild`].
792    ///
793    /// This struct will send bytes to the `stdin` of a
794    /// `PersistentChild`. This is done indirectly through a
795    /// [`LocalSocketStream`], since the child process doesn't have
796    /// direct access to the stdin of the child, as it belongs to the
797    /// parent process.
798    ///
799    /// This writer is more of a "writer lock" over the actual inner
800    /// writer. This is because of reloads.
801    ///
802    /// When duat reloads, the child process is finished. This could
803    /// prematurely end `write` calls of separate threads, leading to
804    /// the loss, duplication, or corruption of data.
805    ///
806    /// That's why this struct has the [`PersistentWriter::on_writer`]
807    /// method. This method will give you mutable access to the writer
808    /// while preventing duat from reloading.
809    ///
810    /// You should make use of it in order to "confirm" that a value
811    /// has actually been written. Any confirmation outside of this
812    /// method can't be trusted.
813    pub struct PersistentWriter(RawPersistentWriter);
814
815    impl PersistentWriter {
816        /// Calls a function on the inner [`Write`]r.
817        ///
818        /// This will also prevent Duat from reloading, allowing for
819        /// lossless and duplicationless data sending.
820        #[track_caller]
821        pub fn on_writer<R>(
822            &mut self,
823            f: impl FnOnce(&mut RawPersistentWriter) -> std::io::Result<R>,
824        ) -> std::io::Result<R> {
825            use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
826
827            WRITERS_WRITING.fetch_add(1, Ordering::Acquire);
828            let result = catch_unwind(AssertUnwindSafe(move || f(&mut self.0)));
829            WRITERS_WRITING.fetch_sub(1, Ordering::Release);
830
831            match result {
832                Ok(result) => result,
833                Err(panic) => resume_unwind(panic),
834            }
835        }
836    }
837
838    /// The writer from [`PersistentWriter::on_writer`].
839    ///
840    /// This struct is basically just a wrapper over a
841    /// [`BufWriter<LocalSocketStream>`], but it also comes with the
842    /// [`encode_as_bytes`] method, which lets you encode a value as
843    /// bytes in a more convenient, less prone to error way, than
844    /// using [`bincode`] by itself.
845    ///
846    /// [`encode_as_bytes`]: RawPersistentWriter::encode_as_bytes
847    pub struct RawPersistentWriter(BufWriter<LocalSocketStream>);
848
849    impl RawPersistentWriter {
850        /// Encode the value as bytes, in a duat compatible way.
851        ///
852        /// Note that you have to call [`Write::flush`] in order to
853        /// actually send the data.
854        pub fn encode_as_bytes(&mut self, value: impl Encode) -> Result<usize, EncodeError> {
855            bincode::encode_into_std_write(value, &mut self.0, config::standard())
856        }
857    }
858
859    impl Write for RawPersistentWriter {
860        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
861            self.0.write(buf)
862        }
863
864        fn flush(&mut self) -> std::io::Result<()> {
865            self.0.flush()
866        }
867    }
868
869    /// A request to spawn a new [`PersistentChild`] process.
870    #[doc(hidden)]
871    #[derive(Decode, Encode)]
872    pub struct PersistentSpawnRequest {
873        program: Vec<u8>,
874        args: Vec<Vec<u8>>,
875        envs: Vec<(Vec<u8>, Option<Vec<u8>>)>,
876    }
877
878    impl PersistentSpawnRequest {
879        /// Spawn the [`Command`].
880        ///
881        /// Returns the id of this command, as well as the
882        /// [`Child`] that was spawned.
883        ///
884        /// This should only be done in the Duat executable.
885        // This will become `std::io::RawOsError` once that is stable.
886        pub fn spawn(self) -> Result<(String, Child), i32> {
887            let decode = |value: Vec<u8>| unsafe { OsString::from_encoded_bytes_unchecked(value) };
888
889            let caller = decode(self.program.clone()).to_string_lossy().to_string();
890
891            let child = Command::new(decode(self.program))
892                .args(self.args.into_iter().map(decode))
893                .envs(
894                    self.envs
895                        .into_iter()
896                        .filter_map(|(k, v)| Some((decode(k), decode(v?)))),
897                )
898                .stdin(Stdio::piped())
899                .stdout(Stdio::piped())
900                .stderr(Stdio::piped())
901                // TODO: Deal with pre_exec closures.
902                .spawn()
903                .map_err(|err| err.raw_os_error().unwrap())?;
904
905            Ok((caller, child))
906        }
907    }
908
909    impl std::fmt::Debug for PersistentSpawnRequest {
910        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
911            let decode = |value: Vec<u8>| unsafe { OsString::from_encoded_bytes_unchecked(value) };
912
913            f.debug_struct("PersistentSpawnRequest")
914                .field("program", &decode(self.program.clone()))
915                .field(
916                    "args",
917                    &self.args.iter().cloned().map(decode).collect::<Vec<_>>(),
918                )
919                .field(
920                    "envs",
921                    &self
922                        .envs
923                        .iter()
924                        .cloned()
925                        .map(|(k, v)| (decode(k), v.map(decode)))
926                        .collect::<Vec<_>>(),
927                )
928                .finish()
929        }
930    }
931
932    /// A stored [`PersistentChild`].
933    #[derive(Decode, Encode)]
934    struct StoredPersistentChild {
935        id: usize,
936        stdout_bytes: Vec<u8>,
937        stderr_bytes: Vec<u8>,
938    }
939
940    /// Wait for a [`PersistentChild`] writers to be done writing.
941    pub(crate) fn wait_for_writers() {
942        while WRITERS_WRITING.load(Ordering::Relaxed) > 0 {
943            std::thread::sleep(Duration::from_millis(1));
944        }
945    }
946
947    static WRITERS_WRITING: AtomicUsize = AtomicUsize::new(0);
948}
949
950pub mod storage {
951    //! Utilities for storing items inbetween reloads.
952    use std::{
953        collections::{HashMap, hash_map::Entry},
954        io::Cursor,
955        sync::Mutex,
956    };
957
958    pub use bincode;
959    use bincode::{BorrowDecode, Decode, Encode, config, error::EncodeError};
960
961    use crate::data::Pass;
962
963    static STORED: Mutex<Option<HashMap<String, MaybeTypedValues>>> = Mutex::new(None);
964
965    /// Store a value across reload cycles.
966    ///
967    /// You can use this function if you want to store a value through
968    /// reload cycles, retrieving it after Duat reloads.
969    ///
970    /// The [`Pass`] argument is used here to ensure that you're doing
971    /// this from the main thread, since storing from other threads
972    /// could result in the object not _actually_ being stored, if
973    /// this function is called in the very small time interval
974    /// inbetween duat taking the stored objects out and unloading the
975    /// config.
976    pub fn store<E>(_: &Pass, value: E) -> Result<(), EncodeError>
977    where
978        E: Encode + Send + 'static,
979    {
980        let key = std::any::type_name_of_val(&value).to_string();
981
982        let mut stored_guard = STORED.lock().unwrap_or_else(|err| err.into_inner());
983        let stored = stored_guard.as_mut().unwrap();
984
985        match stored.entry(key.clone()) {
986            Entry::Occupied(mut occupied_entry) => match occupied_entry.get_mut() {
987                MaybeTypedValues::NotTyped(list_of_bytes) => {
988                    let mut encoded = std::mem::take(list_of_bytes);
989                    bincode::encode_into_std_write(value, &mut encoded, config::standard())?;
990                    occupied_entry.insert(MaybeTypedValues::typed(PartiallyDecodedValues::<E> {
991                        encoded: Mutex::new(Cursor::new(encoded)),
992                        decoded: Vec::new(),
993                    }));
994                }
995                MaybeTypedValues::Typed(typed, _) => {
996                    let values: &mut PartiallyDecodedValues<E> = typed.downcast_mut().unwrap();
997                    bincode::encode_into_std_write(
998                        value,
999                        encoded(&values.encoded).get_mut(),
1000                        config::standard(),
1001                    )?;
1002                }
1003            },
1004            Entry::Vacant(vacant_entry) => {
1005                let mut encoded = Vec::new();
1006                bincode::encode_into_std_write(value, &mut encoded, config::standard())?;
1007                vacant_entry.insert(MaybeTypedValues::typed(PartiallyDecodedValues::<E> {
1008                    encoded: Mutex::new(Cursor::new(encoded)),
1009                    decoded: Vec::new(),
1010                }));
1011            }
1012        };
1013
1014        Ok(())
1015    }
1016
1017    /// Retrieve a value that might have been stored on a previous
1018    /// reload cycle.
1019    ///
1020    /// This will call the predicate on each stored value of type `D`
1021    /// (not including those stored as fields in structs), and will
1022    /// extract the value if the predicate returns `true`.
1023    ///
1024    /// If the layout of the type has changed inbetween reloads, all
1025    /// values of said type will be discarded.
1026    ///
1027    /// # Note
1028    ///
1029    /// This function relies on the name of the stored type. This is
1030    /// because more reliable indicators (like [`TypeId`]) can't be
1031    /// relied to be the same inbetween reloads, while a `&str` can.
1032    ///
1033    /// This does mean however, that changing the path of a type will
1034    /// immediately invalidade the stored values, so you should avoid
1035    /// doing that.
1036    ///
1037    /// [`TypeId`]: std::any::TypeId
1038    pub fn get_if<D>(mut pred: impl FnMut(&D) -> bool) -> Option<D>
1039    where
1040        D: Decode<()> + Encode + Send + 'static,
1041    {
1042        let key = std::any::type_name::<D>();
1043
1044        let mut stored_guard = STORED.lock().unwrap_or_else(|err| err.into_inner());
1045        let stored = stored_guard.as_mut().unwrap();
1046
1047        let entry = stored.get_mut(key)?;
1048
1049        let values: &mut PartiallyDecodedValues<D> = match entry {
1050            MaybeTypedValues::NotTyped(list_of_bytes) => {
1051                *entry = MaybeTypedValues::typed(PartiallyDecodedValues::<D> {
1052                    encoded: Mutex::new(Cursor::new(std::mem::take(list_of_bytes))),
1053                    decoded: Vec::new(),
1054                });
1055
1056                let MaybeTypedValues::Typed(values, _) = entry else {
1057                    unreachable!();
1058                };
1059
1060                values.downcast_mut().unwrap()
1061            }
1062            MaybeTypedValues::Typed(values, _) => values.downcast_mut().unwrap(),
1063        };
1064
1065        if let Some(value) = values.decoded.extract_if(.., |value| pred(value)).next() {
1066            Some(value)
1067        } else {
1068            let mut encoded = encoded(&values.encoded);
1069            let iter = std::iter::from_fn(|| {
1070                while encoded.get_ref().len() - encoded.position() as usize > 0 {
1071                    if let Ok(value) =
1072                        bincode::decode_from_std_read(&mut *encoded, config::standard())
1073                    {
1074                        return Some(value);
1075                    }
1076                }
1077
1078                None
1079            });
1080
1081            for value in iter {
1082                if pred(&value) {
1083                    return Some(value);
1084                } else {
1085                    values.decoded.push(value);
1086                }
1087            }
1088
1089            None
1090        }
1091    }
1092
1093    /// Take the stored structs for retrieval on a future reload.
1094    pub(crate) fn get_structs() -> HashMap<String, MaybeTypedValues> {
1095        let mut stored_guard = STORED.lock().unwrap_or_else(|err| err.into_inner());
1096        let mut stored = stored_guard.take().unwrap();
1097        stored.retain(|_, maybe_typed| {
1098            if let MaybeTypedValues::Typed(values, to_bytes) = maybe_typed {
1099                let values = to_bytes(values.as_mut());
1100                if values.is_empty() {
1101                    false
1102                } else {
1103                    *maybe_typed = MaybeTypedValues::NotTyped(values);
1104                    true
1105                }
1106            } else {
1107                true
1108            }
1109        });
1110
1111        stored
1112    }
1113
1114    /// A possibly typed list of stored values.
1115    #[doc(hidden)]
1116    pub enum MaybeTypedValues {
1117        NotTyped(Vec<u8>),
1118        Typed(
1119            Box<dyn std::any::Any + Send>,
1120            fn(&(dyn std::any::Any + Send)) -> Vec<u8>,
1121        ),
1122    }
1123
1124    impl MaybeTypedValues {
1125        fn typed<E: Encode + Send + 'static>(values: PartiallyDecodedValues<E>) -> Self {
1126            Self::Typed(Box::new(values), |values| {
1127                let values: &PartiallyDecodedValues<E> = values.downcast_ref().unwrap();
1128                let mut encoded = encoded(&values.encoded);
1129
1130                for value in values.decoded.iter() {
1131                    _ = bincode::encode_into_std_write(
1132                        value,
1133                        encoded.get_mut(),
1134                        config::standard(),
1135                    );
1136                }
1137
1138                let position = encoded.position();
1139                encoded.get_ref()[position as usize..].to_vec()
1140            })
1141        }
1142    }
1143
1144    impl std::fmt::Debug for MaybeTypedValues {
1145        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1146            match self {
1147                Self::NotTyped(arg0) => f.debug_tuple("NotTyped").field(arg0).finish(),
1148                Self::Typed(..) => f.debug_tuple("Typed").finish_non_exhaustive(),
1149            }
1150        }
1151    }
1152
1153    impl<Context> Decode<Context> for MaybeTypedValues {
1154        fn decode<D: bincode::de::Decoder<Context = Context>>(
1155            decoder: &mut D,
1156        ) -> Result<Self, bincode::error::DecodeError> {
1157            Ok(Self::NotTyped(Decode::decode(decoder)?))
1158        }
1159    }
1160
1161    impl<'de, Context> BorrowDecode<'de, Context> for MaybeTypedValues {
1162        fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
1163            decoder: &mut D,
1164        ) -> Result<Self, bincode::error::DecodeError> {
1165            Ok(Self::NotTyped(Decode::decode(decoder)?))
1166        }
1167    }
1168
1169    impl Encode for MaybeTypedValues {
1170        fn encode<E: bincode::enc::Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
1171            match self {
1172                MaybeTypedValues::NotTyped(list_of_bytes) => {
1173                    Encode::encode(&list_of_bytes, encoder)
1174                }
1175                MaybeTypedValues::Typed(any, get_list_of_bytes) => {
1176                    Encode::encode(&get_list_of_bytes(any.as_ref()), encoder)
1177                }
1178            }
1179        }
1180    }
1181
1182    struct PartiallyDecodedValues<T> {
1183        encoded: Mutex<Cursor<Vec<u8>>>,
1184        decoded: Vec<T>,
1185    }
1186
1187    /// Set the initial list of stored structs.
1188    pub(crate) fn set_structs(structs: HashMap<String, MaybeTypedValues>) {
1189        *STORED.lock().unwrap() = Some(structs);
1190    }
1191
1192    /// Get the encoded [`Cursor`] bytes.
1193    fn encoded(encoded: &Mutex<Cursor<Vec<u8>>>) -> std::sync::MutexGuard<'_, Cursor<Vec<u8>>> {
1194        encoded.lock().unwrap_or_else(|err| err.into_inner())
1195    }
1196}
1197
1198////////// Text Builder macros (for pub/private bending)
1199#[doc(hidden)]
1200pub mod private_exports {
1201    pub use format_like::format_like;
1202}
1203
1204/// Converts a string to a valid priority
1205#[doc(hidden)]
1206pub const fn priority(priority: &str) -> u8 {
1207    let mut bytes = priority.as_bytes();
1208    let mut val = 0;
1209
1210    while let [byte, rest @ ..] = bytes {
1211        assert!(b'0' <= *byte && *byte <= b'9', "invalid digit");
1212        val = val * 10 + (*byte - b'0') as usize;
1213        bytes = rest;
1214    }
1215
1216    assert!(val <= 240, "priority cannot exceed 240");
1217
1218    val as u8
1219}
1220
1221/// Tries to evaluate a block that returns [`Result<T, Text>`]
1222///
1223/// If the block returns [`Ok`], this macro will resolve to `T`. If it
1224/// returns [`Err`], it will log the error with [`context::error!`],
1225/// then it will return from the function. As an example, this:
1226///
1227/// ```rust
1228/// # duat_core::doc_duat!(duat);
1229/// # fn test() {
1230/// use duat::prelude::*;
1231///
1232/// let ret = try_or_log_err! {
1233///     let value = result_fn()?;
1234///     value
1235/// };
1236///
1237/// fn result_fn() -> Result<usize, Text> {
1238///     Err(txt!(":("))
1239/// }
1240/// # }
1241/// ```
1242///
1243/// Will expand into:
1244///
1245/// ```rust
1246/// # duat_core::doc_duat!(duat);
1247/// # fn test() {
1248/// use duat::prelude::*;
1249///
1250/// let ret = match (|| -> Result<_, Text> { Ok(result_fn()?) })() {
1251///     Ok(ret) => ret,
1252///     Err(err) => {
1253///         context::error!("{err}");
1254///         return;
1255///     }
1256/// };
1257///
1258/// fn result_fn() -> Result<usize, Text> {
1259///     Err(txt!(":("))
1260/// }
1261/// # }
1262/// ```
1263///
1264/// Note the [`Ok`] wrapping the tokens, so it works like the `try`
1265/// keyword in that regard.
1266#[macro_export]
1267macro_rules! try_or_log_err {
1268    { $($tokens:tt)* } => {
1269        match (|| -> Result<_, $crate::text::Text> { Ok({ $($tokens)* }) })() {
1270             Ok(ret) => ret,
1271             Err(err) => {
1272                 $crate::context::error!("{err}");
1273                 return;
1274             }
1275        }
1276    }
1277}