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