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