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 of 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//! - The ability to undo/redo changes in the history;
20//! - In the future, button ranges that can interact with the mouse;
21//!
22//! The [`Text`] struct is created in two different ways:
23//!
24//! - By calling [`Text::new`] or one of its [`From`] implementations;
25//! - By building it with the [`text!`] macro;
26//!
27//! The first method is recommended if you want a [`Text`] that will
28//! be modified by input. The only real example of this is the
29//! [`File`] widget.
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//! # use duat_core::text::{text, Text};
37//! fn number_of_horses(count: usize) -> Text {
38//!     if count == 1 {
39//!         text!([HorseCount] 1 " " [Horses] "horse")
40//!     } else {
41//!         text!([HorseCount] count " " [Horses] "horses")
42//!     }
43//! }
44//! fn inlined_number_of_horses(count: usize) -> Text {
45//!     text!([HorseCount] count " " [Horses] {
46//!         if count == 1 { "horse" } else { "horses" }
47//!     })
48//! }
49//! ```
50//!
51//! You can use this whenever you need to update a widget, for
52//! example, just create a new [`Text`] to printed to the screen.
53//!
54//! However, when recreating the entire [`Text`] with a [`text!`]
55//! macro would be too expensive, you can use [`Text`] modifying
56//! functions:
57//!
58//! ```rust
59//! # use duat_core::text::{text, Text};
60//! let mut prompted = text!([Prompt] "type a key:");
61//! let end = prompted.len();
62//! prompted.replace_range((end, end), "a")
63//! ```
64//!
65//! These would be used mostly on the [`File`] widget and other whose
66//! [`Mode`]s make use of [`EditHelper`]s.
67//!
68//! [gap buffers]: gapbuf::GapBuffer
69//! [colored]: crate::form::Form
70//! [ghost text]: Tag::Ghost
71//! [`Ui`]: crate::ui::Ui
72//! [`File`]: crate::widgets::File
73//! [`Widget`]: crate::widgets::Widget
74//! [`StatusLine`]: crate::widgets::StatusLine
75//! [`Mode`]: crate::mode::Mode
76//! [`EditHelper`]: crate::mode::EditHelper
77mod builder;
78mod bytes;
79mod history;
80mod iter;
81mod ops;
82mod reader;
83mod records;
84mod search;
85mod tags;
86
87use std::{
88    ops::Range,
89    path::Path,
90    rc::Rc,
91    sync::{
92        Arc,
93        atomic::{AtomicBool, Ordering},
94    },
95};
96
97pub(crate) use self::history::History;
98pub use self::{
99    builder::{
100        AlignCenter, AlignLeft, AlignRight, Builder, BuilderPart, Ghost, Spacer, err, hint, ok,
101        text,
102    },
103    bytes::{Buffers, Bytes, Strs},
104    history::Change,
105    iter::{FwdIter, Item, Part, RevIter},
106    ops::{Point, TextRange, TwoPoints, utf8_char_width},
107    reader::{MutTags, Reader, ReaderCfg},
108    search::{Matcheable, RegexPattern, Searcher},
109    tags::{Key, Keys, RawTag, Tag, ToggleId},
110};
111use self::{
112    reader::Readers,
113    tags::{FwdTags, GhostId, RevTags, Tags},
114};
115use crate::{
116    cache,
117    cfg::PrintCfg,
118    form,
119    mode::{Cursor, Cursors},
120    ui::Area,
121};
122
123/// The text in a given [`Area`]
124pub struct Text(Box<InnerText>);
125
126struct InnerText {
127    bytes: Bytes,
128    tags: Tags,
129    cursors: Option<Cursors>,
130    // Specific to Files
131    history: Option<History>,
132    readers: Readers,
133    has_changed: bool,
134    has_unsaved_changes: AtomicBool,
135    // Used in Text building
136    forced_new_line: bool,
137}
138
139impl Text {
140    ////////// Creation of Text
141
142    /// Returns a new empty [`Text`]
143    pub fn new() -> Self {
144        Self::from_bytes(Bytes::default(), None, false)
145    }
146
147    pub fn new_with_cursors() -> Self {
148        Self::from_bytes(Bytes::default(), Some(Cursors::default()), false)
149    }
150
151    /// Returns a new empty [`Text`] with history enabled
152    pub(crate) fn new_with_history() -> Self {
153        Self::from_bytes(Bytes::default(), Some(Cursors::default()), true)
154    }
155
156    /// Creates a [`Text`] from a file's [path]
157    ///
158    /// [path]: Path
159    pub(crate) fn from_file(
160        bytes: Bytes,
161        cursors: Cursors,
162        path: impl AsRef<Path>,
163        has_unsaved_changes: bool,
164    ) -> Self {
165        let cursors = if let Some(cursor) = cursors.get_main()
166            && let Some(_) = bytes.char_at(cursor.caret())
167        {
168            cursors
169        } else {
170            Cursors::default()
171        };
172
173        let mut text = Self::from_bytes(bytes, Some(cursors), true);
174        text.0
175            .has_unsaved_changes
176            .store(has_unsaved_changes, Ordering::Relaxed);
177
178        if let Some(history) = cache::load_cache(path.as_ref()) {
179            text.0.history = Some(history);
180        }
181
182        text
183    }
184
185    /// Creates a [`Text`] from [`Bytes`]
186    pub(crate) fn from_bytes(
187        mut bytes: Bytes,
188        cursors: Option<Cursors>,
189        with_history: bool,
190    ) -> Self {
191        let forced_new_line = if bytes.buffers(..).next_back().is_none_or(|b| b != b'\n') {
192            let end = bytes.len();
193            bytes.apply_change(Change::str_insert("\n", end));
194            true
195        } else {
196            false
197        };
198        let tags = Tags::new(bytes.len().byte());
199
200        Self(Box::new(InnerText {
201            bytes,
202            tags,
203            cursors,
204            history: with_history.then(History::new),
205            readers: Readers::default(),
206            forced_new_line,
207            has_changed: false,
208            has_unsaved_changes: AtomicBool::new(false),
209        }))
210    }
211
212    /// Returns an empty [`Text`], only for [`Builder`]s
213    fn empty() -> Self {
214        Self(Box::new(InnerText {
215            bytes: Bytes::default(),
216            tags: Tags::new(0),
217            cursors: None,
218            history: None,
219            readers: Readers::default(),
220            has_changed: false,
221            has_unsaved_changes: AtomicBool::new(false),
222            forced_new_line: false,
223        }))
224    }
225
226    /// Returns a [`Builder`] for [`Text`]
227    ///
228    /// This builder can be used to iteratively create text, by
229    /// assuming that the user wants no* [`Tag`] overlap, and that
230    /// they want to construct the [`Text`] in [`Tag`]/content pairs.
231    ///
232    /// ```rust
233    /// use duat_core::text::{Tag, Text, text};
234    /// let mut builder = Text::builder();
235    /// ```
236    pub fn builder() -> Builder {
237        Builder::new()
238    }
239
240    ////////// Querying functions
241
242    /// The [`Point`] at the end of the text
243    pub fn len(&self) -> Point {
244        self.0.bytes.len()
245    }
246
247    /// Whether or not there are any characters in the [`Text`]
248    ///
249    /// This ignores the last `'\n'` in the [`Text`], since it is
250    /// always there no matter what.
251    ///
252    /// # Notes
253    ///
254    /// This does not check for tags, so with a [`Tag::Ghost`],
255    /// there could actually be a "string" of characters on the
256    /// [`Text`], it just wouldn't be considered real "text".
257    pub fn is_empty(&self) -> bool {
258        self.0.bytes == "\n"
259    }
260
261    /// The `char` at the [`Point`]'s position
262    pub fn char_at(&self, point: Point) -> Option<char> {
263        self.0.bytes.char_at(point)
264    }
265
266    /// An [`Iterator`] over the bytes of the [`Text`]
267    pub fn buffers(&self, range: impl TextRange) -> Buffers {
268        self.0.bytes.buffers(range)
269    }
270
271    /// An [`Iterator`] over the [`&str`]s of the [`Text`]
272    ///
273    /// # Note
274    ///
275    /// The reason why this function returns two strings is that the
276    /// contents of the text are stored in a [`GapBuffer`], which
277    /// works with two strings.
278    ///
279    /// If you want to iterate over them, you can do the following:
280    ///
281    /// ```rust
282    /// # use duat_core::text::{Point, Text};
283    /// # let (p1, p2) = (Point::default(), Point::default());
284    /// let text = Text::new();
285    /// text.strs((p1, p2)).flat_map(str::chars);
286    /// ```
287    ///
288    /// Do note that you should avoid iterators like [`str::lines`],
289    /// as they will separate the line that is partially owned by each
290    /// [`&str`]:
291    ///
292    /// ```rust
293    /// let broken_up_line = [
294    ///     "This is line 1, business as usual.\nThis is line 2, but it",
295    ///     "is broken into two separate strings.\nSo 4 lines would be counted, \
296    ///      instead of 3",
297    /// ];
298    /// ```
299    ///
300    /// # [`TextRange`] behavior:
301    ///
302    /// If you give a single [`usize`]/[`Point`], it will be
303    /// interpreted as a range from.
304    ///
305    /// [`&str`]: str
306    /// [`GapBuffer`]: gapbuf::GapBuffer
307    pub fn strs(&self, range: impl TextRange) -> Strs {
308        self.0.bytes.strs(range)
309    }
310
311    /// Returns an iterator over the lines in a given range
312    ///
313    /// The lines are inclusive, that is, it will iterate over the
314    /// whole line, not just the parts within the range.
315    pub fn lines(
316        &mut self,
317        range: impl TextRange,
318    ) -> impl DoubleEndedIterator<Item = (usize, &str)> + '_ {
319        self.0.bytes.lines(range)
320    }
321
322    /// The inner bytes of the [`Text`]
323    pub fn bytes(&self) -> &Bytes {
324        &self.0.bytes
325    }
326
327    /// The inner bytes of the [`Text`], mutably
328    ///
329    /// Do note that this mutability isn't actually for modifying the
330    /// [`Bytes`] themselves, but instead it is used by some methods
331    /// to read said bytes, like [`make_contiguous`] or [`lines`]
332    ///
333    /// [`make_contiguous`]: Bytes::make_contiguous
334    /// [`lines`]: Bytes::lines
335    pub fn bytes_mut(&mut self) -> &mut Bytes {
336        &mut self.0.bytes
337    }
338
339    /// Gets the indentation level on the current line
340    pub fn indent(&self, p: Point, area: &impl Area, cfg: PrintCfg) -> usize {
341        let [start, _] = self.points_of_line(p.line());
342        let t_iter = self.iter_fwd(start).no_ghosts().no_conceals();
343        area.print_iter(t_iter, cfg.new_line_as('\n'))
344            .filter_map(|(caret, item)| Some(caret).zip(item.part.as_char()))
345            .find(|(_, char)| !char.is_whitespace() || *char == '\n')
346            .map(|(caret, _)| caret.x as usize)
347            .unwrap_or(0)
348    }
349
350    /////////// Reader functions
351
352    /// Adds a [`Reader`] to this [`Text`]
353    ///
354    /// A [`Reader`] will be informed of every change done to this
355    /// [`Text`], and can add or remove [`Tag`]s accordingly. Examples
356    /// of [`Reader`]s are the [tree-sitter] parser, and regex
357    /// parsers. Those can be used for, among other things, syntax
358    /// hightlighting.
359    pub fn add_reader(&mut self, reader_cfg: impl ReaderCfg) -> Result<(), Text> {
360        self.0
361            .readers
362            .add(&mut self.0.bytes, &mut self.0.tags, reader_cfg)
363    }
364
365    pub fn get_reader<R: Reader>(&mut self) -> Option<R::PublicReader<'_>> {
366        self.0.readers.get_mut::<R>(&mut self.0.bytes)
367    }
368
369    ////////// Point querying functions
370
371    /// The [`Point`] corresponding to the byte position, 0 indexed
372    ///
373    /// If the byte position would fall in between two characters
374    /// (because the first one comprises more than one byte), the
375    /// first character is chosen as the [`Point`] where the byte is
376    /// located.
377    ///
378    /// # Panics
379    ///
380    /// Will panic if `b` is greater than the length of the text
381    #[inline(always)]
382    pub fn point_at(&self, b: usize) -> Point {
383        self.0.bytes.point_at(b)
384    }
385
386    /// The [`Point`] associated with a char position, 0 indexed
387    ///
388    /// # Panics
389    ///
390    /// Will panic if `c` is greater than the number of chars in the
391    /// text.
392    #[inline(always)]
393    pub fn point_at_char(&self, c: usize) -> Point {
394        self.0.bytes.point_at_char(c)
395    }
396
397    /// The [`Point`] where the `l`th line starts, 0 indexed
398    ///
399    /// If `l == number_of_lines`, returns the last point of the
400    /// text.
401    ///
402    /// # Panics
403    ///
404    /// Will panic if `l` is greater than the number of lines on the
405    /// text
406    #[inline(always)]
407    pub fn point_at_line(&self, l: usize) -> Point {
408        self.0.bytes.point_at_line(l)
409    }
410
411    /// The start and end [`Point`]s for a given `l` line
412    ///
413    /// If `l == number_of_lines`, these points will be the same.
414    ///
415    /// # Panics
416    ///
417    /// Will panic if the number `l` is greater than the number of
418    /// lines on the text
419    #[inline(always)]
420    pub fn points_of_line(&self, l: usize) -> [Point; 2] {
421        self.0.bytes.points_of_line(l)
422    }
423
424    /// The [points] at the end of the text
425    ///
426    /// This will essentially return the [last point] of the text,
427    /// alongside the last possible [`Point`] of any
428    /// [`Tag::Ghost`] at the end of the text.
429    ///
430    /// [points]: TwoPoints
431    /// [last point]: Self::len
432    pub fn len_points(&self) -> (Point, Option<Point>) {
433        self.ghost_max_points_at(self.len().byte())
434    }
435
436    /// The last [`Point`] associated with a `char`
437    ///
438    /// This will give the [`Point`] of the last `char` of the text.
439    /// The difference between this method and [`len`] is that
440    /// it will return a [`Point`] one position earlier than it. If
441    /// the text is completely empty, it will return [`None`].
442    ///
443    /// [`len`]: Self::len
444    pub fn last_point(&self) -> Option<Point> {
445        self.0.bytes.last_point()
446    }
447
448    ////////// Tag related query functions
449
450    /// The maximum [points] in the `at`th byte
451    ///
452    /// This point is essentially the [point] at that byte, plus the
453    /// last possible [`Point`] of any [`Tag::Ghost`]s in that
454    /// position.
455    ///
456    /// [points]: TwoPoints
457    /// [point]: Self::point_at
458    #[inline(always)]
459    pub fn ghost_max_points_at(&self, at: usize) -> (Point, Option<Point>) {
460        let point = self.point_at(at);
461        (point, self.0.tags.ghosts_total_at(point.byte()))
462    }
463
464    /// Points visually after the [`TwoPoints`]
465    ///
466    /// If the [`TwoPoints`] in question is concealed, treats the
467    /// next visible character as the first character, and returns
468    /// the points of the next visible character.
469    ///
470    /// This method is useful if you want to iterator reversibly
471    /// right after a certain point, thus including the character
472    /// of said point.
473    pub fn points_after(&self, tp: impl TwoPoints) -> Option<(Point, Option<Point>)> {
474        self.iter_fwd(tp)
475            .filter_map(|item| item.part.as_char().map(|_| item.points()))
476            .chain([self.len_points()])
477            .nth(1)
478    }
479
480    /// The visual start of the line
481    ///
482    /// This point is defined not by where the line actually begins,
483    /// but by where the last '\n' was located. For example, if
484    /// [`Tag`]s create ghost text or omit text from multiple
485    /// different lines, this point may differ from where in the
486    /// [`Text`] the physical line actually begins.
487    pub fn visual_line_start(&self, p: impl TwoPoints) -> (Point, Option<Point>) {
488        let (real, ghost) = p.to_points();
489
490        let mut iter = self.iter_rev((real, ghost)).peekable();
491        let mut points = (real, ghost);
492        while let Some(peek) = iter.peek() {
493            match peek.part {
494                Part::Char('\n') => {
495                    return points;
496                }
497                Part::Char(_) => points = iter.next().unwrap().to_points(),
498                _ => drop(iter.next()),
499            }
500        }
501
502        points
503    }
504
505    pub fn get_ghost(&self, id: GhostId) -> Option<&Text> {
506        self.0.tags.get_ghost(id)
507    }
508
509    ////////// String modification functions
510
511    /// Replaces a [range] in the [`Text`]
512    ///
513    /// # [`TextRange`] behavior:
514    ///
515    /// If you give a single [`usize`]/[`Point`], it will be
516    /// interpreted as a range from.
517    ///
518    /// [range]: TextRange
519    pub fn replace_range(&mut self, range: impl TextRange, edit: impl ToString) {
520        let range = range.to_range_at(self.len().byte());
521        let (start, end) = (self.point_at(range.start), self.point_at(range.end));
522        let change = Change::new(edit, [start, end], self);
523
524        self.0.has_changed = true;
525        self.apply_change_inner(0, change.as_ref());
526        self.0
527            .history
528            .as_mut()
529            .map(|h| h.apply_change(None, change));
530    }
531
532    pub(crate) fn apply_change(
533        &mut self,
534        guess_i: Option<usize>,
535        change: Change<String>,
536    ) -> (Option<usize>, Option<usize>) {
537        self.0.has_changed = true;
538
539        let cursors_taken = self.apply_change_inner(guess_i.unwrap_or(0), change.as_ref());
540        let history = self.0.history.as_mut();
541        let insertion_i = history.map(|h| h.apply_change(guess_i, change));
542        (insertion_i, cursors_taken)
543    }
544
545    /// Merges `String`s with the body of text, given a range to
546    /// replace
547    fn apply_change_inner(&mut self, guess_i: usize, change: Change<&str>) -> Option<usize> {
548        self.0.bytes.apply_change(change);
549        self.0.tags.transform(
550            change.start().byte()..change.taken_end().byte(),
551            change.added_end().byte(),
552        );
553
554        *self.0.has_unsaved_changes.get_mut() = true;
555
556        self.0
557            .cursors
558            .as_mut()
559            .map(|cs| cs.apply_change(guess_i, change))
560    }
561
562    /// This is used by [`Area`]s in order to update visible text
563    ///
564    /// In order to not update too much, an [`Area`] will request that
565    /// a region of the [`Text`] (usually roughly what is shown on
566    /// screen) to be updated, rather than the whole [`Text`].
567    ///
568    /// This should be done within the [`Area::print`] and
569    /// [`Area::print_with`] functions.
570    pub fn update_range(
571        &mut self,
572        start: impl FnOnce(&Text) -> Point,
573        end: impl FnOnce(&Text) -> Point,
574    ) {
575        if self.0.has_changed || self.0.readers.needs_update() {
576            let within = start(self).byte()..(end(self).byte() + 1);
577            if let Some(history) = self.0.history.as_mut()
578                && let Some(changes) = history.unprocessed_changes()
579            {
580                let changes: Vec<Change<&str>> = changes.iter().map(|c| c.as_ref()).collect();
581                self.0.readers.process_changes(&mut self.0.bytes, &changes);
582            }
583            self.0
584                .readers
585                .update_range(&mut self.0.bytes, &mut self.0.tags, within.clone());
586
587            self.0.has_changed = false;
588        }
589
590        self.0.tags.update_bounds();
591    }
592
593    ////////// History manipulation functions
594
595    /// Undoes the last moment, if there was one
596    pub fn undo(&mut self) {
597        let mut history = self.0.history.take();
598
599        if let Some(history) = history.as_mut()
600            && let Some(changes) = history.move_backwards()
601            && !changes.is_empty()
602        {
603            self.apply_and_process_changes(changes);
604            self.0.has_changed = true;
605        }
606
607        self.0.history = history;
608    }
609
610    /// Redoes the last moment in the history, if there is one
611    pub fn redo(&mut self) {
612        let mut history = self.0.history.take();
613
614        if let Some(history) = history.as_mut()
615            && let Some(changes) = history.move_forward()
616            && !changes.is_empty()
617        {
618            self.apply_and_process_changes(changes);
619            self.0.has_changed = true;
620        }
621
622        self.0.history = history;
623    }
624
625    pub fn apply_and_process_changes(&mut self, changes: Vec<Change<&str>>) {
626        if let Some(cursors) = self.cursors_mut() {
627            cursors.clear();
628        }
629
630        for (i, change) in changes.iter().enumerate() {
631            self.apply_change_inner(0, *change);
632
633            if let Some(cursors) = self.0.cursors.as_mut() {
634                let start = change.start();
635                let added_end = match change.added_text().chars().next_back() {
636                    Some(last) => change.added_end().rev(last),
637                    None => change.start(),
638                };
639
640                let cursor = Cursor::new(added_end, (start != added_end).then_some(start));
641                cursors.insert(i, cursor, i == changes.len() - 1);
642            }
643        }
644
645        self.0.readers.process_changes(&mut self.0.bytes, &changes);
646    }
647
648    /// Finishes the current moment and adds a new one to the history
649    pub fn new_moment(&mut self) {
650        if let Some(h) = self.0.history.as_mut() {
651            h.new_moment()
652        }
653    }
654
655    ////////// Writing functions
656
657    /// Clones the inner [`Bytes`] as a [`String`]
658    ///
659    /// This function will also cut out a final '\n' from the string.
660    // NOTE: Inherent because I don't want this to implement Display
661    #[allow(clippy::inherent_to_string)]
662    pub fn to_string(&self) -> String {
663        let [s0, s1] = self.strs(..).to_array();
664        if !s1.is_empty() {
665            s0.to_string() + s1.strip_suffix('\n').unwrap_or(s1)
666        } else {
667            s0.strip_suffix('\n').unwrap_or(s0).to_string()
668        }
669    }
670
671    /// Writes the contents of this [`Text`] to a [writer]
672    ///
673    /// [writer]: std::io::Write
674    pub fn write_to(&self, mut writer: impl std::io::Write) -> std::io::Result<usize> {
675        self.0.has_unsaved_changes.store(false, Ordering::Relaxed);
676        let [s0, s1] = self.0.bytes.buffers(..).to_array();
677        Ok(writer.write(s0)? + writer.write(s1)?)
678    }
679
680    /// Wether or not the content has changed since the last [write]
681    ///
682    /// Returns `true` only if the actual bytes of the [`Text`] have
683    /// been changed, ignoring [`Tag`]s and all the other things,
684    /// since those are not written to the filesystem.
685    ///
686    /// [write]: Text::write_to
687    pub fn has_unsaved_changes(&self) -> bool {
688        self.0.has_unsaved_changes.load(Ordering::Relaxed)
689    }
690
691    ////////// Reload related functions
692
693    /// Takes the [`Bytes`] from this [`Text`], consuming it
694    pub(crate) fn take_bytes(self) -> Bytes {
695        self.0.bytes
696    }
697
698    ////////// Tag addition/deletion functions
699
700    /// Inserts a [`Tag`] at the given position
701    pub fn insert_tag(&mut self, key: Key, tag: Tag) {
702        self.0.tags.insert(key, tag.clone());
703    }
704
705    /// Removes the [`Tag`]s of a [key] from a region
706    ///
707    /// # Caution
708    ///
709    /// While it is fine to do this on your own widgets, you should
710    /// refrain from using this function in a [`File`]s [`Text`], as
711    /// it must iterate over all tags in the file, so if there are a
712    /// lot of other tags, this operation may be slow.
713    ///
714    /// # [`TextRange`] behavior
715    ///
716    /// If you give it a [`Point`] or [`usize`], it will be treated as
717    /// a one byte range.
718    ///
719    /// [key]: Keys
720    /// [`File`]: crate::widgets::File
721    pub fn remove_tags(&mut self, range: impl TextRange, keys: impl Keys) {
722        let range = range.to_range_at(self.len().byte());
723        self.0.tags.remove_from(range, keys)
724    }
725
726    /// Removes all [`Tag`]s
727    ///
728    /// Refrain from using this function on [`File`]s, as there may be
729    /// other [`Tag`] providers, and you should avoid messing with
730    /// their tags.
731    ///
732    /// [`File`]: crate::widgets::File
733    pub fn clear_tags(&mut self) {
734        self.0.tags = Tags::new(self.0.bytes.len().byte());
735    }
736
737    /////////// Cursor functions
738
739    /// Enables the usage of [`Cursors`] in this [`Text`]
740    ///
741    /// This is automatically done whenever you use the [`EditHelper`]
742    /// struct.
743    ///
744    /// [`EditHelper`]: crate::mode::EditHelper
745    pub fn enable_cursors(&mut self) {
746        if self.0.cursors.is_none() {
747            self.0.cursors = Some(Cursors::default())
748        }
749    }
750
751    /// Removes the tags for all the cursors, used before they are
752    /// expected to move
753    pub(crate) fn add_cursors(&mut self, area: &impl Area, cfg: PrintCfg) {
754        let Some(cursors) = self.0.cursors.take() else {
755            return;
756        };
757
758        if cursors.len() < 500 {
759            for (cursor, is_main) in cursors.iter() {
760                self.add_cursor(cursor, is_main);
761            }
762        } else {
763            let (start, _) = area.first_points(self, cfg);
764            let (end, _) = area.last_points(self, cfg);
765            for (cursor, is_main) in cursors.iter() {
766                let range = cursor.range(self);
767                if range.end > start.byte() && range.start < end.byte() {
768                    self.add_cursor(cursor, is_main);
769                }
770            }
771        }
772
773        self.0.cursors = Some(cursors);
774    }
775
776    /// Adds the tags for all the cursors, used after they are
777    /// expected to have moved
778    pub(crate) fn remove_cursors(&mut self, area: &impl Area, cfg: PrintCfg) {
779        let Some(cursors) = self.0.cursors.take() else {
780            return;
781        };
782
783        if cursors.len() < 500 {
784            for (cursor, _) in cursors.iter() {
785                self.remove_cursor(cursor);
786            }
787        } else {
788            let (start, _) = area.first_points(self, cfg);
789            let (end, _) = area.last_points(self, cfg);
790            for (cursor, _) in cursors.iter() {
791                let range = cursor.range(self);
792                if range.end > start.byte() && range.start < end.byte() {
793                    self.remove_cursor(cursor);
794                }
795            }
796        }
797
798        self.0.cursors = Some(cursors)
799    }
800
801    /// Adds a [`Cursor`] to the [`Text`]
802    fn add_cursor(&mut self, cursor: &Cursor, is_main: bool) {
803        let (caret, selection) = cursor.tag_points(self);
804
805        let (cursor, form) = if is_main {
806            (Tag::MainCursor(caret.byte()), form::M_SEL_ID)
807        } else {
808            (Tag::ExtraCursor(caret.byte()), form::E_SEL_ID)
809        };
810        self.0
811            .bytes
812            .add_record([caret.byte(), caret.char(), caret.line()]);
813        self.0.tags.insert(Key::for_cursors(), cursor);
814
815        if let Some([start, end]) = selection {
816            self.0.tags.insert(
817                Key::for_cursors(),
818                Tag::Form(start.byte()..end.byte(), form, 250),
819            );
820        }
821    }
822
823    /// Removes a [`Cursor`] from the [`Text`]
824    fn remove_cursor(&mut self, cursor: &Cursor) {
825        let (caret, selection) = cursor.tag_points(self);
826        let points = [caret]
827            .into_iter()
828            .chain(selection.into_iter().flatten().find(|p| *p != caret));
829        for p in points {
830            self.remove_tags(p.byte(), Key::for_cursors());
831        }
832    }
833
834    /////////// Iterator methods
835
836    /// A forward iterator of the [chars and tags] of the [`Text`]
837    ///
838    /// [chars and tags]: Part
839    pub fn iter_fwd(&self, at: impl TwoPoints) -> FwdIter<'_> {
840        FwdIter::new_at(self, at)
841    }
842
843    /// A reverse iterator of the [chars and tags] of the [`Text`]
844    ///
845    /// [chars and tags]: Part
846    pub fn iter_rev(&self, at: impl TwoPoints) -> RevIter<'_> {
847        RevIter::new_at(self, at)
848    }
849
850    /// A forward iterator of the [`char`]s of the [`Text`]
851    ///
852    /// Each [`char`] will be accompanied by a [`Point`], which is the
853    /// position where said character starts, e.g.
854    /// [`Point::default()`] for the first character
855    pub fn chars_fwd(&self, p: Point) -> impl Iterator<Item = (Point, char)> + '_ {
856        self.0.bytes.chars_fwd(p)
857    }
858
859    /// A reverse iterator of the [`char`]s of the [`Text`]
860    ///
861    /// Each [`char`] will be accompanied by a [`Point`], which is the
862    /// position where said character starts, e.g.
863    /// [`Point::default()`] for the first character
864    pub fn chars_rev(&self, p: Point) -> impl Iterator<Item = (Point, char)> + '_ {
865        self.0.bytes.chars_rev(p)
866    }
867
868    /// A forward iterator over the [`Tag`]s of the [`Text`]
869    ///
870    /// This iterator will consider some [`Tag`]s before `b`, since
871    /// their ranges may overlap with `b`
872    ///
873    /// # Note
874    ///
875    /// Duat works fine with [`Tag`]s in the middle of a codepoint,
876    /// but external utilizers may not, so keep that in mind.
877    pub fn tags_fwd(&self, b: usize) -> FwdTags {
878        self.0.tags.fwd_at(b)
879    }
880
881    /// An reverse iterator over the [`Tag`]s of the [`Text`]
882    ///
883    /// This iterator will consider some [`Tag`]s ahead of `b`, since
884    /// their ranges may overlap with `b`
885    ///
886    /// # Note
887    ///
888    /// Duat works fine with [`Tag`]s in the middle of a codepoint,
889    /// but external utilizers may not, so keep that in mind.
890    pub fn tags_rev(&self, b: usize) -> RevTags {
891        self.0.tags.rev_at(b)
892    }
893
894    pub fn raw_tags_fwd(&self, b: usize) -> impl Iterator<Item = (usize, RawTag)> {
895        self.0.tags.raw_fwd_at(b)
896    }
897
898    pub fn raw_tags_rev(&self, b: usize) -> impl Iterator<Item = (usize, RawTag)> {
899        self.0.tags.raw_rev_at(b)
900    }
901
902    /// The [`Cursors`] printed to this [`Text`], if they exist
903    pub fn cursors(&self) -> Option<&Cursors> {
904        self.0.cursors.as_ref()
905    }
906
907    /// A mut reference to this [`Text`]'s [`Cursors`] if they exist
908    pub fn cursors_mut(&mut self) -> Option<&mut Cursors> {
909        self.0.cursors.as_mut()
910    }
911
912    pub(crate) fn history(&self) -> Option<&History> {
913        self.0.history.as_ref()
914    }
915
916    ////////// One str functions
917
918    /// Gets a single [`&str`] from a given [range]
919    ///
920    /// This is the equivalent of calling
921    /// [`Bytes::make_contiguous`] and [`Bytes::get_contiguous`].
922    /// While this takes less space in code, calling the other two
923    /// functions means that you won't be mutably borrowing the
924    /// [`Bytes`] anymore, so if that matters to you, you should do
925    /// that.
926    ///
927    /// [`&str`]: str
928    /// [range]: TextRange
929    pub fn contiguous(&mut self, range: impl TextRange) -> &str {
930        self.make_contiguous(range.clone());
931        self.get_contiguous(range).unwrap()
932    }
933
934    /// Moves the [`GapBuffer`]'s gap, so that the `range` is whole
935    ///
936    /// The return value is the value of the gap, if the second `&str`
937    /// is the contiguous one.
938    ///
939    /// [`GapBuffer`]: gapbuf::GapBuffer
940    pub fn make_contiguous(&mut self, range: impl TextRange) {
941        self.0.bytes.make_contiguous(range);
942    }
943
944    /// Assumes that the `range` given is contiguous in `self`
945    ///
946    /// You *MUST* call [`make_contiguous`] before using this
947    /// function. The sole purpose of this function is to not keep the
948    /// [`Bytes`] mutably borrowed.
949    ///
950    /// [`make_contiguous`]: Self::make_contiguous
951    pub fn get_contiguous(&self, range: impl TextRange) -> Option<&str> {
952        self.0.bytes.get_contiguous(range)
953    }
954}
955
956/// Merges a range in a sorted list of ranges, useful in [`Reader`]s
957///
958/// Since ranges are not allowed to intersect, they will be sorted
959/// both in their starting bound and in their ending bound.
960pub fn merge_range_in(ranges: &mut Vec<Range<usize>>, range: Range<usize>) -> [usize; 2] {
961    let (r_range, start) = match ranges.binary_search_by_key(&range.start, |r| r.start) {
962        // Same thing here
963        Ok(i) => (i..i + 1, range.start),
964        Err(i) => {
965            // This is if we intersect the added part
966            if let Some(older_i) = i.checked_sub(1)
967                && range.start <= ranges[older_i].end
968            {
969                (older_i..i, ranges[older_i].start)
970            // And here is if we intersect nothing on the
971            // start, no changes drained.
972            } else {
973                (i..i, range.start)
974            }
975        }
976    };
977    let start_i = r_range.start;
978    // Otherwise search ahead for another change to be merged
979    let (r_range, end) = match ranges[start_i..].binary_search_by_key(&range.end, |r| r.start) {
980        Ok(i) => (r_range.start..start_i + i + 1, ranges[start_i + i].end),
981        Err(i) => match (start_i + i).checked_sub(1).and_then(|i| ranges.get(i)) {
982            Some(older) => (r_range.start..start_i + i, range.end.max(older.end)),
983            None => (r_range.start..start_i + i, range.end),
984        },
985    };
986
987    ranges.splice(r_range, [start..end]);
988    [start, end - start]
989}
990
991/// Splits a range within a region
992///
993/// The first return is the part of `within` that must be updated.
994/// The second return is what is left of `range`.
995///
996/// If `range` is fully inside `within`, remove `range`;
997/// If `within` is fully inside `range`, split `range` in 2;
998/// If `within` intersects `range` in one side, cut it out;
999fn split_range_within(
1000    range: Range<usize>,
1001    within: Range<usize>,
1002) -> (Option<Range<usize>>, [Option<Range<usize>>; 2]) {
1003    if range.start >= within.end || within.start >= range.end {
1004        (None, [Some(range), None])
1005    } else {
1006        let start_range = (within.start > range.start).then_some(range.start..within.start);
1007        let end_range = (range.end > within.end).then_some(within.end..range.end);
1008        let split_ranges = [start_range, end_range];
1009        let range_to_check = range.start.max(within.start)..(range.end.min(within.end));
1010        (Some(range_to_check), split_ranges)
1011    }
1012}
1013
1014fn transform_ranges(ranges: &mut [Range<usize>], changes: &[Change<&str>]) {
1015    let mut range_bounds = ranges
1016        .iter_mut()
1017        .flat_map(|r| [&mut r.start, &mut r.end])
1018        .peekable();
1019    let mut shift = 0;
1020
1021    for change in changes.iter() {
1022        while let Some(bound) = range_bounds.next_if(|b| **b < change.start().byte()) {
1023            *bound = (*bound as i32 + shift) as usize;
1024        }
1025        shift += change.added_end().byte() as i32 - change.taken_end().byte() as i32;
1026    }
1027    for bound in range_bounds {
1028        *bound = (*bound as i32 + shift) as usize
1029    }
1030}
1031
1032impl Default for Text {
1033    fn default() -> Self {
1034        Self::new()
1035    }
1036}
1037
1038impl std::fmt::Debug for Text {
1039    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1040        f.debug_struct("Text")
1041            .field("bytes", &self.0.bytes)
1042            .field("tags", &self.0.tags)
1043            .finish_non_exhaustive()
1044    }
1045}
1046
1047impl Clone for Text {
1048    fn clone(&self) -> Self {
1049        Self(Box::new(InnerText {
1050            bytes: self.0.bytes.clone(),
1051            tags: self.0.tags.clone(),
1052            cursors: self.0.cursors.clone(),
1053            history: self.0.history.clone(),
1054            readers: Readers::default(),
1055            forced_new_line: self.0.forced_new_line,
1056            has_changed: self.0.has_changed,
1057            has_unsaved_changes: AtomicBool::new(false),
1058        }))
1059    }
1060}
1061
1062impl From<std::io::Error> for Text {
1063    fn from(value: std::io::Error) -> Self {
1064        err!({ value.kind().to_string() })
1065    }
1066}
1067
1068impl From<Box<dyn std::error::Error>> for Text {
1069    fn from(value: Box<dyn std::error::Error>) -> Self {
1070        err!({ value.to_string() })
1071    }
1072}
1073
1074impl From<&std::path::PathBuf> for Text {
1075    fn from(value: &std::path::PathBuf) -> Self {
1076        let value = value.to_str().unwrap_or("");
1077        Self::from(value)
1078    }
1079}
1080
1081impl PartialEq for Text {
1082    fn eq(&self, other: &Self) -> bool {
1083        self.0.bytes == other.0.bytes && self.0.tags == other.0.tags
1084    }
1085}
1086
1087impl PartialEq<&str> for Text {
1088    fn eq(&self, other: &&str) -> bool {
1089        self.0.bytes == *other
1090    }
1091}
1092
1093impl PartialEq<String> for Text {
1094    fn eq(&self, other: &String) -> bool {
1095        self.0.bytes == *other
1096    }
1097}
1098
1099impl_from_to_string!(u8);
1100impl_from_to_string!(u16);
1101impl_from_to_string!(u32);
1102impl_from_to_string!(u64);
1103impl_from_to_string!(u128);
1104impl_from_to_string!(usize);
1105impl_from_to_string!(i8);
1106impl_from_to_string!(i16);
1107impl_from_to_string!(i32);
1108impl_from_to_string!(i64);
1109impl_from_to_string!(i128);
1110impl_from_to_string!(isize);
1111impl_from_to_string!(f32);
1112impl_from_to_string!(f64);
1113impl_from_to_string!(char);
1114impl_from_to_string!(&str);
1115impl_from_to_string!(String);
1116impl_from_to_string!(Box<str>);
1117impl_from_to_string!(Rc<str>);
1118impl_from_to_string!(Arc<str>);
1119
1120/// Implements [`From<$t>`] for [`Text`]
1121macro impl_from_to_string($t:ty) {
1122    impl From<$t> for Text {
1123        fn from(value: $t) -> Self {
1124            let string = <$t as ToString>::to_string(&value);
1125            let bytes = Bytes::new(&string);
1126            Self::from_bytes(bytes, None, false)
1127        }
1128    }
1129}