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> {}