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