duat_core/buffer/history.rs
1//! The history for a [`Text`].
2//!
3//! The [`History`] is composed of [`Moment`]s, each having a list of
4//! [`Change`]s. Whenever you [`undo`]/[`redo`], you are
5//! undoing/redoing a whole [`Moment`], with all of its [`Change`]s,
6//! all at once.
7//!
8//! This permits Vim style undoing (one [`Change`] per [`Moment`]) as
9//! well as Kakoune style undoing (multiple [`Change`]s per
10//! [`Moment`]).
11//!
12//! [`undo`]: Text::undo
13//! [`redo`]: Text::redo
14use std::{
15 iter::{Chain, Enumerate},
16 marker::PhantomData,
17 ops::Range,
18 sync::{Arc, LazyLock, Mutex},
19};
20
21use bincode::{BorrowDecode, Decode, Encode};
22use gap_buf::GapBuffer;
23
24use super::{Point, Text};
25use crate::{
26 Ranges,
27 buffer::{Buffer, BufferId, BufferOpts},
28 mode::Selections,
29 text::{Strs, Tags, TextRange},
30 utils::{add_shifts as add, merging_range_by_guess_and_lazy_shift},
31};
32
33/// The history of edits, contains all moments.
34#[derive(Debug)]
35pub struct History {
36 // Moments in regard to undoing/redoing.
37 new_moment: Moment,
38 undo_redo_moments: Vec<Moment>,
39 cur_moment: usize,
40 // Moments in regard to BufferTrackers.
41 unread_moments: Vec<UnreadMoment>,
42 // The moment where a [`Buffer`] was saved.
43 //
44 // [`Buffer`]: crate::buffer::Buffer
45 saved_moment: Option<usize>,
46}
47
48impl History {
49 /// Returns a new `History`.
50 #[allow(clippy::new_without_default)]
51 pub const fn new() -> Self {
52 Self {
53 new_moment: Moment::new(),
54 undo_redo_moments: Vec::new(),
55 cur_moment: 0,
56 unread_moments: Vec::new(),
57 saved_moment: None,
58 }
59 }
60
61 /// Adds a [`Change`] to the [`History`].
62 pub fn apply_change(
63 &mut self,
64 guess_i: Option<usize>,
65 change: Change<'static, String>,
66 ) -> usize {
67 for unread in self.unread_moments.iter_mut() {
68 unread.add_change(guess_i, change.clone());
69 }
70 self.new_moment.add_change(guess_i, change)
71 }
72
73 /// Declares that the current moment is complete and starts a
74 /// new one.
75 pub fn new_moment(&mut self) {
76 if self.new_moment.is_empty() {
77 return;
78 }
79
80 self.undo_redo_moments.truncate(self.cur_moment);
81
82 if let Some(saved_moment) = self.saved_moment
83 && saved_moment >= self.cur_moment
84 {
85 self.saved_moment = None;
86 }
87
88 self.undo_redo_moments
89 .push(std::mem::take(&mut self.new_moment));
90 self.cur_moment += 1;
91 }
92
93 /// Redoes the next [`Moment`], returning its [`Change`]s.
94 ///
95 /// Applying these [`Change`]s in the order that they're given
96 /// will result in a correct redoing.
97 pub(crate) fn move_forward(
98 &mut self,
99 ) -> Option<(impl ExactSizeIterator<Item = Change<'_>>, bool)> {
100 self.new_moment();
101 if self.cur_moment == self.undo_redo_moments.len() {
102 None
103 } else {
104 self.cur_moment += 1;
105
106 let iter = self.undo_redo_moments[self.cur_moment - 1]
107 .iter()
108 .enumerate()
109 .map(|(i, change)| {
110 for unread in self.unread_moments.iter_mut() {
111 unread.add_change(Some(i), change.to_string_change());
112 }
113 change
114 });
115
116 let is_saved = self.saved_moment.is_some_and(|m| m == self.cur_moment);
117 Some((iter, is_saved))
118 }
119 }
120
121 /// Undoes a [`Moment`], returning its reversed [`Change`]s.
122 ///
123 /// These [`Change`]s will already be shifted corectly, such that
124 /// applying them in sequential order, without further
125 /// modifications, will result in a correct undoing.
126 pub(crate) fn move_backwards(
127 &mut self,
128 ) -> Option<(impl ExactSizeIterator<Item = Change<'_>>, bool)> {
129 self.new_moment();
130 if self.cur_moment == 0 {
131 None
132 } else {
133 self.cur_moment -= 1;
134
135 let iter = self.undo_redo_moments[self.cur_moment]
136 .iter()
137 .undone()
138 .enumerate()
139 .map(|(i, change)| {
140 for unread in self.unread_moments.iter_mut() {
141 unread.add_change(Some(i), change.to_string_change());
142 }
143 change
144 });
145
146 let is_saved = self.saved_moment.is_some_and(|m| m == self.cur_moment);
147 Some((iter, is_saved))
148 }
149 }
150
151 /// Declares that the current state of the [`Text`] was saved on
152 /// disk.
153 pub(super) fn declare_saved(&mut self) {
154 self.saved_moment = Some(self.cur_moment)
155 }
156}
157
158impl Clone for History {
159 fn clone(&self) -> Self {
160 Self {
161 new_moment: self.new_moment.clone(),
162 undo_redo_moments: self.undo_redo_moments.clone(),
163 cur_moment: self.cur_moment,
164 unread_moments: Vec::new(),
165 saved_moment: self.saved_moment,
166 }
167 }
168}
169
170/// A moment in history, which may contain changes, or may just
171/// contain selections.
172///
173/// It also contains information about how to print the buffer, so
174/// that going back in time is less jarring.
175#[derive(Clone, Default, Debug)]
176pub struct Moment {
177 changes: GapBuffer<Change<'static, String>>,
178 shift_state: (usize, [i32; 3]),
179}
180
181impl Moment {
182 /// Returns a new `Moment`.
183 const fn new() -> Self {
184 Self {
185 changes: GapBuffer::new(),
186 shift_state: (0, [0; 3]),
187 }
188 }
189}
190
191impl<Context> Decode<Context> for Moment {
192 fn decode<D: bincode::de::Decoder<Context = Context>>(
193 decoder: &mut D,
194 ) -> Result<Self, bincode::error::DecodeError> {
195 Ok(Moment {
196 changes: GapBuffer::from_iter(Vec::<Change<'static, String>>::decode(decoder)?),
197 shift_state: Decode::decode(decoder)?,
198 })
199 }
200}
201
202impl Encode for Moment {
203 fn encode<E: bincode::enc::Encoder>(
204 &self,
205 encoder: &mut E,
206 ) -> Result<(), bincode::error::EncodeError> {
207 let changes = self.changes.iter().cloned().collect::<Vec<_>>();
208 changes.encode(encoder)?;
209 self.shift_state.encode(encoder)
210 }
211}
212
213impl Moment {
214 /// First try to merge this change with as many changes as
215 /// possible, then add it in.
216 pub(crate) fn add_change(
217 &mut self,
218 guess_i: Option<usize>,
219 mut change: Change<'static, String>,
220 ) -> usize {
221 let new_shift = change.shift();
222 let (from, shift) = self.shift_state;
223
224 // The range of changes that will be drained.
225 let m_range = merging_range_by_guess_and_lazy_shift(
226 (&self.changes, self.changes.len()),
227 (guess_i.unwrap_or(0), [change.start(), change.taken_end()]),
228 (from, shift, [0; 3], Point::shift_by),
229 (Change::start, Change::added_end),
230 );
231
232 // If sh_from < c_range.end, I need to shift the changes between the
233 // two, so that they match the shifting of the changes before sh_from.
234 if from < m_range.end && shift != [0; 3] {
235 for change in self.changes.range_mut(from..m_range.end).iter_mut() {
236 change.shift_by(shift);
237 }
238 // Otherwise, the shifting will happen in reverse, and `from`
239 // will be moved backwards until the point where m_range ends.
240 // This is better for localized Changes.
241 } else if from > m_range.end && shift != [0; 3] {
242 for change in self.changes.range_mut(m_range.end..from).iter_mut() {
243 change.shift_by(shift.map(|i| -i));
244 }
245 }
246
247 match m_range.len() {
248 1 => {
249 let old = std::mem::replace(&mut self.changes[m_range.start], change);
250 self.changes[m_range.start].try_merge(old);
251 }
252 _ => {
253 let changes: Vec<_> = self.changes.drain(m_range.clone()).collect();
254 for c in changes.into_iter().rev() {
255 change.try_merge(c);
256 }
257 self.changes.insert(m_range.start, change);
258 }
259 }
260
261 if m_range.start + 1 < self.changes.len() {
262 self.shift_state = (m_range.start + 1, add(shift, new_shift));
263 } else {
264 self.shift_state = (0, [0; 3]);
265 }
266
267 m_range.start
268 }
269
270 /// An [`ExactSizeIterator`] over the [`Change`]s in this
271 /// `Moment`.
272 pub fn iter(&self) -> Changes<'_> {
273 Changes {
274 moment: self,
275 iter: self.changes.iter().enumerate(),
276 undo_shift: None,
277 }
278 }
279
280 /// Returns the number of [`Change`]s in this `Moment`
281 pub fn len(&self) -> usize {
282 self.changes.len()
283 }
284
285 /// Wether there are any [`Change`]s in this `Moment`
286 ///
287 /// This can happen when creating a [`Moment::default`].
288 #[must_use]
289 pub fn is_empty(&self) -> bool {
290 self.len() == 0
291 }
292}
293
294/// A change in a buffer, with a start, taken text, and added text
295///
296/// If you acquired this `Change` from a [`BufferTracker::parts`]
297/// call, you need not worry about adding it to the ranges that need
298/// to be updated, as that has already been done.
299#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
300pub struct Change<'h, S = &'h str> {
301 start: [i32; 3],
302 added: S,
303 taken: S,
304 added_end: [i32; 3],
305 taken_end: [i32; 3],
306 _ghost: PhantomData<&'h str>,
307}
308
309impl Change<'static, String> {
310 /// Returns a new [Change].
311 pub fn new(edit: impl ToString, range: Range<Point>, text: &Text) -> Self {
312 let added = {
313 let edit = edit.to_string();
314 // A '\n' must be kept at the end, no matter what.
315 if (range.start == text.end_point() || range.end == text.end_point())
316 && !edit.ends_with('\n')
317 {
318 edit + "\n"
319 } else {
320 edit
321 }
322 };
323
324 let taken = text[range.clone()].to_string();
325 let added_end = add(
326 range.start.as_signed(),
327 Point::end_point_of(&added).as_signed(),
328 );
329 Change {
330 start: range.start.as_signed(),
331 added,
332 taken,
333 added_end,
334 taken_end: range.end.as_signed(),
335 _ghost: PhantomData,
336 }
337 }
338
339 /// Returns a copyable [`Change`]
340 pub fn as_ref(&self) -> Change<'_, &str> {
341 Change {
342 start: self.start,
343 added: &self.added,
344 taken: &self.taken,
345 added_end: self.added_end,
346 taken_end: self.taken_end,
347 _ghost: PhantomData,
348 }
349 }
350
351 /// In this function, it is assumed that `self` happened
352 /// _after_ `newer`
353 ///
354 /// If the merger fails, the older [`Change`] will be returned;
355 pub fn try_merge(&mut self, mut older: Self) {
356 if has_start_of(older.added_range(), self.taken_range()) {
357 let fixed_end = older.added_end().min(self.taken_end());
358
359 let start = sub(self.start, older.start);
360 let end = sub(fixed_end.as_signed(), older.start);
361 let range = start[0] as usize..end[0] as usize;
362 older.added.replace_range(range, &self.added);
363
364 let range = (fixed_end.byte() - self.start[0] as usize)..;
365
366 older.taken.push_str(&self.taken[range]);
367
368 *self = older;
369 } else if has_start_of(self.taken_range(), older.added_range()) {
370 let fixed_end = self.taken_end().min(older.added_end());
371
372 let start = sub(older.start, self.start);
373 let end = sub(fixed_end.as_signed(), self.start);
374 let range = start[0] as usize..end[0] as usize;
375 self.taken.replace_range(range, &older.taken);
376
377 let range = (fixed_end.byte() - older.start[0] as usize)..;
378
379 self.added.push_str(&older.added[range]);
380 } else {
381 panic!("Changes chosen that don't interact");
382 }
383 self.added_end = add(self.start, Point::end_point_of(&self.added).as_signed());
384 self.taken_end = add(self.start, Point::end_point_of(&self.taken).as_signed());
385 }
386}
387
388impl<'h> Change<'h> {
389 /// Creates a [`Change<String>`] from a [`Change<&str>`]
390 pub fn to_string_change(&self) -> Change<'static, String> {
391 Change {
392 start: self.start,
393 added: self.added.to_string(),
394 taken: self.taken.to_string(),
395 added_end: self.added_end,
396 taken_end: self.taken_end,
397 _ghost: PhantomData,
398 }
399 }
400
401 /// Returns a new copyable [`Change`] from an insertion.
402 pub fn str_insert(added_str: &'h str, start: Point) -> Self {
403 Self {
404 start: start.as_signed(),
405 added: added_str,
406 taken: "",
407 added_end: (start + Point::end_point_of(added_str)).as_signed(),
408 taken_end: start.as_signed(),
409 _ghost: PhantomData,
410 }
411 }
412}
413
414impl<'s, S: std::borrow::Borrow<str>> Change<'s, S> {
415 /// Returns a reversed version of this [`Change`]
416 pub fn reverse(self) -> Self {
417 Self {
418 start: self.start,
419 added: self.taken,
420 taken: self.added,
421 added_end: self.taken_end,
422 taken_end: self.added_end,
423 _ghost: PhantomData,
424 }
425 }
426
427 /// Gets a [`Range<Point>`], from the start to the end of the
428 /// affected lines
429 ///
430 /// For example, if you make an edit that transforms lines `1..=3`
431 /// to lines `1..=5`, this function will return a [`Range`] that
432 /// starts at the beginning of line 1, and ends at the end of line
433 /// 5.
434 ///
435 /// # Note
436 ///
437 /// This end of this range will come _after_ the last `\n`,
438 /// which means that, in that example, said point would have a
439 /// [`Point::line`] value equal to 6, _not_ 5, since it
440 /// represents both the end of line 5, and the beginning of line
441 /// 6.
442 #[track_caller]
443 pub fn line_range(&self, strs: &Strs) -> Range<Point> {
444 let full = strs.full();
445 let start = full.point_at_coords(self.start[2] as usize, 0);
446 if self.added_end[2] as usize == full.end_point().line() {
447 start..full.end_point()
448 } else {
449 let end_line = full.line(self.added_end[2] as usize);
450 start..end_line.range().end
451 }
452 }
453
454 /// The [`Point`] at the start of the change
455 pub fn start(&self) -> Point {
456 to_point(self.start)
457 }
458
459 /// Returns the end of the [`Change`], before it was applied
460 pub fn taken_end(&self) -> Point {
461 to_point(self.taken_end)
462 }
463
464 /// Returns the end of the [`Change`], after it was applied
465 pub fn added_end(&self) -> Point {
466 to_point(self.added_end)
467 }
468
469 /// Returns the taken [`Range`]
470 pub fn taken_range(&self) -> Range<Point> {
471 self.start()..self.taken_end()
472 }
473
474 /// Returns the added [`Range`]
475 pub fn added_range(&self) -> Range<Point> {
476 self.start()..self.added_end()
477 }
478
479 /// The text that was taken on this [`Change`]
480 pub fn added_str(&self) -> &str {
481 self.added.borrow()
482 }
483
484 /// The text that was added by this [`Change`]
485 pub fn taken_str(&self) -> &str {
486 self.taken.borrow()
487 }
488
489 /// The total shift caused by this [`Change`]
490 pub fn shift(&self) -> [i32; 3] {
491 [
492 self.added_end[0] - self.taken_end[0],
493 self.added_end[1] - self.taken_end[1],
494 self.added_end[2] - self.taken_end[2],
495 ]
496 }
497
498 /// Shifts the [`Change`] by a "signed point"
499 pub(crate) fn shift_by(&mut self, shift: [i32; 3]) {
500 self.start = add(self.start, shift);
501 self.added_end = add(self.added_end, shift);
502 self.taken_end = add(self.taken_end, shift);
503 }
504}
505
506impl<'s, S: std::fmt::Debug> std::fmt::Debug for Change<'s, S> {
507 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
508 struct DebugArray([i32; 3]);
509
510 impl std::fmt::Debug for DebugArray {
511 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
512 write!(f, "{:?}", self.0)
513 }
514 }
515
516 f.debug_struct("Change")
517 .field("start", &DebugArray(self.start))
518 .field("added", &self.added)
519 .field("taken", &self.taken)
520 .field("added_end", &DebugArray(self.added_end))
521 .field("taken_end", &DebugArray(self.taken_end))
522 .field("_ghost", &self._ghost)
523 .finish()
524 }
525}
526
527impl Encode for Change<'static, String> {
528 fn encode<E: bincode::enc::Encoder>(
529 &self,
530 encoder: &mut E,
531 ) -> Result<(), bincode::error::EncodeError> {
532 Encode::encode(&self.start, encoder)?;
533 Encode::encode(&self.added, encoder)?;
534 Encode::encode(&self.taken, encoder)?;
535 Encode::encode(&self.added_end, encoder)?;
536 Encode::encode(&self.taken_end, encoder)?;
537 Ok(())
538 }
539}
540
541impl<Context> Decode<Context> for Change<'static, String> {
542 fn decode<D: bincode::de::Decoder<Context = Context>>(
543 decoder: &mut D,
544 ) -> Result<Self, bincode::error::DecodeError> {
545 Ok(Self {
546 start: Decode::decode(decoder)?,
547 added: Decode::decode(decoder)?,
548 taken: Decode::decode(decoder)?,
549 added_end: Decode::decode(decoder)?,
550 taken_end: Decode::decode(decoder)?,
551 _ghost: PhantomData,
552 })
553 }
554}
555
556impl<'de, Context> BorrowDecode<'de, Context> for Change<'static, String> {
557 fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
558 decoder: &mut D,
559 ) -> Result<Self, bincode::error::DecodeError> {
560 Ok(Self {
561 start: Decode::decode(decoder)?,
562 added: Decode::decode(decoder)?,
563 taken: Decode::decode(decoder)?,
564 added_end: Decode::decode(decoder)?,
565 taken_end: Decode::decode(decoder)?,
566 _ghost: PhantomData,
567 })
568 }
569}
570
571/// A tracker to keep up to date on changes to [`Buffer`]s
572///
573/// This struct is capable of tracking all the [`Change`]s that happen
574/// to any `Buffer`. That happens through the
575/// [`BufferTracker::parts`] method, which gives a
576/// [`BufferParts`] struct, including the `Buffer`'s [`Strs`],
577/// [`Tags`], [`Selections`], as well as an [`ExactSizeIterator`] over
578/// the `Change`s that took place since the last call to this
579/// function, and a [`RangesToUpdate`] associated with the [`Buffer`]
580///
581/// The [`RangesToUpdate`] is a struct that keeps track of the ranges
582/// where changes have taken place, and informs you on which ones need
583/// to be updated based on what is currently visible on screen. At the
584/// start, this will include the full range of the `Buffer`, since
585/// Duat assumes that you will want to update the whole buffer.
586///
587/// This struct, alongside [`PerBuffer`], allows for a nice and
588/// standardised workflow for "parsers", which essentially update the
589/// [`Buffer`]s based on changes that took place and on what is
590/// presently visible. One example of such a parser can be seen in the
591/// `duat-treesitter` crate.
592///
593/// [`PerBuffer`]: super::PerBuffer
594pub struct BufferTracker {
595 id: LazyLock<TrackerId>,
596 tracked: Mutex<Vec<(BufferId, Arc<Mutex<Ranges>>)>>,
597}
598
599impl BufferTracker {
600 /// Returns a new `ChangesFetcher`
601 ///
602 /// This struct can be stored in a `static` variable, since this
603 /// function is `const`. You can then use the same
604 /// `ChangesFetcher` to fetch [`Change`]s from all [`Buffer`]s
605 pub const fn new() -> Self {
606 Self {
607 id: LazyLock::new(TrackerId::new),
608 tracked: Mutex::new(Vec::new()),
609 }
610 }
611
612 /// Gets the [`BufferParts`] of a [`Buffer`]
613 ///
614 /// This struct consists of the normal [`TextParts`], ([`Strs`],
615 /// [`Tags`], [`Selections`]), but it also includes an
616 /// [`Iterator`] over all the [`Change`]s that took place since
617 /// the last time this function was called by this tracker on this
618 /// `Buffer`.
619 ///
620 /// It is intended for borrowing the `Tags` mutably, whilst
621 /// reading from the `Strs`, `Selections` and the `Change`s that
622 /// took place.
623 ///
624 /// Returns [`None`] when calling this function on a [`Buffer`]
625 /// without first having called [`BufferTracker::register_buffer`]
626 /// on it.
627 ///
628 /// [`TextParts`]: crate::text::TextParts
629 /// [`Tags`]: crate::text::Tags
630 /// [`Selections`]: crate::mode::Selections
631 #[track_caller]
632 pub fn parts<'b>(&self, buf: &'b mut Buffer) -> Option<BufferParts<'b>> {
633 let mut tracked = self.tracked.lock().unwrap();
634
635 let buf_id = buf.buffer_id();
636
637 let (_, ranges) = tracked.iter_mut().find(|(id, ..)| *id == buf_id)?;
638 let unread = buf
639 .history
640 .unread_moments
641 .iter_mut()
642 .find(|unread| unread.id == *self.id)
643 .unwrap();
644
645 if unread.has_been_read {
646 unread.has_been_read = false;
647 unread.moment = Moment::new();
648 } else {
649 unread.has_been_read = true;
650
651 let mut ranges_lock = ranges.lock().unwrap_or_else(|err| err.into_inner());
652 for change in unread.moment.iter() {
653 ranges_lock.shift_by(
654 change.start().byte(),
655 change.added_end().byte() as i32 - change.taken_end().byte() as i32,
656 );
657
658 let range = change.added_range();
659 ranges_lock.add(range.start.byte()..range.end.byte());
660 }
661 }
662
663 let parts = buf.text.parts();
664
665 Some(BufferParts {
666 strs: parts.strs,
667 tags: parts.tags,
668 selections: parts.selections,
669 changes: unread.moment.iter(),
670 ranges_to_update: RangesToUpdate {
671 ranges: ranges.clone(),
672 buf_len: parts.strs.len(),
673 _ghost: PhantomData,
674 },
675 opts: &buf.opts,
676 })
677 }
678
679 /// Registers a [`Buffer`] on the list of those that should be
680 /// tracked
681 ///
682 /// Does nothing if the `Buffer` was already registered.
683 pub fn register_buffer(&self, buf: &mut Buffer) {
684 let mut tracked = self.tracked.lock().unwrap();
685
686 if !tracked.iter().any(|(id, ..)| *id == buf.buffer_id()) {
687 buf.history.unread_moments.push(UnreadMoment {
688 id: *self.id,
689 moment: Moment::new(),
690 has_been_read: false,
691 });
692 let ranges = Arc::new(Mutex::new(Ranges::new(0..buf.text().len())));
693 tracked.push((buf.buffer_id(), ranges));
694 }
695 }
696}
697
698impl Default for BufferTracker {
699 fn default() -> Self {
700 Self::new()
701 }
702}
703
704/// This function is like [`TextParts`], but it includes information
705/// about [`Change`]s that took place since the last call to
706/// [`BufferTracker::parts`], as well as all the ranges of the
707/// [`Text`] that still need updating.
708///
709/// [`TextParts`]: crate::text::TextParts
710pub struct BufferParts<'b> {
711 /// The [`Strs`] of the whole [`Text`] of the [`Buffer`].
712 pub strs: &'b Strs,
713 /// The [`Tags`] of the [`Buffer`].
714 ///
715 /// This, unlike [`Strs`], allows mutation in the form of
716 /// [adding] and [removing] [`Tag`]s.
717 ///
718 /// [adding]: Tags::insert
719 /// [removing]: Tags::remove
720 /// [`Tag`]: crate::text::Tag
721 pub tags: Tags<'b>,
722 /// The [`Selections`] of the [`Buffer`].
723 pub selections: &'b Selections,
724 /// An [`ExactSizeIterator`] of all [`Change`]s that took place
725 /// since the last call to [`BufferTracker::parts`]
726 pub changes: Changes<'b>,
727 /// A list of the ranges that need to be updated.
728 ///
729 /// This should be used in conjunction with visible ranges
730 /// acquired from a [`Handle<Buffer>`], in order to update only
731 /// what is visible on screen.
732 ///
733 /// [`Handle<Buffer>`]: crate::context::Handle
734 pub ranges_to_update: RangesToUpdate<'b>,
735 /// The [`BufferOpts`] of the `Buffer` in question.
736 pub opts: &'b BufferOpts,
737}
738
739/// If `lhs` contains the start of `rhs`
740fn has_start_of(lhs: Range<Point>, rhs: Range<Point>) -> bool {
741 lhs.start <= rhs.start && rhs.start <= lhs.end
742}
743
744/// Subtracts two `i32` arrays
745fn sub(lhs: [i32; 3], rhs: [i32; 3]) -> [i32; 3] {
746 [lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]]
747}
748
749/// Converts an `[i32; 3]` to a [`Point`]
750fn to_point(signed: [i32; 3]) -> Point {
751 Point::from_raw(signed[0] as usize, signed[1] as usize, signed[2] as usize)
752}
753
754/// An [`Iterator`] over the [`Change`]s of a [`Moment`]
755#[doc(hidden)]
756#[derive(Debug, Clone)]
757pub struct Changes<'h> {
758 moment: &'h Moment,
759 iter: Enumerate<
760 Chain<
761 std::slice::Iter<'h, Change<'static, String>>,
762 std::slice::Iter<'h, Change<'static, String>>,
763 >,
764 >,
765 undo_shift: Option<[i32; 3]>,
766}
767
768impl<'h> Changes<'h> {
769 /// Converts this [`Iterator`] to one over the undone version of
770 /// the [`Change`]s
771 ///
772 /// It also resets iteration to the start, so that you aren't
773 /// iterating over "done" and "undone" versions of the `Change`s
774 /// at once.
775 ///
776 /// Normally, [`Change::taken_str`] is the `&str` that was taken
777 /// from the [`Text`] by this [`Change`]. This method assumes that
778 /// you are undoing changes, so the `Change::taken_str` will now
779 /// be the `&str` that was _added_ after the `Change`, and
780 /// [`Change::added_str`] will be the `&str` that was taken.
781 ///
782 /// This method can be useful if you want to modify a [`Strs`] in
783 /// order to check out what it used to look like.
784 pub fn undone(self) -> Self {
785 Self {
786 iter: self.moment.changes.iter().enumerate(),
787 undo_shift: Some([0; 3]),
788 ..self
789 }
790 }
791}
792
793impl<'h> Iterator for Changes<'h> {
794 type Item = Change<'h>;
795
796 fn next(&mut self) -> Option<Self::Item> {
797 let change = self.iter.next().map(|(i, change)| {
798 let (from, shift) = self.moment.shift_state;
799 let mut change = change.as_ref();
800 if i >= from {
801 change.shift_by(shift);
802 }
803 change
804 })?;
805
806 Some(if let Some(undo_shift) = self.undo_shift.as_mut() {
807 let mut change = change.reverse();
808 change.shift_by(*undo_shift);
809 *undo_shift = add(*undo_shift, change.shift());
810
811 change
812 } else {
813 change
814 })
815 }
816
817 fn size_hint(&self) -> (usize, Option<usize>) {
818 self.iter.size_hint()
819 }
820}
821
822impl<'h> ExactSizeIterator for Changes<'h> {}
823
824/// A list of [`Range<usize>`]s of byte indices in a [`Buffer`] that
825/// need to be updated
826///
827/// The recommended way to use this struct is the following:
828///
829/// - Firstly, this should all probably happen in the
830/// [`BufferUpdated`] hook, which is called right before printing to
831/// the screen.
832/// - Before calling [`BufferTracker::parts`], you should retrieve the
833/// ranges that you care about updating, either through
834/// [`Handle::full_printed_range`] or
835/// [`Handle::printed_line_ranges`]. This is to update only what is
836/// visible, conserving cpu resources.
837/// - Then, with the received ranges, you can call
838/// [`RangesToUpdate::cutoff`], [`intersecting`], or
839/// [`select_from`], in order to filter out which ranges need to be
840/// updated.
841/// - If updating the ranges was successfull, you can call
842/// [`RangesToUpdate::update_on`] or [`update_intersecting`], in
843/// order to declare those ranges as updated.
844///
845/// [`BufferUpdated`]: crate::hook::BufferUpdated
846/// [`Handle::full_printed_range`]: crate::context::Handle::full_printed_range
847/// [`Handle::printed_line_ranges`]: crate::context::Handle::printed_line_ranges
848/// [`intersecting`]: RangesToUpdate::intersecting
849/// [`select_from`]: RangesToUpdate::select_from
850/// [`update_intersecting`]: RangesToUpdate::update_intersecting
851pub struct RangesToUpdate<'b> {
852 ranges: Arc<Mutex<Ranges>>,
853 buf_len: usize,
854 _ghost: PhantomData<&'b Buffer>,
855}
856
857impl<'b> RangesToUpdate<'b> {
858 /// Adds ranges to the list of those that need updating
859 ///
860 /// Later on, when duat prints on a range that intersects with
861 /// these, you can call [`Handle::full_printed_range`] or
862 /// [`Handle::printed_line_ranges`] in order to get visible
863 /// ranges, and then call [`RangesToUpdate::cutoff`], or
864 /// [`intersecting`], or [`select_from`], in order to get the
865 /// ranges that need updating, which will include these ones that
866 /// were added by this method, as well as those relating to the
867 /// changes that took place in the [`Buffer`].
868 ///
869 /// Returns `true` if any range was added at all.
870 ///
871 /// [`Handle::full_printed_range`]: crate::context::Handle::full_printed_range
872 /// [`Handle::printed_line_ranges`]: crate::context::Handle::printed_line_ranges
873 /// [`intersecting`]: Self::intersecting
874 /// [`select_from`]: Self::select_from
875 #[track_caller]
876 pub fn add_ranges(&self, to_add: impl IntoIterator<Item = impl TextRange>) -> bool {
877 let mut ranges = self.ranges.lock().unwrap();
878 let mut has_changed = false;
879 for range in to_add {
880 has_changed |= ranges.add(range.to_range(self.buf_len));
881 }
882 has_changed
883 }
884
885 /// Declares that the ranges given by the iterator have been
886 /// updated
887 ///
888 /// The visible iterator here should come from one of the methods
889 /// on the [`Handle<Buffer>`] which returns some list of visible
890 /// ranges. These include [`Handle::full_printed_range`] or
891 /// [`Handle::printed_line_ranges`]. You can, of course, also
892 /// feed only part of these lists, or some other arbitrary
893 /// range, in order to declare those updated too.
894 ///
895 /// This function will then assume that you have successfully
896 /// updated the ranges and will cut these out of the list. This
897 /// will remove the intersections between the ranges that need to
898 /// be updated and those of the iterator.
899 ///
900 /// It will _not_ completely remove ranges that partially
901 /// intersect those of the iterator, only truncating them. If you
902 /// want that behavior, see [`update_intersecting`]
903 ///
904 /// [`Handle<Buffer>`]: crate::context::Handle
905 /// [`Handle::full_printed_range`]: crate::context::Handle::full_printed_range
906 /// [`Handle::printed_line_ranges`]: crate::context::Handle::printed_line_ranges
907 /// [`update_intersecting`]: Self::update_intersecting
908 pub fn update_on(&self, visible: impl IntoIterator<Item = impl TextRange>) -> bool {
909 let mut ranges = self.ranges.lock().unwrap();
910 let mut has_changed = false;
911 for range in visible {
912 let range = range.to_range(u32::MAX as usize);
913 has_changed |= ranges.remove_on(range).count() > 0;
914 }
915 has_changed
916 }
917
918 /// Declares that any range intersecting with any of those on the
919 /// iterator has been updated
920 ///
921 /// The visible iterator here should come from one of the methods
922 /// on the [`Handle<Buffer>`] which returns some list of visible
923 /// ranges. These include [`Handle::full_printed_range`] or
924 /// [`Handle::printed_line_ranges`]. You can, of course, also
925 /// feed only part of these lists, or some other arbitrary
926 /// range, in order to declare those updated too.
927 ///
928 /// If you want a method that only removes the intersection with
929 /// the ranges that need updating, see [`update_on`].
930 ///
931 /// [`Handle<Buffer>`]: crate::context::Handle
932 /// [`Handle::full_printed_range`]: crate::context::Handle::full_printed_range
933 /// [`Handle::printed_line_ranges`]: crate::context::Handle::printed_line_ranges
934 /// [`update_on`]: Self::update_on
935 pub fn update_intersecting(&self, visible: impl IntoIterator<Item = impl TextRange>) -> bool {
936 let mut ranges = self.ranges.lock().unwrap();
937 let mut has_changed = false;
938 for range in visible {
939 let range = range.to_range(u32::MAX as usize);
940 has_changed |= ranges.remove_intersecting(range).count() > 0;
941 }
942 has_changed
943 }
944
945 /// Returns a list of intersections between the ranges that need
946 /// updating and those from an iterator
947 ///
948 /// The visible iterator here should come from one of the methods
949 /// on the [`Handle<Buffer>`] which returns some list of visible
950 /// ranges. These include [`Handle::full_printed_range`] or
951 /// [`Handle::printed_line_ranges`]. You can, of course, also
952 /// feed only part of these lists, or some other arbitrary
953 /// range, in order to declare those updated too.
954 ///
955 /// Note that this returns only the intersecting bits. If you want
956 /// a list of all ranges that at least partially intersect, see
957 /// [`intersecting`]. If you want to do the opposite, i.e., select
958 /// all ranges from the iterator that intersect with those from
959 /// the list, see [`select_from`].
960 ///
961 /// This method is useful if you don't need update full lines,
962 /// since it will only care about the ranges that have actually
963 /// changed, which aren't full lines most of the time.
964 /// [`select_from`] is more useful for updating full lines, since
965 /// you can generate a list of printed lines from
966 /// [`Handle::printed_line_ranges`], and select from those
967 /// only the ranges that have had changes in them. This pattern is
968 /// used, for example, by `duat-treesitter`.
969 ///
970 /// [`Handle<Buffer>`]: crate::context::Handle
971 /// [`Handle::full_printed_range`]: crate::context::Handle::full_printed_range
972 /// [`Handle::printed_line_ranges`]: crate::context::Handle::printed_line_ranges
973 /// [`intersecting`]: Self::intersecting
974 /// [`select_from`]: Self::select_from
975 pub fn cutoff(&self, list: impl IntoIterator<Item = impl TextRange>) -> Vec<Range<usize>> {
976 let ranges = self.ranges.lock().unwrap();
977 list.into_iter()
978 .flat_map(|range| ranges.iter_over(range.to_range(u32::MAX as usize)))
979 .collect()
980 }
981
982 /// Returns a list of all ranges that intersect with those from an
983 /// iterator
984 ///
985 /// The visible iterator here should come from one of the methods
986 /// on the [`Handle<Buffer>`] which returns some list of visible
987 /// ranges. These include [`Handle::full_printed_range`] or
988 /// [`Handle::printed_line_ranges`]. You can, of course, also
989 /// feed only part of these lists, or some other arbitrary
990 /// range, in order to declare those updated too.
991 ///
992 /// Note that this returns the full ranges, not just the parts
993 /// that intersect. If you want a list of only the
994 /// intersections, see [`cutoff`]. If you want to select the
995 /// ranges in the iterator that intersect with those from the
996 /// list, see [`select_from`].
997 ///
998 /// [`Handle<Buffer>`]: crate::context::Handle
999 /// [`Handle::full_printed_range`]: crate::context::Handle::full_printed_range
1000 /// [`Handle::printed_line_ranges`]: crate::context::Handle::printed_line_ranges
1001 /// [`cutoff`]: Self::cutoff
1002 /// [`select_from`]: Self::select_from
1003 pub fn intersecting(
1004 &self,
1005 list: impl IntoIterator<Item = impl TextRange>,
1006 ) -> Vec<Range<usize>> {
1007 let ranges = self.ranges.lock().unwrap();
1008 let mut intersecting = Vec::new();
1009
1010 // There will almost never be more than 50 or so ranges in here, so
1011 // it's ok to be a little inefficient.
1012 // Feel free to optimize this if you wish to.
1013 for range in list {
1014 for range in ranges.iter_intersecting(range.to_range(u32::MAX as usize)) {
1015 if !intersecting.contains(&range) {
1016 intersecting.push(range);
1017 }
1018 }
1019 }
1020
1021 intersecting.sort_unstable_by(|lhs, rhs| lhs.start.cmp(&rhs.start));
1022 intersecting
1023 }
1024
1025 /// Filters an iterator to a list of ranges that intersect with
1026 /// those that need updating
1027 ///
1028 /// The visible iterator here should come from one of the methods
1029 /// on the [`Handle<Buffer>`] which returns some list of visible
1030 /// ranges. These include [`Handle::full_printed_range`] or
1031 /// [`Handle::printed_line_ranges`]. You can, of course, also
1032 /// feed only part of these lists, or some other arbitrary
1033 /// range, in order to declare those updated too.
1034 ///
1035 /// This method is really useful if you want to update on full
1036 /// lines, but only do so if the lines have actually changed. If
1037 /// the lines have had changes, those will be in the
1038 /// [`RangesToUpdate`]. This method will check if the range of a
1039 /// line intersects with the ranges that need updating. If that is
1040 /// the case, that line will be kept in the returned [`Vec`].
1041 ///
1042 /// If you want a method that returns only the ranges that have
1043 /// actually changed, check out [`cutoff`]. If you want a method
1044 /// that that returns any range from the list that intersects with
1045 /// those of the iterator, check out [`intersecting`].
1046 ///
1047 /// [`Handle<Buffer>`]: crate::context::Handle
1048 /// [`Handle::full_printed_range`]: crate::context::Handle::full_printed_range
1049 /// [`Handle::printed_line_ranges`]: crate::context::Handle::printed_line_ranges
1050 /// [`cutoff`]: Self::cutoff
1051 /// [`intersecting`]: Self::intersecting
1052 pub fn select_from(&self, list: impl IntoIterator<Item = impl TextRange>) -> Vec<Range<usize>> {
1053 let ranges = self.ranges.lock().unwrap();
1054 // There will almost never be more than 50 or so ranges in here, so
1055 // it's ok to be a little inefficient.
1056 // Feel free to optimize this if you wish to.
1057 list.into_iter()
1058 .filter_map(|range| {
1059 let range = range.to_range(u32::MAX as usize);
1060 ranges
1061 .iter_intersecting(range.clone())
1062 .next()
1063 .map(|_| range)
1064 })
1065 .collect()
1066 }
1067}
1068
1069impl<'b> std::fmt::Debug for RangesToUpdate<'b> {
1070 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1071 f.debug_struct("RangesToUpdate")
1072 .field("ranges", &*self.ranges.lock().unwrap())
1073 .field("buf_len", &self.buf_len)
1074 .finish_non_exhaustive()
1075 }
1076}
1077
1078#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
1079struct TrackerId(usize);
1080
1081impl TrackerId {
1082 /// Returns a new [`TrackerId`]
1083 fn new() -> Self {
1084 use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
1085 static COUNT: AtomicUsize = AtomicUsize::new(0);
1086 Self(COUNT.fetch_add(1, Relaxed))
1087 }
1088}
1089
1090#[derive(Debug)]
1091struct UnreadMoment {
1092 id: TrackerId,
1093 moment: Moment,
1094 has_been_read: bool,
1095}
1096
1097impl UnreadMoment {
1098 /// Adds a [`Change`], resetting the [`Moment`] first if
1099 /// necessary.
1100 fn add_change(&mut self, guess_i: Option<usize>, change: Change<'static, String>) {
1101 if self.has_been_read {
1102 self.has_been_read = false;
1103 self.moment = Moment::new();
1104 }
1105 self.moment.add_change(guess_i, change);
1106 }
1107}