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