duat_core/text/
mod.rs

1//! The primary data structure in Duat
2//!
3//! This struct is responsible for all of the text that will be
4//! printed to the screen, as well as any modifications on it.
5//!
6//! The [`Text`] is a very versatile holder for characters, below is a
7//! list of some of its capabilities:
8//!
9//! - Be cheaply* edited at any point, due to its two [gap buffers];
10//! - Be [colored] in any way, at any point;
11//! - Have any arbitrary range concealed, that is, hidden from view,
12//!   but still in there;
13//! - Arbitrary [ghost text], that is, [`Text`] that shows up, but is
14//!   not actually part of the [`Text`], i.e., it can be easily
15//!   ignored by external modifiers (like an LSP or tree-sitter) of
16//!   the file, without any special checks;
17//! - [Left]/[right]/[center] alignment of output (although that is
18//!   implemented by the [`Ui`]);
19//! - [Spacers] for even more advanced alignment
20//! - The ability to [undo]/[redo] changes in the history;
21//! - In the future, button ranges that can interact with the mouse;
22//!
23//! The [`Text`] struct is created in two different ways:
24//!
25//! - By calling [`Text::new`] or one of its [`From`] implementations;
26//! - By building it with the [`txt!`] macro;
27//!
28//! The first method is recommended if you want a [`Text`] that will
29//! be modified by input. This is often the case if your [`Widget`] is
30//! some sort of text box, chief of which is the [`File`], which is
31//! the central [`Widget`] of every text editor.
32//!
33//! The second method is what should be used most of the time, as it
34//! lets you quickly create formatted [`Widget`]s/[`StatusLine`] parts
35//! in a very modular way:
36//!
37//! ```rust
38//! # use duat_core::prelude::*;
39//! fn number_of_horses(count: usize) -> Text {
40//!     if count == 1 {
41//!         txt!("[horses.count]1[horses] horse").build()
42//!     } else {
43//!         txt!("[horses.count]{}[horses] horses", count).build()
44//!     }
45//! }
46//!
47//! fn inlined_number_of_horses(count: usize) -> Text {
48//!     txt!(
49//!         "[horses.count]{count} [horses]{}",
50//!         if count == 1 { "horse" } else { "horses" }
51//!     )
52//!     .build()
53//! }
54//! ```
55//!
56//! You can use this whenever you need to update a widget, for
57//! example, just create a new [`Text`] to printed to the screen.
58//!
59//! However, when recreating the entire [`Text`] with a [`txt!`]
60//! macro would be too expensive, you can use [`Text`] modifying
61//! functions:
62//!
63//! ```rust
64//! # duat_core::form::set_initial(duat_core::form::get_initial());
65//! # use duat_core::prelude::*;
66//! let mut prompted = txt!("[prompt]type a key: ").build();
67//! let end = prompted.len();
68//! prompted.replace_range(end..end, "a")
69//! ```
70//!
71//! A general rule of thumb for "too expensive" is this: if your
72//! [`Text`] can't scroll more than a few lines, it is not too
73//! expensive to rebuild. This way of editing the [`Text`] is mostly
74//! used on the [`File`] widget and other textbox-like [`Widget`]s.
75//!
76//! [Left]: AlignLeft
77//! [right]: AlignRight
78//! [center]: AlignCenter
79//! [Spacers]: Spacer
80//! [undo]: Text::undo
81//! [redo]: Text::redo
82//! [gap buffers]: gapbuf::GapBuffer
83//! [colored]: crate::form::Form
84//! [ghost text]: Ghost
85//! [`Ui`]: crate::ui::Ui
86//! [`File`]: crate::file::File
87//! [`Widget`]: crate::ui::Widget
88//! [`StatusLine`]: https://docs.rs/duat-utils/latest/duat_utils/widgets/struct.StatusLine.html
89//! [`Mode`]: crate::mode::Mode
90mod builder;
91mod bytes;
92mod history;
93mod iter;
94mod ops;
95mod records;
96mod search;
97mod shift_list;
98mod tags;
99
100use std::{
101    path::Path,
102    rc::Rc,
103    sync::{
104        Arc,
105        atomic::{AtomicBool, Ordering},
106    },
107};
108
109use self::tags::{FwdTags, InnerTags, RevTags};
110pub use self::{
111    builder::{Builder, BuilderPart, txt},
112    bytes::{Buffers, Bytes, Lines, Strs},
113    history::{Change, History, Moment},
114    iter::{FwdIter, Item, Part, RevIter},
115    ops::{Point, TextRange, TextRangeOrPoint, TwoPoints, utf8_char_width},
116    search::{Matcheable, RegexPattern, Searcher},
117    tags::{
118        AlignCenter, AlignLeft, AlignRight, Conceal, ExtraCaret, FormTag, Ghost, GhostId,
119        MainCaret, RawTag, Spacer, Tag, Tagger, Taggers, Tags, ToggleId,
120    },
121};
122use crate::{
123    cfg::PrintCfg,
124    context, form,
125    mode::{Selection, Selections},
126    ui::Area,
127};
128
129/// The text of a given [`Widget`]
130///
131/// The [`Text`] is the backbone of Duat. It is the thing responsible
132/// for everything that shows up on screen.
133///
134/// You can build a [`Text`] manually, by using [`Text::new`], or with
135/// some convenience, by using the [`txt!`] macro, making use of a
136/// [`Builder`].
137///
138/// [`Widget`]: crate::ui::Widget
139pub struct Text(Box<InnerText>);
140
141struct InnerText {
142    bytes: Bytes,
143    tags: InnerTags,
144    selections: Selections,
145    // Specific to Files
146    history: Option<History>,
147    has_changed: bool,
148    has_unsaved_changes: AtomicBool,
149}
150
151impl Text {
152    ////////// Creation and Destruction of Text
153
154    /// Returns a new empty [`Text`]
155    pub fn new() -> Self {
156        Self::from_bytes(Bytes::default(), Selections::new_empty(), false)
157    }
158
159    /// Returns a new empty [`Text`] with [`Selections`] enabled
160    pub fn new_with_selections() -> Self {
161        Self::from_bytes(
162            Bytes::default(),
163            Selections::new(Selection::default()),
164            false,
165        )
166    }
167
168    /// Returns a new empty [`Text`] with history enabled
169    pub(crate) fn new_with_history() -> Self {
170        Self::from_bytes(
171            Bytes::default(),
172            Selections::new(Selection::default()),
173            true,
174        )
175    }
176
177    /// Creates a [`Text`] from a file's [path]
178    ///
179    /// [path]: Path
180    pub(crate) fn from_file(
181        bytes: Bytes,
182        selections: Selections,
183        path: impl AsRef<Path>,
184        has_unsaved_changes: bool,
185    ) -> Self {
186        let selections = if let Some(selection) = selections.get_main()
187            && let Some(_) = bytes.char_at(selection.caret())
188        {
189            selections
190        } else {
191            Selections::new(Selection::default())
192        };
193
194        let mut text = Self::from_bytes(bytes, selections, true);
195        text.0
196            .has_unsaved_changes
197            .store(has_unsaved_changes, Ordering::Relaxed);
198
199        if let Ok(history) = context::Cache::new().load(path.as_ref()) {
200            text.0.history = Some(history);
201        }
202
203        text
204    }
205
206    /// Creates a [`Text`] from [`Bytes`]
207    pub(crate) fn from_bytes(mut bytes: Bytes, selections: Selections, with_history: bool) -> Self {
208        if bytes.buffers(..).next_back().is_none_or(|b| b != b'\n') {
209            let end = bytes.len();
210            bytes.apply_change(Change::str_insert("\n", end));
211        }
212        let tags = InnerTags::new(bytes.len().byte());
213
214        Self(Box::new(InnerText {
215            bytes,
216            tags,
217            selections,
218            history: with_history.then(History::new),
219            has_changed: false,
220            has_unsaved_changes: AtomicBool::new(false),
221        }))
222    }
223
224    /// Returns an empty [`Text`], only for [`Builder`]s
225    fn empty() -> Self {
226        Self(Box::new(InnerText {
227            bytes: Bytes::default(),
228            tags: InnerTags::new(0),
229            selections: Selections::new_empty(),
230            history: None,
231            has_changed: false,
232            has_unsaved_changes: AtomicBool::new(false),
233        }))
234    }
235
236    /// Returns a [`Builder`] for [`Text`]
237    ///
238    /// This builder can be used to iteratively create text, by
239    /// assuming that the user wants no* [`Tag`] overlap, and that
240    /// they want to construct the [`Text`] in [`Tag`]/content pairs.
241    ///
242    /// ```rust
243    /// use duat_core::prelude::*;
244    /// let mut builder = Text::builder();
245    /// ```
246    pub fn builder() -> Builder {
247        Builder::new()
248    }
249
250    /// Takes the [`Bytes`] from this [`Text`], consuming it
251    pub(crate) fn take_bytes(self) -> Bytes {
252        self.0.bytes
253    }
254
255    ////////// Querying functions
256
257    /// Whether the [`Bytes`] and `InnerTags` are empty
258    ///
259    /// This ignores the last `'\n'` in the [`Text`], since it is
260    /// always there no matter what.
261    ///
262    /// If you only want to check for the [`Bytes`], ignoring possible
263    /// [`Ghost`]s, see [`is_empty`].
264    ///
265    /// [`is_empty`]: Bytes::is_empty
266    pub fn is_empty_empty(&self) -> bool {
267        self.0.bytes == "\n" && self.0.tags.is_empty()
268    }
269
270    /// The inner bytes of the [`Text`]
271    ///
272    /// Note that, since [`Text`] has an implementation of
273    /// [`std::ops::Deref<Target = Bytes>`], you mostly don't need
274    /// to call this method.
275    ///
276    /// [regex searching]: Bytes::search_fwd
277    pub fn bytes(&self) -> &Bytes {
278        &self.0.bytes
279    }
280
281    /// The parts that make up a [`Text`]
282    ///
283    /// This function is used when you want to [insert]/[remove]
284    /// [`Tag`]s (i.e., borrow the inner `InnerTags` mutably via
285    /// [`Tags`]), while still being able to read from the
286    /// [`Bytes`] and [`Selections`].
287    ///
288    /// [insert]: Tags::insert
289    /// [remove]: Tags::remove
290    /// [`&mut Bytes`]: Bytes
291    pub fn parts(&mut self) -> TextParts<'_> {
292        TextParts {
293            bytes: &self.0.bytes,
294            tags: Tags(&mut self.0.tags),
295            selections: &self.0.selections,
296        }
297    }
298
299    /// Gets the indentation level on the current line
300    pub fn indent(&self, p: Point, area: &impl Area, mut cfg: PrintCfg) -> usize {
301        let [start, _] = self.points_of_line(p.line());
302        let t_iter = self.iter_fwd(start).no_ghosts().no_conceals();
303        area.print_iter(t_iter, *cfg.new_line_as('\n'))
304            .filter_map(|(caret, item)| Some(caret).zip(item.part.as_char()))
305            .find(|(_, char)| !char.is_whitespace() || *char == '\n')
306            .map(|(caret, _)| caret.x as usize)
307            .unwrap_or(0)
308    }
309
310    ////////// Tag related query functions
311
312    /// The maximum [points] in the `at`th byte
313    ///
314    /// This point is essentially the [point] at that byte, plus the
315    /// last possible [`Point`] of any [`Ghost`]s in that
316    /// position.
317    ///
318    /// [points]: TwoPoints
319    /// [point]: Bytes::point_at_byte
320    #[inline(always)]
321    pub fn ghost_max_points_at(&self, b: usize) -> (Point, Option<Point>) {
322        let point = self.point_at_byte(b);
323        (point, self.0.tags.ghosts_total_at(point.byte()))
324    }
325
326    /// The [points] at the end of the text
327    ///
328    /// This will essentially return the [last point] of the text,
329    /// alongside the last possible [`Point`] of any
330    /// [`Ghost`] at the end of the text.
331    ///
332    /// [points]: TwoPoints
333    /// [last point]: Bytes::len
334    pub fn len_points(&self) -> (Point, Option<Point>) {
335        self.ghost_max_points_at(self.len().byte())
336    }
337
338    /// Points visually after the [`TwoPoints`]
339    ///
340    /// If the [`TwoPoints`] in question is concealed, treats the
341    /// next visible character as the first character, and returns
342    /// the points of the next visible character.
343    ///
344    /// This method is useful if you want to iterator reversibly
345    /// right after a certain point, thus including the character
346    /// of said point.
347    pub fn points_after(&self, tp: impl TwoPoints) -> Option<(Point, Option<Point>)> {
348        self.iter_fwd(tp)
349            .filter_map(|item| item.part.as_char().map(|_| item.points()))
350            .chain([self.len_points()])
351            .nth(1)
352    }
353
354    /// The visual start of the line
355    ///
356    /// This point is defined not by where the line actually begins,
357    /// but by where the last '\n' was located. For example, if
358    /// [`Tag`]s create ghost text or omit text from multiple
359    /// different lines, this point may differ from where in the
360    /// [`Text`] the physical line actually begins.
361    pub fn visual_line_start(&self, p: impl TwoPoints) -> (Point, Option<Point>) {
362        let (real, ghost) = p.to_points();
363
364        let mut iter = self.iter_rev((real, ghost)).peekable();
365        let mut points = (real, ghost);
366        while let Some(peek) = iter.peek() {
367            match peek.part {
368                Part::Char('\n') => {
369                    return points;
370                }
371                Part::Char(_) => points = iter.next().unwrap().to_points(),
372                _ => drop(iter.next()),
373            }
374        }
375
376        points
377    }
378
379    /// Gets the [`Ghost`] of a given [`GhostId`]
380    pub fn get_ghost(&self, id: GhostId) -> Option<&Text> {
381        self.0.tags.get_ghost(id)
382    }
383
384    ////////// Modification functions
385
386    /// Replaces a [range] in the [`Text`]
387    ///
388    /// # [`TextRange`] behavior:
389    ///
390    /// If you give a single [`usize`]/[`Point`], it will be
391    /// interpreted as a range from.
392    ///
393    /// [range]: TextRange
394    pub fn replace_range(&mut self, range: impl TextRange, edit: impl ToString) {
395        let range = range.to_range(self.len().byte());
396        let (start, end) = (
397            self.point_at_byte(range.start),
398            self.point_at_byte(range.end),
399        );
400        let change = Change::new(edit, [start, end], self);
401
402        self.0.has_changed = true;
403        self.apply_change_inner(0, change.as_ref());
404        self.0
405            .history
406            .as_mut()
407            .map(|h| h.apply_change(None, change));
408    }
409
410    pub(crate) fn apply_change(
411        &mut self,
412        guess_i: Option<usize>,
413        change: Change,
414    ) -> (Option<usize>, usize) {
415        self.0.has_changed = true;
416
417        let selections_taken = self.apply_change_inner(guess_i.unwrap_or(0), change.as_ref());
418        let history = self.0.history.as_mut();
419        let insertion_i = history.map(|h| h.apply_change(guess_i, change));
420        (insertion_i, selections_taken)
421    }
422
423    /// Merges `String`s with the body of text, given a range to
424    /// replace
425    fn apply_change_inner(&mut self, guess_i: usize, change: Change<&str>) -> usize {
426        self.0.bytes.apply_change(change);
427        self.0.tags.transform(
428            change.start().byte()..change.taken_end().byte(),
429            change.added_end().byte(),
430        );
431
432        *self.0.has_unsaved_changes.get_mut() = true;
433        self.0.selections.apply_change(guess_i, change)
434    }
435
436    fn without_last_nl(mut self) -> Self {
437        let change = Change::remove_last_nl(self.len());
438        self.apply_change_inner(0, change);
439        self
440    }
441
442    /// Updates bounds, so that [`Tag`] ranges can visibly cross the
443    /// screen
444    ///
445    /// This is used in order to allow for very long [`Tag`] ranges
446    /// (say, a [`Form`] being applied on the range `3..999`) to show
447    /// up properly without having to lookback a bazillion [`Tag`]s
448    /// which could be in the way.
449    ///
450    /// [`Form`]: crate::form::Form
451    pub fn update_bounds(&mut self) {
452        self.0.tags.update_bounds();
453    }
454
455    /// Inserts a [`Text`] into this [`Text`], in a specific [`Point`]
456    pub fn insert_text(&mut self, p: Point, text: Text) {
457        let insert = if p.char() == 1 && self.0.bytes == "\n" {
458            let change = Change::new(
459                text.0.bytes.strs(..).unwrap().to_string(),
460                [Point::default(), p],
461                self,
462            );
463            self.apply_change_inner(0, change.as_ref());
464            Point::default()
465        } else {
466            let added_str = text.0.bytes.strs(..).unwrap().to_string();
467            let change = Change::str_insert(&added_str, p);
468            self.apply_change_inner(0, change);
469            p
470        };
471
472        if insert == self.len() {
473            self.0.tags.extend(text.0.tags);
474        } else {
475            self.0.tags.insert_tags(insert, text.0.tags);
476        }
477    }
478
479    ////////// History functions
480
481    /// Undoes the last moment, if there was one
482    pub fn undo(&mut self) {
483        let mut history = self.0.history.take();
484
485        if let Some(history) = history.as_mut()
486            && let Some(moment) = history.move_backwards()
487        {
488            self.apply_and_process_changes(moment);
489            self.0.has_changed = true;
490        }
491
492        self.0.history = history;
493    }
494
495    /// Redoes the last moment in the history, if there is one
496    pub fn redo(&mut self) {
497        let mut history = self.0.history.take();
498
499        if let Some(history) = history.as_mut()
500            && let Some(moment) = history.move_forward()
501        {
502            self.apply_and_process_changes(moment);
503            self.0.has_changed = true;
504        }
505
506        self.0.history = history;
507    }
508
509    /// Finishes the current moment and adds a new one to the history
510    pub fn new_moment(&mut self) {
511        if let Some(h) = self.0.history.as_mut() {
512            h.new_moment()
513        }
514    }
515
516    /// Returns a [`Moment`] containing all [`Change`]s since the last
517    /// call to this function
518    ///
519    /// This is useful if you want to figure out what has changed
520    /// after a certain period of time has passed.
521    pub fn unprocessed_moments(&self) -> Option<Vec<Moment>> {
522        self.0.history.as_ref().map(|h| h.unprocessed_moments())
523    }
524
525    fn apply_and_process_changes(&mut self, moment: Moment) {
526        self.0.selections.clear();
527
528        for (i, change) in moment.changes().enumerate() {
529            self.apply_change_inner(0, change);
530
531            let start = change.start();
532            let added_end = match change.added_str().chars().next_back() {
533                Some(last) => change.added_end().rev(last),
534                None => change.start(),
535            };
536
537            let selection = Selection::new(added_end, (start != added_end).then_some(start));
538            self.0
539                .selections
540                .insert(i, selection, i == moment.len() - 1);
541        }
542    }
543
544    ////////// Writing functions
545
546    /// Clones the inner [`Bytes`] as a [`String`]
547    ///
548    /// This function will also cut out a final '\n' from the string.
549    // NOTE: Inherent because I don't want this to implement Display
550    #[allow(clippy::inherent_to_string)]
551    pub fn to_string(&self) -> String {
552        let [s0, s1] = self.strs(..).unwrap().to_array();
553        if !s1.is_empty() {
554            s0.to_string() + s1.strip_suffix('\n').unwrap_or(s1)
555        } else {
556            s0.strip_suffix('\n').unwrap_or(s0).to_string()
557        }
558    }
559
560    /// Writes the contents of this [`Text`] to a [writer]
561    ///
562    /// [writer]: std::io::Write
563    pub fn write_to(&self, mut writer: impl std::io::Write) -> std::io::Result<usize> {
564        self.0.has_unsaved_changes.store(false, Ordering::Relaxed);
565        let [s0, s1] = self.0.bytes.buffers(..).to_array();
566        Ok(writer.write(s0)? + writer.write(s1)?)
567    }
568
569    /// Wether or not the content has changed since the last [write]
570    ///
571    /// Returns `true` only if the actual bytes of the [`Text`] have
572    /// been changed, ignoring [`Tag`]s and all the other things,
573    /// since those are not written to the filesystem.
574    ///
575    /// [write]: Text::write_to
576    pub fn has_unsaved_changes(&self) -> bool {
577        self.0.has_unsaved_changes.load(Ordering::Relaxed)
578    }
579
580    ////////// Tag addition/deletion functions
581
582    /// Inserts a [`Tag`] at the given position
583    pub fn insert_tag<R>(&mut self, tagger: Tagger, r: R, tag: impl Tag<R>) {
584        self.0.tags.insert(tagger, r, tag);
585    }
586
587    /// Removes the [`Tag`]s of a [key] from a region
588    ///
589    /// # Caution
590    ///
591    /// While it is fine to do this on your own widgets, you should
592    /// refrain from using this function in a [`File`]s [`Text`], as
593    /// it must iterate over all tags in the file, so if there are a
594    /// lot of other tags, this operation may be slow.
595    ///
596    /// # [`TextRange`] behavior
597    ///
598    /// If you give it a [`Point`] or [`usize`], it will be treated as
599    /// a one byte range.
600    ///
601    /// [key]: Taggers
602    /// [`File`]: crate::file::File
603    pub fn remove_tags(&mut self, taggers: impl Taggers, range: impl TextRangeOrPoint) {
604        let range = range.to_range(self.len().byte());
605        self.0.tags.remove_from(taggers, range)
606    }
607
608    /// Removes all [`Tag`]s
609    ///
610    /// Refrain from using this function on [`File`]s, as there may be
611    /// other [`Tag`] providers, and you should avoid messing with
612    /// their tags.
613    ///
614    /// [`File`]: crate::file::File
615    pub fn clear_tags(&mut self) {
616        self.0.tags = InnerTags::new(self.0.bytes.len().byte());
617    }
618
619    /////////// Selection functions
620
621    /// Returns a [`Text`] without [`Selections`]
622    ///
623    /// You should use this if you want to send the [`Text`] across
624    /// threads.
625    pub fn no_selections(mut self) -> Selectionless {
626        self.0.selections.clear();
627        Selectionless(self)
628    }
629
630    /// Removes the tags for all the selections, used before they are
631    /// expected to move
632    pub(crate) fn add_selections(&mut self, area: &impl Area, cfg: PrintCfg) {
633        let within = (self.0.selections.len() >= 500).then(|| {
634            let (start, _) = area.start_points(self, cfg);
635            let (end, _) = area.end_points(self, cfg);
636            (start, end)
637        });
638
639        let mut add_selection = |selection: &Selection, bytes: &mut Bytes, is_main: bool| {
640            let (caret, selection) = selection.tag_points(bytes);
641
642            let key = Tagger::for_selections();
643            let form = if is_main {
644                self.0.tags.insert(key, caret.byte(), MainCaret);
645                form::M_SEL_ID
646            } else {
647                self.0.tags.insert(key, caret.byte(), ExtraCaret);
648                form::E_SEL_ID
649            };
650
651            bytes.add_record([caret.byte(), caret.char(), caret.line()]);
652
653            if let Some([start, end]) = selection {
654                let range = start.byte()..end.byte();
655                self.0.tags.insert(key, range, form.to_tag(95));
656            }
657        };
658
659        if let Some((start, end)) = within {
660            for (_, selection, is_main) in self.0.selections.iter_within(start..end) {
661                add_selection(selection, &mut self.0.bytes, is_main);
662            }
663        } else {
664            for (selection, is_main) in self.0.selections.iter() {
665                add_selection(selection, &mut self.0.bytes, is_main);
666            }
667        }
668    }
669
670	/// Removes the [`Tag`]s for all [`Selection`]s
671    pub(crate) fn remove_selections(&mut self) {
672        self.remove_tags(Tagger::for_selections(), ..);
673    }
674
675    /////////// Iterator methods
676
677    /// A forward iterator of the [chars and tags] of the [`Text`]
678    ///
679    /// [chars and tags]: Part
680    pub fn iter_fwd(&self, at: impl TwoPoints) -> FwdIter<'_> {
681        FwdIter::new_at(self, at)
682    }
683
684    /// A reverse iterator of the [chars and tags] of the [`Text`]
685    ///
686    /// [chars and tags]: Part
687    pub fn iter_rev(&self, at: impl TwoPoints) -> RevIter<'_> {
688        RevIter::new_at(self, at)
689    }
690
691    /// A forward iterator of the [`char`]s of the [`Text`]
692    ///
693    /// Each [`char`] will be accompanied by a [`Point`], which is the
694    /// position where said character starts, e.g.
695    /// [`Point::default()`] for the first character
696    pub fn chars_fwd(
697        &self,
698        range: impl TextRange,
699    ) -> Option<impl Iterator<Item = (Point, char)> + '_> {
700        self.0.bytes.chars_fwd(range)
701    }
702
703    /// A reverse iterator of the [`char`]s of the [`Text`]
704    ///
705    /// Each [`char`] will be accompanied by a [`Point`], which is the
706    /// position where said character starts, e.g.
707    /// [`Point::default()`] for the first character
708    pub fn chars_rev(
709        &self,
710        range: impl TextRange,
711    ) -> Option<impl Iterator<Item = (Point, char)> + '_> {
712        self.0.bytes.chars_rev(range)
713    }
714
715    /// A forward iterator over the [`Tag`]s of the [`Text`]
716    ///
717    /// This iterator will consider some [`Tag`]s before `b`, since
718    /// their ranges may overlap with `b`
719    ///
720    /// # Note
721    ///
722    /// Duat works fine with [`Tag`]s in the middle of a codepoint,
723    /// but external utilizers may not, so keep that in mind.
724    pub fn tags_fwd(&self, b: usize) -> FwdTags<'_> {
725        self.0.tags.fwd_at(b)
726    }
727
728    /// An reverse iterator over the [`Tag`]s of the [`Text`]
729    ///
730    /// This iterator will consider some [`Tag`]s ahead of `b`, since
731    /// their ranges may overlap with `b`
732    ///
733    /// # Note
734    ///
735    /// Duat works fine with [`Tag`]s in the middle of a codepoint,
736    /// but external utilizers may not, so keep that in mind.
737    pub fn tags_rev(&self, b: usize) -> RevTags<'_> {
738        self.0.tags.rev_at(b)
739    }
740
741    /// A forward [`Iterator`] over the [`RawTag`]s
742    ///
743    /// This [`Iterator`] does not take into account [`Tag`] ranges
744    /// that intersect with the starting point, unlike
745    /// [`Text::tags_fwd`]
746    pub fn raw_tags_fwd(&self, b: usize) -> impl Iterator<Item = (usize, RawTag)> {
747        self.0.tags.raw_fwd_at(b)
748    }
749
750    /// A reverse [`Iterator`] over the [`RawTag`]s
751    ///
752    /// This [`Iterator`] does not take into account [`Tag`] ranges
753    /// that intersect with the starting point, unlike
754    /// [`Text::tags_rev`]
755    pub fn raw_tags_rev(&self, b: usize) -> impl Iterator<Item = (usize, RawTag)> {
756        self.0.tags.raw_rev_at(b)
757    }
758
759    /// The [`Selections`] printed to this [`Text`], if they exist
760    pub fn selections(&self) -> &Selections {
761        &self.0.selections
762    }
763
764    /// A mut reference to this [`Text`]'s [`Selections`] if they
765    /// exist
766    pub fn selections_mut(&mut self) -> &mut Selections {
767        &mut self.0.selections
768    }
769
770    /// The [`History`] of [`Moment`]s in this [`Text`]
771    pub fn history(&self) -> Option<&History> {
772        self.0.history.as_ref()
773    }
774}
775
776impl std::ops::Deref for Text {
777    type Target = Bytes;
778
779    fn deref(&self) -> &Self::Target {
780        self.bytes()
781    }
782}
783
784impl Default for Text {
785    fn default() -> Self {
786        Self::new()
787    }
788}
789
790impl std::fmt::Debug for Text {
791    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
792        f.debug_struct("Text")
793            .field("bytes", &self.0.bytes)
794            .field("tags", &self.0.tags)
795            .finish_non_exhaustive()
796    }
797}
798
799impl Clone for Text {
800    fn clone(&self) -> Self {
801        Self(Box::new(InnerText {
802            bytes: self.0.bytes.clone(),
803            tags: self.0.tags.clone(),
804            selections: self.0.selections.clone(),
805            history: self.0.history.clone(),
806            has_changed: self.0.has_changed,
807            has_unsaved_changes: AtomicBool::new(false),
808        }))
809    }
810}
811
812impl From<std::io::Error> for Text {
813    fn from(value: std::io::Error) -> Self {
814        txt!("{}", value.kind().to_string()).build()
815    }
816}
817
818impl From<Box<dyn std::error::Error>> for Text {
819    fn from(value: Box<dyn std::error::Error>) -> Self {
820        txt!("{}", value.to_string()).build()
821    }
822}
823
824impl From<&std::path::PathBuf> for Text {
825    fn from(value: &std::path::PathBuf) -> Self {
826        let value = value.to_str().unwrap_or("");
827        Self::from(value)
828    }
829}
830
831impl PartialEq for Text {
832    fn eq(&self, other: &Self) -> bool {
833        self.0.bytes == other.0.bytes && self.0.tags == other.0.tags
834    }
835}
836
837impl PartialEq<&str> for Text {
838    fn eq(&self, other: &&str) -> bool {
839        self.0.bytes == *other
840    }
841}
842
843impl PartialEq<String> for Text {
844    fn eq(&self, other: &String) -> bool {
845        self.0.bytes == *other
846    }
847}
848
849impl_from_to_string!(u8);
850impl_from_to_string!(u16);
851impl_from_to_string!(u32);
852impl_from_to_string!(u64);
853impl_from_to_string!(u128);
854impl_from_to_string!(usize);
855impl_from_to_string!(i8);
856impl_from_to_string!(i16);
857impl_from_to_string!(i32);
858impl_from_to_string!(i64);
859impl_from_to_string!(i128);
860impl_from_to_string!(isize);
861impl_from_to_string!(f32);
862impl_from_to_string!(f64);
863impl_from_to_string!(char);
864impl_from_to_string!(&str);
865impl_from_to_string!(String);
866impl_from_to_string!(Box<str>);
867impl_from_to_string!(Rc<str>);
868impl_from_to_string!(Arc<str>);
869
870/// Implements [`From<$t>`] for [`Text`]
871macro impl_from_to_string($t:ty) {
872    impl From<$t> for Text {
873        fn from(value: $t) -> Self {
874            let string = <$t as ToString>::to_string(&value);
875            let bytes = Bytes::new(&string);
876            Self::from_bytes(bytes, Selections::new_empty(), false)
877        }
878    }
879}
880
881/// A [`Text`] that is guaranteed not to have [`Selections`] in it
882///
883/// Useful for sending across threads, especially when it comes to
884/// [`Logs`].
885///
886/// [`Logs`]: crate::context::Logs
887#[derive(Clone, Debug)]
888pub struct Selectionless(Text);
889
890impl Selectionless {
891    /// Gets the [`Text`] within, allowing for mutation again
892    pub fn get(&self) -> Text {
893        self.0.clone()
894    }
895}
896
897impl std::ops::Deref for Selectionless {
898    type Target = Text;
899
900    fn deref(&self) -> &Self::Target {
901        &self.0
902    }
903}
904
905impl From<Selectionless> for Text {
906    fn from(value: Selectionless) -> Self {
907        value.0
908    }
909}
910
911// SAFETY: This struct is defined by the lack of Selections, the only
912// non Send/Sync part of a Text
913unsafe impl Send for Selectionless {}
914unsafe impl Sync for Selectionless {}
915
916impl AsRef<Bytes> for Text {
917    fn as_ref(&self) -> &Bytes {
918        self.bytes()
919    }
920}
921
922/// The Parts that make up a [`Text`]
923pub struct TextParts<'a> {
924    /// The [`Bytes`] of the [`Text`]
925    pub bytes: &'a Bytes,
926    /// The [`Tags`] of the [`Text`]
927    ///
928    /// This, unlike [`Bytes`], allows mutation in the form of
929    /// [adding] and [removing] [`Tag`]s.
930    ///
931    /// [adding]: Tags::insert
932    /// [removing]: Tags::remove
933    pub tags: Tags<'a>,
934    /// The [`Selections`] of the [`Text`]
935    ///
936    /// For most [`Widget`]s, there should be no [`Selection`], since
937    /// they are just visual.
938    ///
939    /// [`Widget`]: crate::ui::Widget
940    pub selections: &'a Selections,
941}