Skip to main content

duat_core/buffer/
mod.rs

1//! The primary [`Widget`] of Duat, used to display buffers.
2//!
3//! Most extensible features of Duat have the primary purpose of
4//! serving the [`Buffer`], such as multiple [`Cursor`]s, a
5//! `History` system, [`RawArea::PrintInfo`], etc.
6//!
7//! The [`Buffer`] also provides a list of printed lines through the
8//! [`Handle::printed_lines`] method. This method is notably used by
9//! the [`LineNumbers`] widget, that shows the numbers of the
10//! currently printed lines.
11//!
12//! [`LineNumbers`]: https://docs.rs/duat/latest/duat/widgets/struct.LineNumbers.html
13//! [`Cursor`]: crate::mode::Cursor
14//! [`RawArea::PrintInfo`]: crate::ui::traits::RawArea::PrintInfo
15use std::{
16    collections::HashMap,
17    fs,
18    ops::Range,
19    path::{Path, PathBuf},
20    sync::{LazyLock, Mutex, MutexGuard},
21};
22
23use crossterm::event::{MouseButton, MouseEventKind};
24
25pub use crate::buffer::{
26    buffer_id::BufferId,
27    history::{Change, Changes, History, Moment, RangesToUpdate},
28    opts::BufferOpts,
29};
30use crate::{
31    context::{self, Handle, cache},
32    data::{Pass, RwData, WriteableTuple},
33    hook::{self, BufferSaved, BufferUpdated, OnMouseEvent},
34    mode::{Cursor, Selections, TwoPointsPlace},
35    opts::PrintOpts,
36    text::{Point, Strs, StrsBuf, Text, TextMut, TextParts, TextVersion, txt},
37    ui::{Area, Coord, PrintInfo, PrintedLine, Widget},
38};
39
40mod history;
41mod opts;
42
43pub(crate) fn add_buffer_hooks() {
44    hook::add::<OnMouseEvent<Buffer>>(|pa, event| match event.kind {
45        MouseEventKind::Down(MouseButton::Left) => {
46            let point = match event.points {
47                Some(TwoPointsPlace::Within(points) | TwoPointsPlace::AheadOf(points)) => {
48                    points.real
49                }
50                _ => event.handle.text(pa).last_point(),
51            };
52
53            event.handle.selections_mut(pa).remove_extras();
54            event.handle.edit_main(pa, |mut c| {
55                c.unset_anchor();
56                c.move_to(point)
57            })
58        }
59        MouseEventKind::Down(_) => {}
60        MouseEventKind::Up(_) => {}
61        MouseEventKind::Drag(MouseButton::Left) => {
62            let point = match event.points {
63                Some(TwoPointsPlace::Within(points) | TwoPointsPlace::AheadOf(points)) => {
64                    points.real
65                }
66                _ => event.handle.text(pa).last_point(),
67            };
68
69            event.handle.selections_mut(pa).remove_extras();
70            event.handle.edit_main(pa, |mut c| {
71                c.set_anchor_if_needed();
72                c.move_to(point);
73            })
74        }
75        MouseEventKind::Drag(_) => {}
76        MouseEventKind::Moved => {}
77        MouseEventKind::ScrollDown => {
78            let opts = event.handle.opts(pa);
79            let (widget, area) = event.handle.write_with_area(pa);
80            area.scroll_ver(widget.text(), 3, opts);
81        }
82        MouseEventKind::ScrollUp => {
83            let opts = event.handle.opts(pa);
84            let (widget, area) = event.handle.write_with_area(pa);
85            area.scroll_ver(widget.text(), -3, opts);
86        }
87        MouseEventKind::ScrollLeft => {}
88        MouseEventKind::ScrollRight => {}
89    });
90}
91
92/// The widget that is used to print and edit buffers.
93pub struct Buffer {
94    id: BufferId,
95    path: PathKind,
96    text: Text,
97    pub(crate) layout_order: usize,
98    history: History,
99    cached_print_info: Mutex<Option<CachedPrintInfo>>,
100    /// The [`PrintOpts`] of this `Buffer`.
101    ///
102    /// This object, much like `PrintOpts`, implements [`Copy`], which
103    /// makes it convenient for moving it around without borrowing the
104    /// `Buffer`.
105    ///
106    /// You can use this member to change the way this `Buffer` will
107    /// be printed specifically.
108    pub opts: BufferOpts,
109    prev_opts: Mutex<PrintOpts>,
110    was_reloaded: bool,
111}
112
113impl Buffer {
114    /// Returns a new [`Buffer`], private for now.
115    pub(crate) fn new(path: Option<PathBuf>, opts: BufferOpts) -> Self {
116        let (text, path) = match path {
117            Some(path) => {
118                let canon_path = path.canonicalize();
119                if let Ok(path) = &canon_path
120                    && let Ok(buffer) = std::fs::read_to_string(path)
121                {
122                    let selections = {
123                        let selection = cache::load(path).unwrap_or_default();
124                        Selections::new(selection)
125                    };
126                    let text = Text::from_parts(StrsBuf::new(buffer), selections);
127                    (text, PathKind::SetExists(path.clone()))
128                } else if canon_path.is_err()
129                    && let Ok(mut canon_path) = path.with_file_name(".").canonicalize()
130                {
131                    canon_path.push(path.file_name().unwrap());
132                    (
133                        Text::with_default_main_selection(),
134                        PathKind::SetAbsent(canon_path),
135                    )
136                } else {
137                    (Text::with_default_main_selection(), PathKind::new_unset())
138                }
139            }
140            None => (Text::with_default_main_selection(), PathKind::new_unset()),
141        };
142
143        let history = History::new(&text);
144
145        Self {
146            id: BufferId::new(),
147            path,
148            text,
149            layout_order: 0,
150            history,
151            cached_print_info: Mutex::new(None),
152            opts,
153            prev_opts: Mutex::new(opts.to_print_opts()),
154            was_reloaded: false,
155        }
156    }
157
158    /// Returns a new `Buffer` from its reloaded raw parts.
159    pub(crate) fn from_raw_parts(
160        buf: StrsBuf,
161        selections: Selections,
162        history: History,
163        path: PathKind,
164        opts: BufferOpts,
165        layout_order: usize,
166        was_reloaded: bool,
167    ) -> Buffer {
168        Self {
169            id: BufferId::new(),
170            path,
171            text: Text::from_parts(buf, selections),
172            layout_order,
173            history,
174            cached_print_info: Mutex::new(None),
175            opts,
176            prev_opts: Mutex::new(opts.to_print_opts()),
177            was_reloaded,
178        }
179    }
180
181    ////////// Path querying functions
182
183    /// The full path of the buffer.
184    ///
185    /// If there is no set path, returns `"*scratch buffer*#{id}"`.
186    pub fn path(&self) -> PathBuf {
187        self.path.path()
188    }
189
190    /// The full path of the buffer.
191    ///
192    /// Returns [`None`] if the path has not been set yet, i.e., if
193    /// the buffer is a scratch buffer.
194    pub fn path_set(&self) -> Option<PathBuf> {
195        self.path.path_set()
196    }
197
198    /// A [`Text`] from the full path of this [`PathKind`]
199    ///
200    /// # Formatting
201    ///
202    /// If the buffer's `path` was set:
203    ///
204    /// ```text
205    /// [buffer]{path}
206    /// ```
207    ///
208    /// If the buffer's `path` was not set:
209    ///
210    /// ```text
211    /// [buffer.new.scratch]*scratch buffer #{id}*
212    /// ```
213    pub fn path_txt(&self) -> Text {
214        self.path_kind().path_txt()
215    }
216
217    /// The buffer's name.
218    ///
219    /// If there is no set path, returns `"*scratch buffer #{id}*"`.
220    pub fn name(&self) -> String {
221        self.path.name()
222    }
223
224    /// The buffer's name.
225    ///
226    /// Returns [`None`] if the path has not been set yet, i.e., if
227    /// the buffer is a scratch buffer.
228    pub fn name_set(&self) -> Option<String> {
229        self.path.name_set()
230    }
231
232    /// A [`Text`] from the name of this [`PathKind`]
233    ///
234    /// The name of a [`Buffer`] widget is the same as the path, but
235    /// it strips away the current directory. If it can't, it will
236    /// try to strip away the home directory, replacing it with
237    /// `"~"`. If that also fails, it will just show the full
238    /// path.
239    ///
240    /// # Formatting
241    ///
242    /// If the buffer's `name` was set:
243    ///
244    /// ```text
245    /// [buffer]{name}
246    /// ```
247    ///
248    /// If the buffer's `name` was not set:
249    ///
250    /// ```text
251    /// [buffer.new.scratch]*scratch buffer #{id}*
252    /// ```
253    pub fn name_txt(&self) -> Text {
254        self.path.name_txt()
255    }
256
257    /// The type of [`PathBuf`]
258    ///
259    /// This represents the three possible states for a `Buffer`'s
260    /// `PathBuf`, as it could either represent a real `Buffer`,
261    /// not exist, or not have been defined yet.
262    pub fn path_kind(&self) -> PathKind {
263        self.path.clone()
264    }
265
266    ////////// Auxiliatory methods for incremental parsing
267
268    /// Resets the print info if deemed necessary, returning the final
269    /// result, as well as `true` if things have changed
270    ///
271    /// After calling this, `self.cached_print_info` is guaranteed to
272    /// be [`Some`]
273    fn reset_print_info_if_needed<'b>(
274        &'b self,
275        area: &Area,
276    ) -> MutexGuard<'b, Option<CachedPrintInfo>> {
277        let opts_changed = {
278            let mut prev_opts = self.prev_opts.lock().unwrap();
279            let cur_opts = self.opts.to_print_opts();
280            let opts_changed = *prev_opts != cur_opts;
281            *prev_opts = cur_opts;
282            opts_changed
283        };
284
285        let mut cached_print_info = self.cached_print_info.lock().unwrap();
286        if opts_changed
287            || cached_print_info.as_ref().is_none_or(|cpi| {
288                self.text
289                    .version()
290                    .has_structurally_changed_since(cpi.text_state)
291                    || area.get_print_info() != cpi.area_print_info
292                    || area.top_left() != cpi.coords.0
293                    || area.bottom_right() != cpi.coords.1
294            })
295        {
296            let opts = self.opts.to_print_opts();
297            let start = area.start_points(&self.text, opts).real;
298            let end = area.end_points(&self.text, opts).real;
299            let printed_line_numbers = area.get_printed_lines(&self.text, opts).unwrap();
300
301            *cached_print_info = Some(CachedPrintInfo {
302                range: start..end,
303                printed_line_numbers,
304                printed_line_ranges: None,
305                _visible_line_ranges: None,
306                text_state: self.text.version(),
307                area_print_info: area.get_print_info(),
308                coords: (area.top_left(), area.bottom_right()),
309            });
310        } else {
311            cached_print_info.as_mut().unwrap().text_state = self.text.version();
312        };
313
314        cached_print_info
315    }
316
317    ////////// General querying functions
318
319    /// A unique identifier for this `Buffer`.
320    ///
321    /// This is more robust than identifying it by its path or name,
322    /// or event [`PathKind`], since those could change, but this
323    /// cannot.
324    pub fn buffer_id(&self) -> BufferId {
325        self.id
326    }
327
328    /// The [`Text`] of this `Buffer`
329    ///
330    /// This is the same as [`Widget::text`], but doesn't need the
331    /// [`Widget`] trait to be in scope.
332    pub fn text(&self) -> &Text {
333        &self.text
334    }
335
336    /// The mutable [`TextMut`] of this `Buffer`
337    ///
338    /// This is the same as [`Widget::text_mut`], but doesn't need the
339    /// [`Widget`] trait to be in scope.
340    pub fn text_mut(&mut self) -> TextMut<'_> {
341        self.text.as_mut()
342    }
343
344    /// The parts that make up a [`Text`].
345    ///
346    /// This function is used when you want to [insert]/[remove]
347    /// [`Tag`]s (i.e., borrow the inner `InnerTags` mutably via
348    /// [`Tags`]), while still being able to read from the
349    /// [`Strs`] and [`Selections`].
350    ///
351    /// [insert]: crate::text::Tags::insert
352    /// [remove]: crate::text::Tags::remove
353    /// [`Tag`]: crate::text::Tag
354    /// [`Tags`]: crate::text::Tags
355    pub fn text_parts(&mut self) -> TextParts<'_> {
356        self.text.parts()
357    }
358
359    /// The number of bytes in the buffer.
360    pub fn len_bytes(&self) -> usize {
361        self.text.len()
362    }
363
364    /// The number of [`char`]s in the buffer.
365    pub fn len_chars(&self) -> usize {
366        self.text.end_point().char()
367    }
368
369    /// The number of lines in the buffer.
370    pub fn len_lines(&self) -> usize {
371        self.text.end_point().line()
372    }
373
374    /// The [`Selections`] that are used on the [`Text`].
375    pub fn selections(&self) -> &Selections {
376        self.text.selections()
377    }
378
379    /// A mutable reference to the [`Selections`].
380    pub fn selections_mut(&mut self) -> &mut Selections {
381        self.text.selections_mut()
382    }
383
384    /// Whether o not the [`Buffer`] exists or not.
385    pub fn exists(&self) -> bool {
386        self.path_set()
387            .is_some_and(|p| std::fs::exists(PathBuf::from(&p)).is_ok_and(|e| e))
388    }
389
390    /// Wether this buffer came from a previous reload cycle.
391    ///
392    /// You should use this function to decide on things that persist
393    /// across reload cycles (i.e. the [`crate::process`] and
394    /// [`crate::storage`] modules).
395    pub fn was_reloaded(&self) -> bool {
396        self.was_reloaded
397    }
398
399    /// Prepare this `Buffer` for reloading.
400    ///
401    /// This works by creating a new [`Buffer`], which will take
402    /// ownership of a stripped down version of this one's [`Text`]
403    pub(crate) fn take_reload_parts(&mut self) -> (StrsBuf, Selections, History) {
404        self.text.prepare_for_reloading();
405        let (strs_buf, selections) = self.text.take_reload_parts();
406        (
407            strs_buf,
408            selections,
409            std::mem::replace(&mut self.history, History::new(&self.text)),
410        )
411    }
412
413    /// The update function for [`Buffer`]s.
414    pub(crate) fn update(pa: &mut Pass, handle: &Handle<Self>) {
415        // Asynchronous updating of opts
416        let (buffer, area) = handle.write_with_area(pa);
417
418        if let Some(main) = buffer.text().get_main_sel() {
419            area.scroll_around_points(
420                buffer.text(),
421                main.caret().to_two_points_after(),
422                buffer.print_opts(),
423            );
424        }
425
426        drop(buffer.reset_print_info_if_needed(area));
427
428        hook::trigger(pa, BufferUpdated(handle.clone()));
429
430        handle.text_mut(pa).update_bounds();
431    }
432}
433
434impl Widget for Buffer {
435    fn text(&self) -> &Text {
436        &self.text
437    }
438
439    fn text_mut(&mut self) -> TextMut<'_> {
440        let mut text_mut = self.text.as_mut();
441        text_mut.attach_history(&mut self.history);
442        text_mut
443    }
444
445    fn print_opts(&self) -> PrintOpts {
446        self.opts.to_print_opts()
447    }
448}
449
450impl Handle {
451    /// Writes the buffer to the current [`PathBuf`], if one was set.
452    pub fn save(&self, pa: &mut Pass) -> Result<bool, Text> {
453        self.save_quit(pa, false)
454    }
455
456    /// Saves and quits, resulting in no config reload.
457    ///
458    /// Returns `Ok(true)` if it saved, `Ok(false)` if that wasn't
459    /// necessary, and `Err` if there was some problem.
460    pub(crate) fn save_quit(&self, pa: &mut Pass, quit: bool) -> Result<bool, Text> {
461        let buf = self.write(pa);
462
463        if let PathKind::SetExists(path) | PathKind::SetAbsent(path) = &buf.path {
464            let path = path.clone();
465            if buf.text.has_unsaved_changes() {
466                crate::notify::set_next_write_as_from_duat(path.clone());
467
468                let file = match std::fs::File::create(&path) {
469                    Ok(file) => file,
470                    Err(err) => {
471                        crate::notify::unset_next_write_as_from_duat(path.clone());
472                        return Err(err.into());
473                    }
474                };
475
476                if let Err(err) = buf
477                    .text
478                    .save_on(std::io::BufWriter::new(file))
479                    .inspect(|_| buf.path = PathKind::SetExists(path.clone()))
480                {
481                    crate::notify::unset_next_write_as_from_duat(path.clone());
482                    return Err(err.into());
483                }
484
485                hook::trigger(pa, BufferSaved((self.clone(), quit)));
486
487                Ok(true)
488            } else {
489                Ok(false)
490            }
491        } else {
492            Err(txt!("No buffer was set"))
493        }
494    }
495
496    /// Writes the buffer to the given [`Path`].
497    ///
498    /// [`Path`]: std::path::Path
499    pub fn save_to(
500        &self,
501        pa: &mut Pass,
502        path: impl AsRef<std::path::Path>,
503    ) -> std::io::Result<bool> {
504        self.save_quit_to(pa, path, false)
505    }
506
507    /// Writes the buffer to the given [`Path`].
508    ///
509    /// [`Path`]: std::path::Path
510    pub(crate) fn save_quit_to(
511        &self,
512        pa: &mut Pass,
513        path: impl AsRef<std::path::Path>,
514        quit: bool,
515    ) -> std::io::Result<bool> {
516        let buf = self.write(pa);
517
518        if buf.text.has_unsaved_changes() {
519            let path = path.as_ref();
520            let res = buf
521                .text
522                .save_on(std::io::BufWriter::new(fs::File::create(path)?));
523            buf.history.declare_saved();
524
525            if res.as_ref().is_ok() {
526                hook::trigger(pa, BufferSaved((self.clone(), quit)));
527            }
528
529            res.and(Ok(true))
530        } else {
531            Ok(false)
532        }
533    }
534
535    /// Returns the list of printed line numbers.
536    ///
537    /// These are returned as a `usize`, showing the index of the line
538    /// in the buffer, and a `bool`, which is `true` when the line is
539    /// wrapped.
540    ///
541    /// If you want the actual content of these lines (as [`Strs`]s),
542    /// check out [`Handle::printed_lines`]. If you want the content
543    /// of only the _visible_ portion of these lines, check out
544    /// [`Handle::visible_lines`].
545    #[track_caller]
546    pub fn printed_line_numbers(&self, pa: &Pass) -> Vec<PrintedLine> {
547        let buffer = self.read(pa);
548        let cpi = buffer.reset_print_info_if_needed(self.area().read(pa));
549        cpi.as_ref().unwrap().printed_line_numbers.clone()
550    }
551
552    /// The printed [`Range<Point>`], from the top of the screen to
553    /// the bottom.
554    ///
555    /// Do note that this includes all concealed lines and parts that
556    /// are out of screen. If you want only to include partially
557    /// visible lines, while excluding fully hidden ones, check out
558    /// [`Handle::printed_lines`]. If you want to exclude every
559    /// concealed or out of screen section, check out
560    /// [`Handle::visible_lines`].
561    pub fn full_printed_range(&self, pa: &Pass) -> Range<Point> {
562        let buffer = self.read(pa);
563        let cpi = buffer.reset_print_info_if_needed(self.area().read(pa));
564        cpi.as_ref().unwrap().range.clone()
565    }
566
567    /// Returns the list of printed lines.
568    ///
569    /// These are returned as [`Strs`], which are duat's equivalent of
570    /// [`str`] for the [`Text`] struct.
571    ///
572    /// Note that this function returns all portions of printed lines,
573    /// not just those that are visible. This means that it will also
574    /// include partially [concealed] lines and parts of the line that
575    /// are out of screen.
576    ///
577    /// If you want a list of _only_ the visible sections, check out
578    /// [`Handle::visible_lines`].
579    ///
580    /// If you want a [`Range<Point>`] of the printed section of the
581    /// [`Text`] (including concealed lines), check out
582    /// [`Handle::full_printed_range`].
583    ///
584    /// If you just want the line numbers of the printed lines, check
585    /// out [`Handle::printed_line_numbers`].
586    ///
587    /// [concealed]: crate::text::Conceal
588    pub fn printed_lines<'b>(&'b self, pa: &'b Pass) -> Vec<&'b Strs> {
589        let buffer = self.read(pa);
590        let mut cpi = buffer.reset_print_info_if_needed(self.area().read(pa));
591        let cpi = cpi.as_mut().unwrap();
592        let lines = &cpi.printed_line_numbers;
593
594        let printed_lines = if let Some(printed_lines) = &cpi.printed_line_ranges {
595            printed_lines
596        } else {
597            let mut last = None;
598            cpi.printed_line_ranges.insert(
599                lines
600                    .iter()
601                    .filter(|line| {
602                        last.as_mut()
603                            .is_none_or(|num| std::mem::replace(num, line.number) < line.number)
604                    })
605                    .map(|line| buffer.text.line(line.number).range())
606                    .collect(),
607            )
608        };
609
610        printed_lines
611            .iter()
612            .map(|range| &buffer.text[range.clone()])
613            .collect()
614    }
615
616    /// A list of [`Range<usize>`]s for the byte ranges of each
617    /// printed line.
618    ///
619    /// This is just a shorthand for calling [`Handle::printed_lines`]
620    /// and mapping each one via [`Strs::byte_range`].
621    pub fn printed_line_ranges(&self, pa: &Pass) -> Vec<Range<usize>> {
622        let lines = self.printed_lines(pa);
623        lines.into_iter().map(|line| line.byte_range()).collect()
624    }
625
626    /// Only the visible parts of printed lines.
627    ///
628    /// This is just like [`Handle::printed_lines`], but excludes
629    /// _every_ section that was concealed or is not visible on
630    /// screen.
631    pub fn visible_lines<'b>(&'b self, _: &'b Pass) -> Vec<&'b Strs> {
632        todo!();
633    }
634}
635
636/// Represents the presence or absence of a path.
637#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, bincode::Decode, bincode::Encode)]
638pub enum PathKind {
639    /// A [`PathBuf`] that has been defined and points to a real
640    /// buffer.
641    SetExists(PathBuf),
642    /// A [`PathBuf`] that has been defined but isn't a real buffer.
643    SetAbsent(PathBuf),
644    /// A [`PathBuf`] that has not been defined.
645    ///
646    /// The number within represents a specific [`Buffer`], and when
647    /// printed to, for example, the [`StatusLine`], would show up as
648    /// `txt!("[buffer]*scratch buffer*#{id}")`
649    ///
650    /// [`StatusLine`]: https://docs.rs/duat/latest/duat/widgets/struct.StatusLine.html
651    NotSet(usize),
652}
653
654impl PathKind {
655    /// Returns a new unset [`PathBuf`].
656    pub(crate) fn new_unset() -> PathKind {
657        use std::sync::atomic::{AtomicUsize, Ordering};
658        static UNSET_COUNT: AtomicUsize = AtomicUsize::new(1);
659
660        PathKind::NotSet(UNSET_COUNT.fetch_add(1, Ordering::Relaxed))
661    }
662
663    /// Returns a [`PathBuf`] if `self` is [`SetExists`] or
664    /// [`SetAbsent`].
665    ///
666    /// [`SetExists`]: PathKind::SetExists
667    /// [`SetAbsent`]: PathKind::SetAbsent
668    pub fn as_path(&self) -> Option<PathBuf> {
669        match self {
670            PathKind::SetExists(path) | PathKind::SetAbsent(path) => Some(path.clone()),
671            PathKind::NotSet(_) => None,
672        }
673    }
674
675    /// The full path of the buffer.
676    ///
677    /// If there is no set path, returns `"*scratch buffer*#{id}"`.
678    pub fn path(&self) -> PathBuf {
679        match self {
680            PathKind::SetExists(path) | PathKind::SetAbsent(path) => path.clone(),
681            PathKind::NotSet(id) => PathBuf::from(format!("*scratch buffer*#{id}")),
682        }
683    }
684
685    /// The full path of the buffer.
686    ///
687    /// Returns [`None`] if the path has not been set yet.
688    pub fn path_set(&self) -> Option<PathBuf> {
689        match self {
690            PathKind::SetExists(path) | PathKind::SetAbsent(path) => Some(path.clone()),
691            PathKind::NotSet(_) => None,
692        }
693    }
694
695    /// The buffer's name.
696    ///
697    /// If there is no set path, returns `"*scratch buffer #{id}*"`.
698    pub fn name(&self) -> String {
699        match self {
700            PathKind::SetExists(path) | PathKind::SetAbsent(path) => {
701                let cur_dir = context::current_dir();
702                if let Ok(path) = path.strip_prefix(cur_dir) {
703                    path.to_string_lossy().to_string()
704                } else if let Some(home_dir) = dirs_next::home_dir()
705                    && let Ok(path) = path.strip_prefix(home_dir)
706                {
707                    Path::new("~").join(path).to_string_lossy().to_string()
708                } else {
709                    path.to_string_lossy().to_string()
710                }
711            }
712            PathKind::NotSet(id) => format!("*scratch buffer #{id}*"),
713        }
714    }
715
716    /// The buffer's name.
717    ///
718    /// Returns [`None`] if the path has not been set yet.
719    pub fn name_set(&self) -> Option<String> {
720        match self {
721            PathKind::SetExists(path) | PathKind::SetAbsent(path) => {
722                let cur_dir = context::current_dir();
723                Some(if let Ok(path) = path.strip_prefix(cur_dir) {
724                    path.to_string_lossy().to_string()
725                } else if let Some(home_dir) = dirs_next::home_dir()
726                    && let Ok(path) = path.strip_prefix(home_dir)
727                {
728                    Path::new("~").join(path).to_string_lossy().to_string()
729                } else {
730                    path.to_string_lossy().to_string()
731                })
732            }
733            PathKind::NotSet(_) => None,
734        }
735    }
736
737    /// A [`Text`] from the full path of this [`PathKind`].
738    ///
739    /// # Formatting
740    ///
741    /// If the buffer's `path` was set:
742    ///
743    /// ```text
744    /// [buffer]{path}
745    /// ```
746    ///
747    /// If the buffer's `path` was not set:
748    ///
749    /// ```text
750    /// [buffer.new.scratch]*scratch buffer #{id}*
751    /// ```
752    pub fn path_txt(&self) -> Text {
753        match self {
754            PathKind::SetExists(path) | PathKind::SetAbsent(path) => txt!("[buffer]{path}"),
755            PathKind::NotSet(id) => txt!("[buffer.new.scratch]*scratch buffer #{id}*"),
756        }
757    }
758
759    /// A [`Text`] from the name of this `PathKind`.
760    ///
761    /// The name of a [`Buffer`] widget is the same as the path, but
762    /// it strips away the current directory. If it can't, it will
763    /// try to strip away the home directory, replacing it with `"~"`.
764    /// If that also fails, it will just show the full path.
765    ///
766    /// # Formatting
767    ///
768    /// If the buffer's `name` was set:
769    ///
770    /// ```text
771    /// [buffer]{name}
772    /// ```
773    ///
774    /// If the buffer's `name` was not set:
775    ///
776    /// ```text
777    /// [buffer.new.scratch]*scratch buffer #{id}*
778    /// ```
779    pub fn name_txt(&self) -> Text {
780        match self {
781            PathKind::SetExists(path) | PathKind::SetAbsent(path) => {
782                let cur_dir = context::current_dir();
783                if let Ok(path) = path.strip_prefix(cur_dir) {
784                    txt!("[buffer]{path}")
785                } else if let Some(home_dir) = dirs_next::home_dir()
786                    && let Ok(path) = path.strip_prefix(home_dir)
787                {
788                    txt!("[buffer]{}", Path::new("~").join(path))
789                } else {
790                    txt!("[buffer]{path}")
791                }
792            }
793            PathKind::NotSet(id) => txt!("[buffer.new.scratch]*scratch buffer #{id}*"),
794        }
795    }
796}
797
798impl<P: AsRef<Path>> From<P> for PathKind {
799    fn from(value: P) -> Self {
800        let path = value.as_ref();
801        if let Ok(true) = path.try_exists() {
802            PathKind::SetExists(path.into())
803        } else {
804            PathKind::SetAbsent(path.into())
805        }
806    }
807}
808
809/// Cached information about the printing of this [`Buffer`]
810struct CachedPrintInfo {
811    range: Range<Point>,
812    printed_line_numbers: Vec<PrintedLine>,
813    printed_line_ranges: Option<Vec<Range<Point>>>,
814    _visible_line_ranges: Option<Vec<Range<Point>>>,
815    text_state: TextVersion,
816    area_print_info: PrintInfo,
817    coords: (Coord, Coord),
818}
819
820mod buffer_id {
821    use std::sync::atomic::{AtomicUsize, Ordering};
822
823    static COUNT: AtomicUsize = AtomicUsize::new(0);
824
825    /// A unique identifier for a [`Buffer`].
826    ///
827    /// [`Buffer`]: super::Buffer
828    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
829    pub struct BufferId(usize);
830
831    impl BufferId {
832        /// Returns a new `BufferId`, uniquely identifying a
833        /// [`Buffer`].
834        ///
835        /// [`Buffer`]: super::Buffer
836        pub(super) fn new() -> Self {
837            Self(COUNT.fetch_add(1, Ordering::Relaxed))
838        }
839    }
840}
841
842/// A struct to associate one `T` to each [`Buffer`].
843///
844/// This is very useful to implement the "parser pattern", where you
845/// have one parser per `Buffer`, acting on changes that take place on
846/// each `Buffer`.
847pub struct PerBuffer<T: 'static>(LazyLock<RwData<HashMap<BufferId, T>>>);
848
849impl<T: 'static> PerBuffer<T> {
850    /// Returns a new mapping of [`Buffer`]s to a type `T`.
851    ///
852    /// Since this function is `const`, you can conveniently place it
853    /// in a `static` variable, in order to record one `T` for every
854    /// `Buffer` that you want to associate the struct to.
855    ///
856    /// This is very useful in order to create the "parser pattern" on
857    /// a number of different `Buffer`s, letting you store things and
858    /// retrieve them as needed.
859    ///
860    /// # Note
861    ///
862    /// This function will _not_ automatically add new [`Buffer`]s to
863    /// the list. To do that, you should add a [hook] on [`Buffer`],
864    /// that calls [`PerBuffer::register`].
865    ///
866    /// Additionally, you will probably also want to setup a hook
867    /// that calls [`PerBuffer::unregister`] on [`BufferClosed`]
868    ///
869    /// [`BufferClosed`]: crate::hook::BufferClosed
870    pub const fn new() -> Self {
871        Self(LazyLock::new(RwData::default))
872    }
873
874    /// Register a [`Buffer`] with an initial value of `T`.
875    ///
876    /// If there was a previous version of `T` assoiated with the
877    /// `Buffer`, then the new `T` will replace that old version.
878    ///
879    /// You should most likely call this function on the
880    /// [`WidgetOpened<Buffer>`] hook, often aliased to just
881    /// `Buffer`.
882    ///
883    /// [`WidgetOpened<Buffer>`]: crate::hook::WidgetOpened
884    pub fn register<'p>(
885        &'p self,
886        pa: &'p mut Pass,
887        handle: &'p Handle,
888        new_value: T,
889    ) -> (&'p mut T, &'p mut Buffer) {
890        let (list, buf) = pa.write_many((&*self.0, handle));
891
892        let entry = list.entry(buf.buffer_id()).insert_entry(new_value);
893
894        (entry.into_mut(), buf)
895    }
896
897    /// Unregisters a [`Buffer`].
898    ///
899    /// This will remove the `Buffer` from the list, making future
900    /// calls to [`Self::write`] return [`None`]. You should consider
901    /// doing this on the [`BufferClosed`] hook.
902    /// Returns [`None`] if the `Buffer` wasn't already [registered].
903    ///
904    /// [`BufferClosed`]: crate::hook::BufferClosed
905    /// [registered]: Self::register
906    pub fn unregister(&self, pa: &mut Pass, handle: &Handle) -> Option<T> {
907        let buf_id = handle.read(pa).buffer_id();
908        self.0.write(pa).remove(&buf_id)
909    }
910
911    /// Gets a reference to the `T` associated with a [`Buffer`].
912    ///
913    /// This function lets you bipass the normal requirement of a
914    /// [`Pass`] in order to acquire a `T` associated with any given
915    /// `Buffer`.
916    ///
917    /// For now, the two types that can be used as [`BufferPass`]es
918    /// are the [`Buffer`] itself and a [`Cursor<Buffer>`]. These
919    /// types are allowed to do this because they are impossible
920    /// to acquire without first borrowing from an
921    /// [`RwData<Buffer>`], either directly or through a [`Handle`]
922    ///
923    /// Will return [`None`] if the `Buffer` in question wasn't
924    /// [registered] or was [unregistered].
925    ///
926    /// # Note: Why is this safe?
927    ///
928    /// From the rest of the operations on this struct, you may glean
929    /// that the [`PerBuffer`] struct is backed by a [`RwData`], and
930    /// the only way to safely access the data in those is through a
931    /// [`Pass`].
932    ///
933    /// So why can you suddenly do this without a `Pass`. Basically,
934    /// since you can't construct a `Buffer`, the only way to actually
935    /// get one is by borrowing from a [`RwData<Buffer>`] or
936    /// [`Handle`].
937    ///
938    /// Given that, the [`Pass`] will already be borrowed, and the
939    /// `Buffer` will act as an "extensionto the [`Pass`]'s borrow",
940    /// and will become invalid at the same time.
941    ///
942    /// It is important to note that this is only safe because
943    /// `Buffer`s can't be acquired without a [`Pass`].
944    ///
945    /// [registered]: Self::register
946    /// [unregistered]: Self::unregister
947    pub fn get<'b>(&'b self, buffer_pass: &'b impl BufferPass) -> Option<&'b T> {
948        static PASS: Pass = unsafe { Pass::new() };
949        let list = self.0.read(&PASS);
950        list.get(&buffer_pass.buffer_id())
951    }
952
953    /// Gets a mutable reference to the `T` associated with a
954    /// [`Buffer`].
955    ///
956    /// This function lets you bipass the normal requirement of a
957    /// [`Pass`] in order to acquire a `T` associated with any given
958    /// `Buffer`.
959    ///
960    /// For now, the two types that can be used as [`BufferPass`]es
961    /// are the [`Buffer`] itself and a [`Cursor<Buffer>`]. These
962    /// types are allowed to do this because they are impossible
963    /// to acquire without first borrowing from an [`RwData<Buffer>`],
964    /// either directly or through a [`Handle`]
965    ///
966    /// Will return [`None`] if the `Buffer` in question wasn't
967    /// [registered] or was [unregistered].
968    ///
969    /// # Note: Why is this safe?
970    ///
971    /// For the same reason that [`PerBuffer::get`] is safe. However,
972    /// in order to prevent multiple borrowings from happening at the
973    /// same time, this will take a mutable borrow of the `Buffer`,
974    /// acting much like a `&mut Pass` in that regard.
975    ///
976    /// [registered]: Self::register
977    /// [unregistered]: Self::unregister
978    pub fn get_mut<'b>(&'b self, buffer: &'b mut impl BufferPass) -> Option<&'b mut T> {
979        static PASS: Pass = unsafe { Pass::new() };
980        let list = self
981            .0
982            .write(unsafe { (&raw const PASS as *mut Pass).as_mut() }.unwrap());
983        list.get_mut(&buffer.buffer_id())
984    }
985
986    /// Writes to the [`Buffer`] and the `T` at the same time.
987    ///
988    /// Will return [`None`] if the `Buffer` in question wasn't
989    /// [registered] or was [unregistered].
990    ///
991    /// [registered]: Self::register
992    /// [unregistered]: Self::unregister
993    pub fn write<'p>(
994        &'p self,
995        pa: &'p mut Pass,
996        handle: &'p Handle,
997    ) -> Option<(&'p mut T, &'p mut Buffer)> {
998        let (list, buffer) = pa.write_many((&*self.0, handle));
999        Some((list.get_mut(&buffer.buffer_id())?, buffer))
1000    }
1001
1002    /// Writes to the [`Buffer`] and a tuple of [writeable] types.
1003    ///
1004    /// This is an extension to the [`Pass::write_many`] method,
1005    /// allowing you to write to many [`RwData`]-like structs at once.
1006    ///
1007    /// Returns [`None`] if any two structs, either in the [`Handle`],
1008    /// [tuple], or [`PerBuffer`] point to the same thing, or if the
1009    /// `Buffer` wasn't [registered] or was [unregistered].
1010    ///
1011    /// [writeable]: crate::data::WriteableData
1012    /// [registered]: Self::register
1013    /// [unregistered]: Self::unregister
1014    pub fn write_with<'p, Tup: WriteableTuple<'p, impl std::any::Any>>(
1015        &'p self,
1016        pa: &'p mut Pass,
1017        handle: &'p Handle,
1018        tup: Tup,
1019    ) -> Option<(&'p mut T, &'p mut Buffer, Tup::Return)> {
1020        let (list, buffer, ret) = pa.try_write_many((&*self.0, handle, tup))?;
1021        Some((list.get_mut(&buffer.buffer_id())?, buffer, ret))
1022    }
1023
1024    /// Tries to write to a bunch of [`Buffer`]s and their respective
1025    /// `T`s.
1026    ///
1027    /// Returns [`None`] if any two [`Handle`]s point to the same
1028    /// `Buffer`, or if any of the `Buffers` weren't [registered] or
1029    /// were [unregistered].
1030    ///
1031    /// [registered]: Self::register
1032    /// [unregistered]: Self::unregister
1033    pub fn write_many<'p, const N: usize>(
1034        &'p self,
1035        pa: &'p mut Pass,
1036        handles: [&'p Handle; N],
1037    ) -> Option<[(&'p mut T, &'p mut Buffer); N]> {
1038        let (list, buffers) = pa.try_write_many((&*self.0, handles))?;
1039        let buf_ids = buffers.each_ref().map(|buf| buf.buffer_id());
1040        let values = list.get_disjoint_mut(buf_ids.each_ref());
1041
1042        let list = values
1043            .into_iter()
1044            .zip(buffers)
1045            .map(|(value, buf)| value.zip(Some(buf)))
1046            .collect::<Option<Vec<_>>>()?;
1047
1048        list.try_into().ok()
1049    }
1050
1051    /// Fusion of [`write_many`] and [`write_with`].
1052    ///
1053    /// Returns [`None`] if any two structs point to the same
1054    /// [`RwData`]-like struct, or if any of the `Buffers` weren't
1055    /// [registered] or were [unregistered].
1056    ///
1057    /// [`write_many`]: Self::write_many
1058    /// [`write_with`]: Self::write_with
1059    /// [registered]: Self::register
1060    /// [unregistered]: Self::unregister
1061    pub fn write_many_with<'p, const N: usize, Tup: WriteableTuple<'p, impl std::any::Any>>(
1062        &'p self,
1063        pa: &'p mut Pass,
1064        handles: [&'p Handle; N],
1065        tup: Tup,
1066    ) -> Option<([(&'p mut T, &'p mut Buffer); N], Tup::Return)> {
1067        let (list, buffers, ret) = pa.try_write_many((&*self.0, handles, tup))?;
1068        let buf_ids = buffers.each_ref().map(|buf| buf.buffer_id());
1069        let values = list.get_disjoint_mut(buf_ids.each_ref());
1070
1071        let list = values
1072            .into_iter()
1073            .zip(buffers)
1074            .map(|(value, buf)| value.zip(Some(buf)))
1075            .collect::<Option<Vec<_>>>()?;
1076
1077        Some((list.try_into().ok()?, ret))
1078    }
1079}
1080
1081impl<T: 'static> Default for PerBuffer<T> {
1082    fn default() -> Self {
1083        Self::new()
1084    }
1085}
1086
1087/// An item that identifies that you are [writing] or [reading] from
1088/// an [`RwData<Buffer>`].
1089///
1090/// This trait is used exclusively by the [`PerBuffer`] struct, which
1091/// can bipass the usual requirements that [`Pass`]es need to be used
1092/// to access the data in [`RwData`]-like structs.
1093///
1094/// [writing]: RwData::write
1095/// [reading]: RwData::read
1096#[doc(hidden)]
1097pub trait BufferPass: InnerBufferPass {
1098    #[doc(hidden)]
1099    fn buffer_id(&self) -> BufferId;
1100}
1101
1102impl BufferPass for Buffer {
1103    fn buffer_id(&self) -> BufferId {
1104        Buffer::buffer_id(self)
1105    }
1106}
1107impl<'b> BufferPass for Cursor<'b, Buffer> {
1108    fn buffer_id(&self) -> BufferId {
1109        Cursor::buffer_id(self)
1110    }
1111}
1112
1113trait InnerBufferPass {}
1114
1115impl InnerBufferPass for Buffer {}
1116impl<'b> InnerBufferPass for Cursor<'b, Buffer> {}