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);