Skip to main content

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 ignored
15//!   by external modifiers (like an LSP or tree-sitter) of the
16//!   buffer, without any special checks.
17//! - [Spacers] for even more advanced alignment (also implemented by
18//!   the [Ui]).
19//! - In the future, button ranges that can interact with the mouse.
20//!
21//! The [`Text`] struct is created in two different ways:
22//!
23//! - By calling [`Text::new`] or one of its [`From`] implementations;
24//! - By building it with the [`txt!`] macro;
25//!
26//! The first method is recommended if you want a [`Text`] that will
27//! be modified by input. This is often the case if your [`Widget`] is
28//! some sort of text box, chief of which is the [`Buffer`], which is
29//! the central `Widget` of every text editor.
30//!
31//! The second method is what should be used most of the time, as it
32//! lets you quickly create formatted [`Widget`]s/[`StatusLine`] parts
33//! in a very modular way:
34//!
35//! ```rust
36//! # duat_core::doc_duat!(duat);
37//! use duat::prelude::*;
38//!
39//! fn number_of_horses(count: usize) -> Text {
40//!     if count == 1 {
41//!         txt!("[horses.count]1[horses] horse")
42//!     } else {
43//!         txt!("[horses.count]{}[horses] horses", count)
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//! }
53//! ```
54//!
55//! You can use this whenever you need to update a widget, for
56//! example, just create a new [`Text`] to printed to the screen.
57//!
58//! However, when recreating the entire [`Text`] with a [`txt!`]
59//! macro would be too expensive, you can use [`Text`] modifying
60//! functions:
61//!
62//! ```rust
63//! # duat_core::form::set_initial(duat_core::form::get_initial());
64//! # duat_core::doc_duat!(duat);
65//! use duat::prelude::*;
66//!
67//! let mut prompted = txt!("[prompt]type a key: ");
68//! let end = prompted.len();
69//! prompted.replace_range(end..end, "a")
70//! ```
71//!
72//! A general rule of thumb for "too expensive" is this: if your
73//! [`Text`] can't scroll more than a few lines, it is not too
74//! expensive to rebuild. This way of editing the [`Text`] is mostly
75//! used on the [`Buffer`] widget and other textbox-like [`Widget`]s.
76//!
77//! [Spacers]: Spacer
78//! [gap buffers]: gap_buf::GapBuffer
79//! [colored]: crate::form::Form
80//! [ghost text]: Ghost
81//! [Ui]: crate::ui::traits::RawUi
82//! [`Buffer`]: crate::buffer::Buffer
83//! [`Widget`]: crate::ui::Widget
84//! [`StatusLine`]: https://docs.rs/duat/latest/duat/widgets/struct.StatusLine.html
85//! [`Mode`]: crate::mode::Mode
86use crate::{
87    buffer::{Change, History},
88    context::Handle,
89    data::Pass,
90    mode::{Selection, Selections},
91    text::{
92        strs::StrsBuf,
93        tags::{FwdTags, InnerTags, RevTags},
94        utils::implPartialEq,
95    },
96    ui::{SpawnId, Widget},
97};
98pub use crate::{
99    text::{
100        builder::{AsBuilderPart, Builder, BuilderPart},
101        iter::{FwdIter, RevIter, TextPart, TextPlace},
102        search::{Matches, RegexHaystack, RegexPattern},
103        strs::{Lines, Strs},
104        tags::{
105            Conceal, FormTag, Ghost, GhostId, RawTag, Spacer, SpawnTag, SwapChar, Tag, Tagger,
106            Tags, ToggleId,
107        },
108        utils::{Point, TextIndex, TextRange, TextRangeOrIndex, TwoPoints, utf8_char_width},
109    },
110    txt,
111};
112
113mod builder;
114mod iter;
115mod search;
116mod shift_list;
117mod strs;
118mod tags;
119mod utils;
120
121/// The text of a given [`Widget`].
122///
123/// The [`Text`] is the backbone of Duat. It is the thing responsible
124/// for everything that shows up on screen.
125///
126/// You can build a `Text` manually, by using [`Text::new`], or with
127/// some convenience, by using the [`txt!`] macro, making use of a
128/// [`Builder`].
129///
130/// [`Widget`]: crate::ui::Widget
131pub struct Text(Box<InnerText>);
132
133#[derive(Clone)]
134struct InnerText {
135    buf: StrsBuf,
136    tags: InnerTags,
137    selections: Selections,
138    has_unsaved_changes: bool,
139}
140
141impl Text {
142    ////////// Creation and Destruction of Text
143
144    /// Returns a new empty `Text`.
145    pub fn new() -> Self {
146        Self::from_parts(String::new(), Selections::new_empty())
147    }
148
149    /// Returns a new empty [`Text`] with [`Selections`] enabled.
150    pub fn with_default_main_selection() -> Self {
151        Self::from_parts(String::new(), Selections::new(Selection::default()))
152    }
153
154    /// Creates a `Text` from a [`String`].
155    pub(crate) fn from_parts(buffer: String, mut selections: Selections) -> Self {
156        let mut buf = StrsBuf::new(&buffer);
157
158        if buf.bytes().next_back().is_none_or(|b| b != b'\n') {
159            let end = buf.end_point();
160            buf.apply_change(Change::str_insert("\n", end));
161        }
162        let tags = InnerTags::new(buf.len());
163
164        let selections = if selections.iter().any(|(sel, _)| {
165            [Some(sel.caret()), sel.anchor()]
166                .into_iter()
167                .flatten()
168                .any(|point| point >= buf.end_point())
169        }) {
170            Selections::new(Selection::default())
171        } else {
172            selections.correct_all(&buf);
173            selections
174        };
175
176        Self(Box::new(InnerText {
177            buf,
178            tags,
179            selections,
180            has_unsaved_changes: false,
181        }))
182    }
183
184    /// Returns a [`Builder`] for [`Text`].
185    ///
186    /// This builder can be used to iteratively create text, by
187    /// assuming that the user wants no* [`Tag`] overlap, and that
188    /// they want to construct the [`Text`] in [`Tag`]/content pairs.
189    ///
190    /// ```rust
191    /// # duat_core::doc_duat!(duat);
192    /// use duat::prelude::*;
193    /// let mut builder = Text::builder();
194    /// ```
195    pub fn builder() -> Builder {
196        Builder::new()
197    }
198
199    ////////// Querying functions
200
201    /// Whether or not there are any characters in the [`Text`],
202    /// besides the final `b'\n'`.
203    ///
204    /// # Note
205    ///
206    /// This does not check for tags, so with a [`Ghost`],
207    /// there could actually be a "string" of characters on the
208    /// [`Text`], it just wouldn't be considered real "text". If you
209    /// want to check for the `InnerTags`'b possible emptyness as
210    /// well, see [`Text::is_empty_empty`].
211    pub fn is_empty(&self) -> bool {
212        let [s0, s1] = self.to_array();
213        (s0 == "\n" && s1.is_empty()) || (s0.is_empty() && s1 == "\n")
214    }
215
216    /// Whether the [`Strs`] and `InnerTags` are empty.
217    ///
218    /// This ignores the last `'\n'` in the [`Text`], since it is
219    /// always there no matter what.
220    ///
221    /// If you only want to check for the [`Strs`], ignoring possible
222    /// [`Ghost`]s, see [`is_empty`].
223    ///
224    /// [`is_empty`]: Strs::is_empty
225    pub fn is_empty_empty(&self) -> bool {
226        self.0.buf.is_empty() && self.0.tags.is_empty()
227    }
228
229    /// The parts that make up a [`Text`].
230    ///
231    /// This function is used when you want to [insert]/[remove]
232    /// [`Tag`]s (i.e., borrow the inner `InnerTags` mutably via
233    /// [`Tags`]), while still being able to read from the
234    /// [`Strs`] and [`Selections`].
235    ///
236    /// [insert]: Tags::insert
237    /// [remove]: Tags::remove
238    pub fn parts(&mut self) -> TextParts<'_> {
239        TextParts {
240            strs: &self.0.buf,
241            tags: self.0.tags.tags(),
242            selections: &self.0.selections,
243        }
244    }
245
246    /// Returns the [`TextMut`] for this `Text`.
247    ///
248    /// This function is used by [`Widget::text_mut`], since that
249    /// function is not supposed to allow the user to swap the
250    /// [`Text`], which could break the history of the [`Buffer`].
251    ///
252    /// For the `Buffer` specifically, it also attaches that `Buffer`
253    /// s `History` to it, which lets one undo and redo things.
254    ///
255    /// [`Buffer`]: crate::buffer::Buffer
256    pub fn as_mut(&mut self) -> TextMut<'_> {
257        TextMut { text: self, history: None }
258    }
259
260    ////////// Tag related query functions
261
262    /// The maximum [points] in the `at`th byte.
263    ///
264    /// This point is essentially the [point] at that byte, plus the
265    /// last possible [`Point`] of any [`Ghost`]s in that
266    /// position.
267    ///
268    /// [points]: TwoPoints
269    /// [point]: Strs::point_at_byte
270    #[track_caller]
271    pub fn ghost_max_points_at(&self, b: usize) -> TwoPoints {
272        let point = self.point_at_byte(b);
273        if let Some(total_ghost) = self.0.tags.ghosts_total_at(point.byte()) {
274            TwoPoints::new(point, total_ghost)
275        } else {
276            TwoPoints::new_after_ghost(point)
277        }
278    }
279
280    /// The [points] at the end of the text.
281    ///
282    /// This will essentially return the [last point] of the text,
283    /// alongside the last possible [`Point`] of any [`Ghost`] at the
284    /// end of the text.
285    ///
286    /// [points]: TwoPoints
287    /// [last point]: Strs::len
288    pub fn len_points(&self) -> TwoPoints {
289        self.ghost_max_points_at(self.len())
290    }
291
292    /// Points visually after the [`TwoPoints`].
293    ///
294    /// If the [`TwoPoints`] in question is concealed, treats the
295    /// next visible character as the first character, and returns
296    /// the points of the next visible character.
297    ///
298    /// This method is useful if you want to iterator reversibly
299    /// right after a certain point, thus including the character
300    /// of said point.
301    #[track_caller]
302    pub fn points_after(&self, tp: TwoPoints) -> Option<TwoPoints> {
303        self.iter_fwd(tp)
304            .filter_map(|item| item.part.as_char().map(|_| item.points()))
305            .chain([self.len_points()])
306            .nth(1)
307    }
308
309    /// The visual start of the line.
310    ///
311    /// This point is defined not by where the line actually begins,
312    /// but by where the last '\n' was located. For example, if
313    /// [`Tag`]s create ghost text or omit text from multiple
314    /// different lines, this point may differ from where in the
315    /// [`Text`] the real line actually begins.
316    ///
317    /// The `skip` value is how many `\n` should be skipped before
318    /// returning.
319    pub fn visual_line_start(&self, mut points: TwoPoints, skip: usize) -> TwoPoints {
320        let mut iter = self.iter_rev(points).peekable();
321        let mut total_seen = 0;
322        while let Some(peek) = iter.peek() {
323            match peek.part {
324                TextPart::Char('\n') => {
325                    if total_seen == skip {
326                        return points;
327                    } else {
328                        total_seen += 1;
329                    }
330                }
331                TextPart::Char(_) => points = iter.next().unwrap().points(),
332                _ => _ = iter.next(),
333            }
334        }
335
336        points
337    }
338
339    /// Gets the [`Ghost`] of a given [`GhostId`]
340    pub fn get_ghost(&self, id: GhostId) -> Option<&Text> {
341        self.0.tags.get_ghost(id)
342    }
343
344    ////////// Modification functions
345
346    /// Replaces a [range] in the `Text`.
347    ///
348    /// # [`TextRange`] behavior:
349    ///
350    /// If you give a single [`usize`]/[`Point`], it will be
351    /// interpreted as a range from.
352    ///
353    /// [range]: TextRange
354    pub fn replace_range(&mut self, range: impl TextRange, edit: impl ToString) {
355        let range = range.to_range(self.len());
356        let (start, end) = (
357            self.point_at_byte(range.start),
358            self.point_at_byte(range.end),
359        );
360        let change = Change::new(edit, start..end, self);
361
362        self.0.buf.increment_version();
363        self.apply_change(0, change.as_ref());
364    }
365
366    /// Merges `String`s with the body of text, given a range to
367    /// replace.
368    fn apply_change(&mut self, guess_i: usize, change: Change<&str>) -> usize {
369        self.0.buf.apply_change(change);
370        self.0.tags.transform(
371            change.start().byte()..change.taken_end().byte(),
372            change.added_end().byte(),
373        );
374
375        self.0.has_unsaved_changes = true;
376        self.0.selections.apply_change(guess_i, change)
377    }
378
379    /// Inserts a `Text` into this `Text`, in a specific [`Point`].
380    pub fn insert_text(&mut self, p: impl TextIndex, text: &Text) {
381        let b = p.to_byte_index().min(self.last_point().byte());
382        let cap = text.last_point().byte();
383
384        let added_str = text.0.buf[..cap].to_string();
385        let point = self.point_at_byte(b);
386        let change = Change::str_insert(&added_str, point);
387        self.apply_change(0, change);
388
389        self.0.tags.insert_tags(point, cap, &text.0.tags);
390    }
391
392    fn apply_and_process_changes<'a>(
393        &mut self,
394        changes: impl ExactSizeIterator<Item = Change<'a, &'a str>>,
395    ) {
396        self.0.selections.clear();
397
398        let len = changes.len();
399        for (i, change) in changes.enumerate() {
400            self.apply_change(0, change);
401
402            let start = change.start().min(self.last_point());
403            let added_end = match change.added_str().chars().next_back() {
404                Some(last) => change.added_end().rev(last),
405                None => start,
406            };
407
408            let selection = Selection::new(added_end, (start != added_end).then_some(start));
409            self.0.selections.insert(i, selection, i == len - 1);
410        }
411    }
412
413    ////////// Writing functions
414
415    /// Writes the contents of this `Text` to a [writer].
416    ///
417    /// [writer]: std::io::Write
418    pub fn save_on(&mut self, mut writer: impl std::io::Write) -> std::io::Result<usize> {
419        self.0.has_unsaved_changes = false;
420
421        let [s0, s1] = self.0.buf.slices(..);
422        Ok(writer.write(s0)? + writer.write(s1)?)
423    }
424
425    /// Wether or not the content has changed since the last [save].
426    ///
427    /// Returns `true` only if the actual buf of the [`Text`] have
428    /// been changed, ignoring [`Tag`]s and all the other things,
429    /// since those are not written to the filesystem.
430    ///
431    /// [save]: Text::save_on
432    pub fn has_unsaved_changes(&self) -> bool {
433        self.0.has_unsaved_changes
434    }
435
436    ////////// Tag addition/deletion functions
437
438    /// Inserts a [`Tag`] at the given position.
439    #[track_caller]
440    pub fn insert_tag<Idx>(&mut self, tagger: Tagger, idx: Idx, tag: impl Tag<Idx>) {
441        self.0.tags.insert_inner(tagger, idx, tag, false)
442    }
443
444    /// Like [`insert_tag`], but does it after other [`Tag`]s with the
445    /// same priority.
446    ///
447    /// [`insert_tag`]: Self::insert_tag
448    pub fn insert_tag_after<Idx>(&mut self, tagger: Tagger, idx: Idx, tag: impl Tag<Idx>) {
449        self.0.tags.insert_inner(tagger, idx, tag, true)
450    }
451
452    /// Removes the [`Tag`]s of a [`Tagger`] from a region.
453    ///
454    /// The input can either be a byte index, a [`Point`], or a
455    /// [range] of byte indices/[`Point`]s. If you are implementing a
456    /// [`Buffer`] updating hook through [`BufferUpdated`], it can be
457    /// very useful to just "undo" all of the [`Tag`] additions done
458    /// by previous updates, you can do that efficiently with this
459    /// function:
460    ///
461    /// ```rust
462    /// # duat_core::doc_duat!(duat);
463    /// use duat::prelude::*;
464    /// setup_duat!(setup);
465    ///
466    /// fn setup() {
467    ///     let tagger = Tagger::new();
468    ///
469    ///     hook::add::<BufferUpdated>(move |pa, handle| {
470    ///         let buf = handle.write(pa);
471    ///         // Removing on the whole Buffer
472    ///         buf.text_mut().remove_tags(tagger, ..);
473    ///         // Logic to add Tags with tagger...
474    ///     });
475    /// }
476    /// ```
477    ///
478    /// [range]: std::ops::RangeBounds
479    /// [`Buffer`]: crate::buffer::Buffer
480    /// [`BufferUpdated`]: crate::hook::BufferUpdated
481    pub fn remove_tags(&mut self, tagger: Tagger, range: impl TextRangeOrIndex) {
482        let range = range.to_range(self.len() + 1);
483        self.0.tags.remove_from(tagger, range)
484    }
485
486    /// Just like [`Text::remove_tags`] but excludes ends on the start
487    /// and starts on the end.
488    ///
489    /// In the regular [`remove_tags`] function, if you remove from a
490    /// range `x..y`, tag ranges that end in `x` or start in `y -
491    /// 1` (exclusive range) will also be removed.
492    ///
493    /// If you don't want that to happen, you can use this function
494    /// instead.
495    ///
496    /// [`remove_tags`]: Self::remove_tags
497    pub fn remove_tags_excl(&mut self, tagger: Tagger, range: impl TextRangeOrIndex) {
498        let range = range.to_range(self.len() + 1);
499        self.0.tags.remove_from_excl(tagger, range)
500    }
501
502    /// Like [`Text::remove_tags`], but removes base on a predicate.
503    ///
504    /// If the function returns `true`, then the tag is removed. Note
505    /// that every [`RawTag`] in here is guaranteed to have the same
506    /// [`Tagger`] as the one passed to the function, so you don't
507    /// need to chack for that.
508    pub fn remove_tags_if(
509        &mut self,
510        tagger: Tagger,
511        from: impl TextRangeOrIndex,
512        filter: impl FnMut(usize, RawTag) -> bool,
513    ) {
514        let range = from.to_range(self.len() + 1);
515        self.0.tags.remove_from_if(tagger, range, filter)
516    }
517
518    /// Removes all [`Tag`]s.
519    ///
520    /// Refrain from using this function on [`Buffer`]s, as there may
521    /// be other [`Tag`] providers, and you should avoid messing
522    /// with their tags.
523    ///
524    /// [`Buffer`]: crate::buffer::Buffer
525    pub fn clear_tags(&mut self) {
526        self.0.tags = InnerTags::new(self.0.buf.len());
527    }
528
529    /////////// Internal synchronization functions
530
531    /// Prepares the `Text` for reloading, to be used on [`Buffer`]s.
532    ///
533    /// [`Buffer`]: crate::buffer::Buffer
534    pub(crate) fn prepare_for_reloading(&mut self) {
535        self.clear_tags();
536    }
537
538    /////////// Iterator methods
539
540    /// A forward iterator of the [chars and tags] of the [`Text`].
541    ///
542    /// [chars and tags]: TextPart
543    #[track_caller]
544    pub fn iter_fwd(&self, at: TwoPoints) -> FwdIter<'_> {
545        FwdIter::new_at(self, at, false)
546    }
547
548    /// A reverse iterator of the [chars and tags] of the [`Text`]
549    ///
550    /// [chars and tags]: TextPart
551    pub fn iter_rev(&self, at: TwoPoints) -> RevIter<'_> {
552        RevIter::new_at(self, at)
553    }
554
555    /// A forward iterator over the [`Tag`]s of the [`Text`].
556    ///
557    /// This iterator will consider some [`Tag`]s before `b`, since
558    /// their ranges may overlap with `b`.
559    ///
560    /// The amount of tags to look for behind depeds on the internal
561    /// `min_len` factor. You can override by providing a lookaround,
562    /// which will tell Duat how many `Tag`s to look behind. If you
563    /// set it to `Some(0)`, lookaround will be disabled.
564    ///
565    /// # Note
566    ///
567    /// Duat works fine with [`Tag`]s in the middle of a codepoint,
568    /// but external utilizers may not, so keep that in mind.
569    pub fn tags_fwd(&self, b: usize, lookaround: Option<usize>) -> FwdTags<'_> {
570        self.0.tags.fwd_at(b, lookaround)
571    }
572
573    /// An reverse iterator over the [`Tag`]s of the [`Text`].
574    ///
575    /// This iterator will consider some `Tag`s ahead of `b`, since
576    /// their ranges may overlap with `b`.
577    ///
578    /// The amount of tags to look for ahead depeds on the internal
579    /// `min_len` factor. You can override by providing a lookaround,
580    /// which will tell Duat how many `Tag`s to look ahead. If you set
581    /// it to `Some(0)`, lookaround will be disabled.
582    ///
583    /// # Note
584    ///
585    /// Duat works fine with [`Tag`]s in the middle of a codepoint,
586    /// but external utilizers may not, so keep that in mind.
587    pub fn tags_rev(&self, b: usize, lookaround: Option<usize>) -> RevTags<'_> {
588        self.0.tags.rev_at(b, lookaround)
589    }
590
591    /// A forward [`Iterator`] over the [`RawTag`]s.
592    ///
593    /// This [`Iterator`] does not take into account [`Tag`] ranges
594    /// that intersect with the starting point, unlike
595    /// [`Text::tags_fwd`]
596    pub fn raw_tags_fwd(&self, b: usize) -> impl Iterator<Item = (usize, RawTag)> {
597        self.0.tags.raw_fwd_at(b)
598    }
599
600    /// A reverse [`Iterator`] over the [`RawTag`]s.
601    ///
602    /// This [`Iterator`] does not take into account [`Tag`] ranges
603    /// that intersect with the starting point, unlike
604    /// [`Text::tags_rev`]
605    pub fn raw_tags_rev(&self, b: usize) -> impl Iterator<Item = (usize, RawTag)> {
606        self.0.tags.raw_rev_at(b)
607    }
608
609    /// The [`Selections`] printed to this `Text`, if they exist.
610    pub fn selections(&self) -> &Selections {
611        &self.0.selections
612    }
613
614    /// A mut reference to this `Text`'s [`Selections`] if they
615    /// exist.
616    pub fn selections_mut(&mut self) -> &mut Selections {
617        &mut self.0.selections
618    }
619
620    /// Gets the main [`Selection`], if there is one.
621    ///
622    /// If you want a method that doesn't return an [`Option`] (for
623    /// convenience), see [`Text::main_sel`].
624    pub fn get_main_sel(&self) -> Option<&Selection> {
625        self.0.selections.get_main()
626    }
627
628    /// Gets the main [`Selection`].
629    ///
630    /// # Panics
631    ///
632    /// This method will panic if there are no `Selection`s. If you
633    /// want a non-panicking method, see [`Text::get_main_sel`].
634    #[track_caller]
635    pub fn main_sel(&self) -> &Selection {
636        self.0.selections.main()
637    }
638
639    /// A list of all [`SpawnId`]s that belong to this `Text`
640    pub fn get_spawned_ids(&self) -> impl Iterator<Item = SpawnId> {
641        self.0.tags.get_spawned_ids()
642    }
643
644    /// Returns a [`String`], but without the `\n` at the end of the
645    /// `Text`.
646    ///
647    /// Normally, when you call `Text::to_string`, (which is actually
648    /// [deref'd] into [`Strs::to_string`]), it will also include the
649    /// last `\n` character, which is always a part of the `Text`
650    /// no matter what. This function doesn't do that.
651    ///
652    /// [deref'd]: https://doc.rust-lang.org/std/ops/trait.Deref.html
653    /// [`Strs::to_string`]: ToString::to_string
654    pub fn to_string_no_last_nl(&self) -> String {
655        let mut string = self.to_string();
656        string.pop();
657        string
658    }
659
660    /// A struct representing how many changes took place since the
661    /// creation of this `Text`
662    ///
663    /// This struct tracks all [`Change`]s and [`Tag`]
664    /// additions/removals, giving you information about wether this
665    /// `Text` has changed, when comparing this to previous
666    /// [`TextVersion`]s of the same `Text`.
667    ///
668    /// This _does_ also include things like undoing and redoing. This
669    /// is done to keep track of all changes that took place, even to
670    /// previously extant states of the text.
671    pub fn version(&self) -> TextVersion {
672        let (tags, meta_tags) = self.0.tags.versions();
673
674        TextVersion {
675            strs: self.0.buf.get_version(),
676            tags,
677            meta_tags,
678        }
679    }
680}
681
682impl std::ops::Deref for Text {
683    type Target = Strs;
684
685    fn deref(&self) -> &Self::Target {
686        &self.0.buf
687    }
688}
689
690/// A struct that allows for [`Text`] modifications from the
691/// [`Widget::text_mut`] function.
692///
693/// It is pretty much identical to `&mut Text`, the difference is that
694/// you can't reassign it to a new [`Text`]. This is done in order to
695/// prevent radical changes to the `Text` of the [`Buffer`] from the
696/// outside.
697///
698/// [`Buffer`]: crate::buffer::Buffer
699#[derive(Debug)]
700pub struct TextMut<'t> {
701    text: &'t mut Text,
702    history: Option<&'t mut History>,
703}
704
705impl<'t> TextMut<'t> {
706    /// Replaces a [range] in the `Text`.
707    ///
708    /// # [`TextRange`] behavior:
709    ///
710    /// If you give a single [`usize`]/[`Point`], it will be
711    /// interpreted as a range from.
712    ///
713    /// [range]: TextRange
714    pub fn replace_range(&mut self, range: impl TextRange, edit: impl ToString) {
715        let range = range.to_range(self.len());
716        let (start, end) = (
717            self.point_at_byte(range.start),
718            self.point_at_byte(range.end),
719        );
720        let change = Change::new(edit, start..end, self);
721
722        self.text.0.buf.increment_version();
723        self.text.apply_change(0, change.as_ref());
724        self.history.as_mut().map(|h| h.apply_change(None, change));
725    }
726
727    /// Applies a [`Change`] to the `Text`.
728    pub(crate) fn apply_change(
729        &mut self,
730        guess_i: Option<usize>,
731        change: Change<'static, String>,
732    ) -> (Option<usize>, usize) {
733        self.text.0.buf.increment_version();
734        let selections_taken = self
735            .text
736            .apply_change(guess_i.unwrap_or(0), change.as_ref());
737        let history = self.history.as_mut();
738        let insertion_i = history.map(|h| h.apply_change(guess_i, change));
739        (insertion_i, selections_taken)
740    }
741
742    ////////// Functions for Tag modifications
743
744    /// The parts that make up a [`Text`].
745    ///
746    /// This function is used when you want to [insert]/[remove]
747    /// [`Tag`]s (i.e., borrow the inner `InnerTags` mutably via
748    /// [`Tags`]), while still being able to read from the
749    /// [`Strs`] and [`Selections`].
750    ///
751    /// [insert]: Tags::insert
752    /// [remove]: Tags::remove
753    pub fn parts(self) -> TextParts<'t> {
754        self.text.parts()
755    }
756
757    /// Inserts a [`Tag`] at the given position.
758    pub fn insert_tag<Idx>(&mut self, tagger: Tagger, idx: Idx, tag: impl Tag<Idx>) {
759        self.text.insert_tag(tagger, idx, tag)
760    }
761
762    /// Like [`insert_tag`], but does it after other [`Tag`]s with the
763    /// same priority.
764    ///
765    /// [`insert_tag`]: Self::insert_tag
766    pub fn insert_tag_after<Idx>(&mut self, tagger: Tagger, idx: Idx, tag: impl Tag<Idx>) {
767        self.text.insert_tag_after(tagger, idx, tag)
768    }
769
770    /// Removes the [`Tag`]s of a [`Tagger`] from a region.
771    ///
772    /// The input can either be a byte index, a [`Point`], or a
773    /// [range] of byte indices/[`Point`]s. If you are implementing a
774    /// [`Buffer`] updating hook through [`BufferUpdated`], it can be
775    /// very useful to just "undo" all of the [`Tag`] additions done
776    /// by previous updates, you can do that efficiently with this
777    /// function:
778    ///
779    /// ```rust
780    /// # duat_core::doc_duat!(duat);
781    /// use duat::prelude::*;
782    /// setup_duat!(setup);
783    ///
784    /// fn setup() {
785    ///     let tagger = Tagger::new();
786    ///
787    ///     hook::add::<BufferUpdated>(move |pa, handle| {
788    ///         let buf = handle.write(pa);
789    ///         // Removing on the whole Buffer
790    ///         buf.text_mut().remove_tags(tagger, ..);
791    ///         // Logic to add Tags with tagger...
792    ///     });
793    /// }
794    /// ```
795    ///
796    /// [range]: std::ops::RangeBounds
797    /// [`Buffer`]: crate::buffer::Buffer
798    /// [`BufferUpdated`]: crate::hook::BufferUpdated
799    pub fn remove_tags(&mut self, tagger: Tagger, range: impl TextRangeOrIndex) {
800        let range = range.to_range(self.len() + 1);
801        self.text.remove_tags(tagger, range)
802    }
803
804    /// Just like [`TextMut::remove_tags`] but excludes ends on the
805    /// start and starts on the end.
806    ///
807    /// In the regular [`remove_tags`] function, if you remove from a
808    /// range `x..y`, tag ranges that end in `x` or start in `y -
809    /// 1` (exclusive range) will also be removed.
810    ///
811    /// If you don't want that to happen, you can use this function
812    /// instead.
813    ///
814    /// [`remove_tags`]: Self::remove_tags
815    pub fn remove_tags_excl(&mut self, tagger: Tagger, range: impl TextRangeOrIndex) {
816        let range = range.to_range(self.len() + 1);
817        self.text.remove_tags_excl(tagger, range)
818    }
819
820    /// Like [`TextMut::remove_tags`], but removes base on a
821    /// predicate.
822    ///
823    /// If the function returns `true`, then the tag is removed. Note
824    /// that every [`RawTag`] in here is guaranteed to have the same
825    /// [`Tagger`] as the one passed to the function, so you don't
826    /// need to chack for that.
827    pub fn remove_tags_if(
828        &mut self,
829        tagger: Tagger,
830        from: impl TextRangeOrIndex,
831        filter: impl FnMut(usize, RawTag) -> bool,
832    ) {
833        let range = from.to_range(self.len() + 1);
834        self.text.remove_tags_if(tagger, range, filter)
835    }
836
837    /// Removes all [`Tag`]s.
838    ///
839    /// Refrain from using this function on [`Buffer`]s, as there may
840    /// be other [`Tag`] providers, and you should avoid messing
841    /// with their tags.
842    ///
843    /// [`Buffer`]: crate::buffer::Buffer
844    pub fn clear_tags(&mut self) {
845        self.text.clear_tags();
846    }
847
848    ////////// Internal methods
849
850    /// Updates bounds, so that [`Tag`] ranges can visibly cross the
851    /// screen.
852    ///
853    /// This is used in order to allow for very long [`Tag`] ranges
854    /// (say, a [`Form`] being applied on the range `3..999`) to show
855    /// up properly without having to lookback a bazillion [`Tag`]s
856    /// which could be in the way.
857    ///
858    /// [`Form`]: crate::form::Form
859    pub(crate) fn update_bounds(&mut self) {
860        self.text.0.tags.update_bounds();
861    }
862
863    /// Functions to add  all [`Widget`]s that were spawned in this
864    /// `Text`.
865    ///
866    /// This function should only be called right before printing,
867    /// where it is "known" that `Widget`s can no longer get rid of
868    /// the [`SpawnTag`]s
869    ///
870    /// [`Widget`]: crate::ui::Widget
871    pub(crate) fn get_widget_spawns(
872        &mut self,
873    ) -> Vec<Box<dyn FnOnce(&mut Pass, usize, Handle<dyn Widget>) + Send>> {
874        std::mem::take(&mut self.text.0.tags.spawn_fns.0)
875    }
876
877    ////////// History functions
878
879    /// Undoes the last moment, if there was one.
880    pub fn undo(&mut self) {
881        if let Some(history) = &mut self.history
882            && let Some((changes, saved_moment)) = history.move_backwards()
883        {
884            self.text.apply_and_process_changes(changes);
885            self.text.0.buf.increment_version();
886            self.text.0.has_unsaved_changes = !saved_moment;
887        }
888    }
889
890    /// Redoes the last moment in the history, if there is one.
891    pub fn redo(&mut self) {
892        if let Some(history) = &mut self.history
893            && let Some((changes, saved_moment)) = history.move_forward()
894        {
895            self.text.apply_and_process_changes(changes);
896            self.text.0.buf.increment_version();
897            self.text.0.has_unsaved_changes = !saved_moment;
898        }
899    }
900
901    /// Finishes the current moment and adds a new one to the history.
902    pub fn new_moment(&mut self) {
903        if let Some(h) = &mut self.history {
904            h.new_moment()
905        }
906    }
907
908    /// Attaches a history to this `TextMut`.
909    pub(crate) fn attach_history(&mut self, history: &'t mut History) {
910        self.history = Some(history);
911    }
912
913    ////////// Selections functions
914
915    /// A mut reference to this `Text`'s [`Selections`] if they
916    /// exist.
917    pub fn selections_mut(self) -> &'t mut Selections {
918        &mut self.text.0.selections
919    }
920}
921
922impl<'t> std::ops::Deref for TextMut<'t> {
923    type Target = Text;
924
925    fn deref(&self) -> &Self::Target {
926        self.text
927    }
928}
929
930impl AsRef<Strs> for Text {
931    fn as_ref(&self) -> &Strs {
932        &self.0.buf
933    }
934}
935
936/// The Parts that make up a [`Text`].
937pub struct TextParts<'a> {
938    /// The [`Strs`] of the whole [`Text`].
939    pub strs: &'a Strs,
940    /// The [`Tags`] of the [`Text`].
941    ///
942    /// This, unlike the previous field, allows mutation in the form
943    /// of [adding] and [removing] [`Tag`]s.
944    ///
945    /// [adding]: Tags::insert
946    /// [removing]: Tags::remove
947    pub tags: Tags<'a>,
948    /// The [`Selections`] of the [`Text`].
949    ///
950    /// For most [`Widget`]s, there should be no [`Selection`], since
951    /// they are just visual.
952    ///
953    /// [`Widget`]: crate::ui::Widget
954    pub selections: &'a Selections,
955}
956
957/// A representation of how many changes took place in a [`Text`].
958///
959/// The purpose of this struct is merely to be compared with
960/// previously acquired instances of itself, to just quickly check if
961/// certain properties of the `Text` have changed.
962///
963/// Note that this is a [`Text`] agnostic struct, comparing the
964/// `TextVersion`s from two different `Text`s is pointless.
965#[derive(Clone, Copy, Debug, PartialEq, Eq)]
966pub struct TextVersion {
967    /// The current version of the [`Strs`].
968    ///
969    /// Any change to the `Strs`, even undoing, will incur a version
970    /// increment.
971    pub strs: u64,
972    /// the current version of [`Tags`].
973    ///
974    /// Any change to the `Tags`, be it addition or removal of
975    /// [`Tag`]s, will incur a version increment.
976    pub tags: u64,
977    /// The current version of meta [`Tag`]s.
978    ///
979    /// Meta tags are those that can change what is even shown on the
980    /// screen, all else being equal. Any addition or removal of meta
981    /// `Tag`s will incur a version increment.
982    pub meta_tags: u64,
983}
984
985impl TextVersion {
986    /// Wether there have been _any_ changes to the [`Text`] since
987    /// this previous instance.
988    pub fn has_changed_since(&self, other: Self) -> bool {
989        self.strs > other.strs || self.tags > other.tags || self.meta_tags > other.meta_tags
990    }
991
992    /// Wether the [`Strs`] have changed since this previous instance.
993    pub fn strs_have_changed_since(&self, other: Self) -> bool {
994        self.strs > other.strs
995    }
996
997    /// Wether the [`Tags`] have changed since this previous instance.
998    ///
999    /// Note that this only tracks if [`Tag`]s have been
1000    /// added/removed. So if, for example, you [replace a range] where
1001    /// no `Tag`s existed, this would return `false`, even though the
1002    /// position of `Tag`s have changed internally.
1003    ///
1004    /// [replace a range]: Text::replace_range
1005    pub fn tags_have_changed_since(&self, other: Self) -> bool {
1006        self.tags > other.tags
1007    }
1008
1009    /// Wether this [`Text`] has "structurally changed" since this
1010    /// previous instance.
1011    ///
1012    /// A `Text` has structurally changed when printing it from the
1013    /// same point could result in a different characters being
1014    /// printed. This not only happens when the [`Strs`] change, but
1015    /// also with certain [`Tag`]s, like [`Ghost`] and [`Conceal`],
1016    /// which also add and remove characters to be printed.
1017    ///
1018    /// These `Tag`s are called "meta tags" internally, since they
1019    /// change the very structure of what `Text` has been printed.
1020    pub fn has_structurally_changed_since(&self, other: Self) -> bool {
1021        self.strs > other.strs || self.meta_tags > other.meta_tags
1022    }
1023}
1024
1025////////// Standard impls
1026
1027impl Default for Text {
1028    fn default() -> Self {
1029        Self::new()
1030    }
1031}
1032
1033impl<T: ToString> From<T> for Text {
1034    fn from(value: T) -> Self {
1035        Self::from_parts(value.to_string(), Selections::new_empty())
1036    }
1037}
1038
1039impl std::fmt::Debug for Text {
1040    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1041        f.debug_struct("Text")
1042            .field("buf", &self.0.buf)
1043            .field("tags", &self.0.tags)
1044            .finish_non_exhaustive()
1045    }
1046}
1047
1048impl Clone for Text {
1049    fn clone(&self) -> Self {
1050        let mut text = Self(self.0.clone());
1051        if text.bytes().next_back().is_none_or(|b| b != b'\n') {
1052            let end = text.end_point();
1053            text.apply_change(0, Change::str_insert("\n", end));
1054        }
1055
1056        text
1057    }
1058}
1059
1060impl Eq for Text {}
1061implPartialEq!(text: Text, other: Text,
1062    text.0.buf == other.0.buf && text.0.tags == other.0.tags
1063);
1064implPartialEq!(text: Text, other: &str, text.0.buf == *other);
1065implPartialEq!(text: Text, other: String, text.0.buf == *other);
1066implPartialEq!(str: &str, text: Text, text.0.buf == **str);
1067implPartialEq!(str: String, text: Text, text.0.buf == **str);
1068
1069impl Eq for TextMut<'_> {}
1070implPartialEq!(text_mut: TextMut<'_>, other: TextMut<'_>, text_mut.text == other.text);
1071implPartialEq!(text_mut: TextMut<'_>, other: Text, text_mut.text == other);
1072implPartialEq!(text_mut: TextMut<'_>, other: &str, text_mut.text.0.buf == *other);
1073implPartialEq!(text_mut: TextMut<'_>, other: String, text_mut.text.0.buf == *other);
1074implPartialEq!(text: Text, other: TextMut<'_>, *text == other.text);
1075implPartialEq!(str: &str, text_mut: TextMut<'_>, text_mut.text.0.buf == **str);
1076implPartialEq!(str: String, text_mut: TextMut<'_>, text_mut.text.0.buf == **str);