1use std::{cell::RefCell, collections::VecDeque, sync::Arc};
2
3use crate::sync::{AtomicU64, Mutex};
4use either::Either;
5use loro_common::{
6 ContainerID, Counter, CounterSpan, HasIdSpan, IdSpan, LoroError, LoroResult, LoroValue, PeerID,
7};
8use parking_lot::lock_api::ReentrantMutex;
9use rustc_hash::{FxHashMap, FxHashSet};
10use tracing::{debug_span, info_span, instrument};
11
12use crate::{
13 change::{get_sys_timestamp, Timestamp},
14 cursor::{AbsolutePosition, Cursor},
15 delta::TreeExternalDiff,
16 event::{Diff, EventTriggerKind},
17 version::Frontiers,
18 ContainerDiff, DiffEvent, DocDiff, LoroDoc, Subscription,
19};
20
21#[derive(Debug, Clone, Default)]
25pub struct DiffBatch {
26 pub cid_to_events: FxHashMap<ContainerID, Diff>,
27 pub order: Vec<ContainerID>,
28}
29
30impl DiffBatch {
31 pub fn new(diff: Vec<DocDiff>) -> Self {
32 let mut map: FxHashMap<ContainerID, Diff> = Default::default();
33 let mut order: Vec<ContainerID> = Vec::with_capacity(diff.len());
34 for d in diff.into_iter() {
35 for item in d.diff.into_iter() {
36 let old = map.insert(item.id.clone(), item.diff);
37 assert!(old.is_none(), "Duplicate container ID in diff events");
38 order.push(item.id.clone());
39 }
40 }
41
42 Self {
43 cid_to_events: map,
44 order,
45 }
46 }
47
48 pub fn compose(&mut self, other: &Self) {
49 if other.cid_to_events.is_empty() {
50 return;
51 }
52
53 for (id, diff) in other.iter() {
54 if let Some(this_diff) = self.cid_to_events.get_mut(id) {
55 this_diff.compose_ref(diff);
56 } else {
57 self.cid_to_events.insert(id.clone(), diff.clone());
58 self.order.push(id.clone());
59 }
60 }
61 }
62
63 pub fn transform(&mut self, other: &Self, left_priority: bool) {
64 if other.cid_to_events.is_empty() || self.cid_to_events.is_empty() {
65 return;
66 }
67
68 for (idx, diff) in self.cid_to_events.iter_mut() {
69 if let Some(b_diff) = other.cid_to_events.get(idx) {
70 diff.transform(b_diff, left_priority);
71 }
72 }
73 }
74
75 pub fn clear(&mut self) {
76 self.cid_to_events.clear();
77 self.order.clear();
78 }
79
80 pub fn iter(&self) -> impl Iterator<Item = (&ContainerID, &Diff)> + '_ {
81 self.order
82 .iter()
83 .map(|cid| (cid, self.cid_to_events.get(cid).unwrap()))
84 }
85
86 #[allow(clippy::should_implement_trait)]
87 pub fn into_iter(self) -> impl Iterator<Item = (ContainerID, Diff)> {
88 let mut cid_to_events = self.cid_to_events;
89 self.order.into_iter().map(move |cid| {
90 let d = cid_to_events.remove(&cid).unwrap();
91 (cid, d)
92 })
93 }
94}
95
96fn transform_cursor(
97 cursor_with_pos: &mut CursorWithPos,
98 remote_diff: &DiffBatch,
99 doc: &LoroDoc,
100 container_remap: &FxHashMap<ContainerID, ContainerID>,
101) {
102 let mut container_changed = false;
103 let mut cid = &cursor_with_pos.cursor.container;
104 while let Some(new_cid) = container_remap.get(cid) {
105 cid = new_cid;
106 container_changed = true;
107 }
108
109 if cursor_with_pos.cursor.id.is_none() {
110 if container_changed {
112 cursor_with_pos.cursor.container = cid.clone();
113 }
114 return;
115 }
116
117 if let Some(diff) = remote_diff.cid_to_events.get(cid) {
118 let new_pos = diff.transform_cursor(cursor_with_pos.pos.pos, false);
119 cursor_with_pos.pos.pos = new_pos;
120 };
121
122 let new_pos = cursor_with_pos.pos.pos;
123 match doc.get_handler(cid.clone()).unwrap() {
124 crate::handler::Handler::Text(h) => {
125 let Some(new_cursor) = h.get_cursor_internal(new_pos, cursor_with_pos.pos.side, false)
126 else {
127 return;
128 };
129
130 cursor_with_pos.cursor = new_cursor;
131 }
132 crate::handler::Handler::List(h) => {
133 let Some(new_cursor) = h.get_cursor(new_pos, cursor_with_pos.pos.side) else {
134 return;
135 };
136
137 cursor_with_pos.cursor = new_cursor;
138 }
139 crate::handler::Handler::MovableList(h) => {
140 let Some(new_cursor) = h.get_cursor(new_pos, cursor_with_pos.pos.side) else {
141 return;
142 };
143
144 cursor_with_pos.cursor = new_cursor;
145 }
146 crate::handler::Handler::Map(_) => {}
147 crate::handler::Handler::Tree(_) => {}
148 crate::handler::Handler::Unknown(_) => {}
149 #[cfg(feature = "counter")]
150 crate::handler::Handler::Counter(_) => {}
151 }
152}
153
154pub struct UndoManager {
161 peer: Arc<AtomicU64>,
162 container_remap: Arc<Mutex<FxHashMap<ContainerID, ContainerID>>>,
163 inner: Arc<parking_lot::ReentrantMutex<RefCell<UndoManagerInner>>>,
164 _peer_id_change_sub: Subscription,
165 _undo_sub: Subscription,
166 doc: LoroDoc,
167}
168
169impl std::fmt::Debug for UndoManager {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 f.debug_struct("UndoManager")
172 .field("peer", &self.peer)
173 .field("container_remap", &self.container_remap)
174 .field("inner", &self.inner)
175 .finish()
176 }
177}
178
179#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180pub enum UndoOrRedo {
181 Undo,
182 Redo,
183}
184
185impl UndoOrRedo {
186 fn opposite(&self) -> UndoOrRedo {
187 match self {
188 Self::Undo => Self::Redo,
189 Self::Redo => Self::Undo,
190 }
191 }
192}
193
194pub type OnPush = Box<
197 dyn for<'a> Fn(UndoOrRedo, CounterSpan, Option<DiffEvent<'a>>) -> UndoItemMeta + Send + Sync,
198>;
199pub type OnPop = Box<dyn Fn(UndoOrRedo, CounterSpan, UndoItemMeta) + Send + Sync>;
200
201struct UndoManagerInner {
202 next_counter: Option<Counter>,
203 undo_stack: Stack,
204 redo_stack: Stack,
205 processing_undo: bool,
206 paused: bool,
207 last_undo_time: i64,
208 merge_interval_in_ms: i64,
209 max_stack_size: usize,
210 exclude_origin_prefixes: Vec<Box<str>>,
211 last_popped_selection: Option<Vec<CursorWithPos>>,
212 on_push: Option<OnPush>,
213 on_pop: Option<OnPop>,
214 group: Option<UndoGroup>,
215}
216
217impl std::fmt::Debug for UndoManagerInner {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 f.debug_struct("UndoManagerInner")
220 .field("latest_counter", &self.next_counter)
221 .field("undo_stack", &self.undo_stack)
222 .field("redo_stack", &self.redo_stack)
223 .field("processing_undo", &self.processing_undo)
224 .field("last_undo_time", &self.last_undo_time)
225 .field("merge_interval", &self.merge_interval_in_ms)
226 .field("max_stack_size", &self.max_stack_size)
227 .field("exclude_origin_prefixes", &self.exclude_origin_prefixes)
228 .field("group", &self.group)
229 .finish()
230 }
231}
232
233#[derive(Debug, Clone, Default)]
234struct UndoGroup {
235 start_counter: Counter,
236 affected_cids: FxHashSet<ContainerID>,
237}
238
239impl UndoGroup {
240 pub fn new(start_counter: Counter) -> Self {
241 Self {
242 start_counter,
243 affected_cids: Default::default(),
244 }
245 }
246}
247
248struct ProcessingUndoGuard {
249 inner: Arc<parking_lot::ReentrantMutex<RefCell<UndoManagerInner>>>,
250}
251
252impl Drop for ProcessingUndoGuard {
253 fn drop(&mut self) {
254 self.inner.lock().borrow_mut().processing_undo = false;
255 }
256}
257
258#[derive(Debug)]
259struct Stack {
260 stack: VecDeque<(VecDeque<StackItem>, Arc<Mutex<DiffBatch>>)>,
261 size: usize,
262}
263
264#[derive(Debug, Clone)]
265struct StackItem {
266 span: CounterSpan,
267 meta: UndoItemMeta,
268}
269
270#[derive(Debug, Default, Clone)]
275pub struct UndoItemMeta {
276 pub value: LoroValue,
277 pub cursors: Vec<CursorWithPos>,
278}
279
280#[derive(Debug, Clone)]
281pub struct CursorWithPos {
282 pub cursor: Cursor,
283 pub pos: AbsolutePosition,
284}
285
286impl UndoItemMeta {
287 pub fn new() -> Self {
288 Self {
289 value: LoroValue::Null,
290 cursors: Default::default(),
291 }
292 }
293
294 pub fn add_cursor(&mut self, cursor: &Cursor) {
299 self.cursors.push(CursorWithPos {
300 cursor: cursor.clone(),
301 pos: AbsolutePosition {
302 pos: cursor.origin_pos,
303 side: cursor.side,
304 },
305 });
306 }
307
308 pub fn set_value(&mut self, value: LoroValue) {
309 self.value = value;
310 }
311}
312
313impl Stack {
314 pub fn new() -> Self {
315 let mut stack = VecDeque::new();
316 stack.push_back((VecDeque::new(), Arc::new(Mutex::new(Default::default()))));
317 Stack { stack, size: 0 }
318 }
319
320 fn peek_top_meta(&self) -> Option<UndoItemMeta> {
324 if self.is_empty() {
325 return None;
326 }
327
328 for (items, _) in self.stack.iter().rev() {
329 if let Some(item) = items.back() {
330 return Some(item.meta.clone());
331 }
332 }
333
334 None
335 }
336
337 pub fn pop(&mut self) -> Option<(StackItem, Arc<Mutex<DiffBatch>>)> {
338 while self.stack.back().unwrap().0.is_empty() && self.stack.len() > 1 {
339 let (_, diff) = self.stack.pop_back().unwrap();
340 let diff = diff.lock();
341 if !diff.cid_to_events.is_empty() {
342 self.stack.back_mut().unwrap().1.lock().compose(&diff);
343 }
344 }
345
346 if self.stack.len() == 1 && self.stack.back().unwrap().0.is_empty() {
347 self.stack.back_mut().unwrap().1.lock().clear();
349 return None;
350 }
351
352 self.size -= 1;
353 let last = self.stack.back_mut().unwrap();
354 last.0.pop_back().map(|x| (x, last.1.clone()))
355 }
359
360 pub fn push(&mut self, span: CounterSpan, meta: UndoItemMeta) {
361 self.push_with_merge(span, meta, false, None)
362 }
363
364 pub fn push_with_merge(
365 &mut self,
366 span: CounterSpan,
367 meta: UndoItemMeta,
368 can_merge: bool,
369 group: Option<&UndoGroup>,
370 ) {
371 let last = self.stack.back_mut().unwrap();
372 let last_remote_diff = last.1.lock();
373
374 let is_disjoint_group = group.is_some_and(|g| {
376 g.affected_cids.iter().all(|cid| {
377 last_remote_diff
378 .cid_to_events
379 .get(cid)
380 .is_none_or(|diff| diff.is_empty())
381 })
382 });
383
384 let should_create_new_entry =
386 !last_remote_diff.cid_to_events.is_empty() && !is_disjoint_group;
387
388 if should_create_new_entry {
389 drop(last_remote_diff);
391 let mut v = VecDeque::new();
392 v.push_back(StackItem { span, meta });
393 self.stack
394 .push_back((v, Arc::new(Mutex::new(DiffBatch::default()))));
395 self.size += 1;
396 return;
397 }
398
399 if can_merge {
401 if let Some(last_span) = last.0.back_mut() {
402 if last_span.span.end == span.start {
403 last_span.span.end = span.end;
405 return;
406 }
407 }
408 }
409
410 self.size += 1;
412 last.0.push_back(StackItem { span, meta });
413 }
414
415 pub fn compose_remote_event(&mut self, diff: &[&ContainerDiff]) {
416 if self.is_empty() {
417 return;
418 }
419
420 let remote_diff = &mut self.stack.back_mut().unwrap().1;
421 let mut remote_diff = remote_diff.lock();
422 for e in diff {
423 if let Some(d) = remote_diff.cid_to_events.get_mut(&e.id) {
424 d.compose_ref(&e.diff);
425 } else {
426 remote_diff
427 .cid_to_events
428 .insert(e.id.clone(), e.diff.clone());
429 remote_diff.order.push(e.id.clone());
430 }
431 }
432 }
433
434 pub fn transform_based_on_this_delta(&mut self, diff: &DiffBatch) {
435 if self.is_empty() {
436 return;
437 }
438 let remote_diff = &mut self.stack.back_mut().unwrap().1;
439 remote_diff.lock().transform(diff, false);
440 }
441
442 pub fn clear(&mut self) {
443 self.stack = VecDeque::new();
444 self.stack.push_back((VecDeque::new(), Default::default()));
445 self.size = 0;
446 }
447
448 pub fn is_empty(&self) -> bool {
449 self.size == 0
450 }
451
452 pub fn len(&self) -> usize {
453 self.size
454 }
455
456 fn discard_empty_front_rows(&mut self) {
457 while self
460 .stack
461 .front()
462 .is_some_and(|(items, _)| items.is_empty())
463 {
464 self.stack.pop_front();
465 }
466 }
467
468 fn ensure_trailing_empty_row(&mut self) {
469 if self.stack.is_empty() {
470 self.stack
471 .push_back((VecDeque::new(), Arc::new(Mutex::new(Default::default()))));
472 }
473 }
474
475 fn pop_front(&mut self) {
476 if self.is_empty() {
477 return;
478 }
479
480 self.discard_empty_front_rows();
481 self.size -= 1;
482 let first = self.stack.front_mut().unwrap();
483 let f = first.0.pop_front();
484 assert!(f.is_some());
485 if first.0.is_empty() {
486 self.stack.pop_front();
487 }
488
489 self.ensure_trailing_empty_row();
490 }
491
492 fn set_top_meta(&mut self, meta: UndoItemMeta) {
493 let Some(top) = self.stack.back_mut() else {
494 return;
495 };
496 let Some(last) = top.0.back_mut() else {
497 return;
498 };
499 last.meta = meta;
500 }
501}
502
503impl Default for Stack {
504 fn default() -> Self {
505 Stack::new()
506 }
507}
508
509impl UndoManagerInner {
510 fn new(last_counter: Counter) -> Self {
511 Self {
512 next_counter: Some(last_counter),
513 undo_stack: Default::default(),
514 redo_stack: Default::default(),
515 processing_undo: false,
516 paused: false,
517 merge_interval_in_ms: 0,
518 last_undo_time: 0,
519 max_stack_size: usize::MAX,
520 exclude_origin_prefixes: vec![],
521 last_popped_selection: None,
522 on_pop: None,
523 on_push: None,
524 group: None,
525 }
526 }
527
528 fn is_disjoint_with_group(&self, diff: &[&ContainerDiff]) -> bool {
531 let Some(group) = &self.group else {
532 return false;
533 };
534
535 diff.iter().all(|d| !group.affected_cids.contains(&d.id))
536 }
537
538 fn record_checkpoint(this: &RefCell<Self>, latest_counter: Counter, event: Option<DiffEvent>) {
539 let previous_counter = this.borrow().next_counter;
540
541 if Some(latest_counter) == this.borrow().next_counter {
542 return;
543 }
544
545 if this.borrow().next_counter.is_none() {
546 this.borrow_mut().next_counter = Some(latest_counter);
547 return;
548 }
549
550 if let Some(group) = &mut this.borrow_mut().group {
551 event.iter().for_each(|e| {
552 e.events.iter().for_each(|e| {
553 group.affected_cids.insert(e.id.clone());
554 })
555 });
556 }
557
558 let now = get_sys_timestamp() as Timestamp;
559 let span = CounterSpan::new(this.borrow().next_counter.unwrap(), latest_counter);
560 let meta = this
561 .borrow()
562 .on_push
563 .as_ref()
564 .map(|x| x(UndoOrRedo::Undo, span, event))
565 .unwrap_or_default();
566
567 let mut this = this.borrow_mut();
568 let this: &mut Self = &mut this;
569 let in_merge_interval = now - this.last_undo_time < this.merge_interval_in_ms;
571
572 let group_should_merge = this.group.is_some()
575 && match (
576 previous_counter,
577 this.group.as_ref().map(|g| g.start_counter),
578 ) {
579 (Some(previous), Some(active)) => previous != active,
580 _ => true,
581 };
582
583 let should_merge = !this.undo_stack.is_empty() && (in_merge_interval || group_should_merge);
584
585 if should_merge {
586 this.undo_stack
587 .push_with_merge(span, meta, true, this.group.as_ref());
588 } else {
589 this.last_undo_time = now;
590 this.undo_stack.push(span, meta);
591 }
592
593 this.next_counter = Some(latest_counter);
594 this.redo_stack.clear();
595 while this.undo_stack.len() > this.max_stack_size {
596 this.undo_stack.pop_front();
597 }
598 }
599}
600
601fn get_counter_end(doc: &LoroDoc, peer: PeerID) -> Counter {
602 doc.oplog().lock().vv().get(&peer).cloned().unwrap_or(0)
603}
604
605impl UndoManager {
606 pub fn new(doc: &LoroDoc) -> Self {
607 let peer = Arc::new(AtomicU64::new(doc.peer_id()));
608 let peer_clone = peer.clone();
609 let peer_clone2 = peer.clone();
610 let inner = Arc::new(ReentrantMutex::new(RefCell::new(UndoManagerInner::new(
611 get_counter_end(doc, doc.peer_id()),
612 ))));
613 let inner_clone = inner.clone();
614 let inner_clone2 = inner.clone();
615 let remap_containers = Arc::new(Mutex::new(FxHashMap::default()));
616 let remap_containers_clone = remap_containers.clone();
617 let undo_sub = doc.subscribe_root(Arc::new(move |event| match event.event_meta.by {
618 EventTriggerKind::Local => {
619 let lock = inner_clone.lock();
622 if lock.borrow().processing_undo {
623 return;
624 }
625 if let Some(id) = event
626 .event_meta
627 .to
628 .iter()
629 .find(|x| x.peer == peer_clone.load(std::sync::atomic::Ordering::Relaxed))
630 {
631 let is_paused = lock.borrow().paused;
632 let should_exclude = lock
633 .borrow()
634 .exclude_origin_prefixes
635 .iter()
636 .any(|x| event.event_meta.origin.starts_with(&**x));
637 if is_paused || should_exclude {
638 let mut inner = lock.borrow_mut();
644 inner.undo_stack.compose_remote_event(event.events);
645 inner.redo_stack.compose_remote_event(event.events);
646 inner.next_counter = Some(id.counter + 1);
647 } else {
648 UndoManagerInner::record_checkpoint(&lock, id.counter + 1, Some(event));
649 }
650 }
651 }
652 EventTriggerKind::Import => {
653 let lock = inner_clone.lock();
654 let mut inner = lock.borrow_mut();
655
656 for e in event.events {
657 if let Diff::Tree(tree) = &e.diff {
658 for item in &tree.diff {
659 let target = item.target;
660 if let TreeExternalDiff::Create { .. } = &item.action {
661 remap_containers_clone
664 .lock()
665 .remove(&target.associated_meta_container());
666 }
667 }
668 }
669 }
670
671 let is_import_disjoint = inner.is_disjoint_with_group(event.events);
672
673 inner.undo_stack.compose_remote_event(event.events);
674 inner.redo_stack.compose_remote_event(event.events);
675
676 if !is_import_disjoint {
679 inner.group = None;
680 }
681 }
682 EventTriggerKind::Checkout => {
683 let lock = inner_clone.lock();
684 if lock.borrow().paused {
685 return;
686 }
687 let mut inner = lock.borrow_mut();
688 inner.undo_stack.clear();
689 inner.redo_stack.clear();
690 inner.next_counter = None;
691 }
692 }));
693
694 let sub = doc.subscribe_peer_id_change(Box::new(move |id| {
695 let lock = inner_clone2.lock();
696 let mut inner = lock.borrow_mut();
697 inner.undo_stack.clear();
698 inner.redo_stack.clear();
699 inner.next_counter = Some(id.counter);
700 peer_clone2.store(id.peer, std::sync::atomic::Ordering::Relaxed);
701 true
702 }));
703
704 UndoManager {
705 peer,
706 container_remap: remap_containers,
707 inner,
708 _peer_id_change_sub: sub,
709 _undo_sub: undo_sub,
710 doc: doc.clone(),
711 }
712 }
713
714 pub fn group_start(&self) -> LoroResult<()> {
715 let lock = self.inner.lock();
716 let mut inner = lock.borrow_mut();
717
718 if inner.group.is_some() {
719 return Err(LoroError::UndoGroupAlreadyStarted);
720 }
721
722 inner.group =
723 Some(UndoGroup::new(inner.next_counter.ok_or_else(|| {
724 LoroError::Unknown("UndoManager is not ready".into())
725 })?));
726
727 Ok(())
728 }
729
730 pub fn group_end(&self) {
731 self.inner.lock().borrow_mut().group = None;
732 }
733
734 pub fn peer(&self) -> PeerID {
735 self.peer.load(std::sync::atomic::Ordering::Relaxed)
736 }
737
738 pub fn set_merge_interval(&self, interval: i64) {
739 self.inner.lock().borrow_mut().merge_interval_in_ms = interval;
740 }
741
742 pub fn set_max_undo_steps(&self, size: usize) {
743 self.inner.lock().borrow_mut().max_stack_size = size;
744 }
745
746 pub fn add_exclude_origin_prefix(&self, prefix: &str) {
747 self.inner
748 .lock()
749 .borrow_mut()
750 .exclude_origin_prefixes
751 .push(prefix.into());
752 }
753
754 pub fn record_new_checkpoint(&self) -> LoroResult<()> {
755 self.doc.with_barrier(|| {});
758 let counter = get_counter_end(&self.doc, self.peer());
759 UndoManagerInner::record_checkpoint(&self.inner.lock(), counter, None);
760 Ok(())
761 }
762
763 #[instrument(skip_all)]
764 pub fn undo(&self) -> LoroResult<bool> {
765 self.perform(
766 |x| &mut x.undo_stack,
767 |x| &mut x.redo_stack,
768 UndoOrRedo::Undo,
769 )
770 }
771
772 #[instrument(skip_all)]
773 pub fn redo(&self) -> LoroResult<bool> {
774 self.perform(
775 |x| &mut x.redo_stack,
776 |x| &mut x.undo_stack,
777 UndoOrRedo::Redo,
778 )
779 }
780
781 fn perform(
782 &self,
783 get_stack: impl Fn(&mut UndoManagerInner) -> &mut Stack,
784 get_opposite: impl Fn(&mut UndoManagerInner) -> &mut Stack,
785 kind: UndoOrRedo,
786 ) -> LoroResult<bool> {
787 if self.inner.lock().borrow().paused {
788 return Ok(false);
789 }
790 let doc = &self.doc.clone();
791 self.record_new_checkpoint()?;
845 let end_counter = get_counter_end(doc, self.peer());
846 let mut top = {
847 let lock = self.inner.lock();
848 let mut inner = lock.borrow_mut();
849 inner.processing_undo = true;
850 get_stack(&mut inner).pop()
851 };
852 let _guard = ProcessingUndoGuard {
853 inner: self.inner.clone(),
854 };
855
856 let mut executed = false;
857 while let Some((mut span, remote_diff)) = top {
858 let mut next_push_selection = None;
859 {
860 let inner = self.inner.clone();
861 let remote_change_clone = remote_diff.lock().clone();
863 let commit = match doc.undo_internal(
864 IdSpan {
865 peer: self.peer(),
866 counter: span.span,
867 },
868 &mut self.container_remap.lock(),
869 Some(&remote_change_clone),
870 &mut |diff| {
871 info_span!("transform remote diff").in_scope(|| {
872 let inner = inner.lock();
873 get_stack(&mut inner.borrow_mut()).transform_based_on_this_delta(diff);
875 });
876 },
877 ) {
878 Ok(c) => c,
879 Err(e) => {
880 get_stack(&mut self.inner.lock().borrow_mut())
881 .push(span.span, span.meta);
882 return Err(e);
883 }
884 };
885 drop(commit);
886 let inner = self.inner.lock();
887 let mut is_some = false;
888
889 if let Some(on_pop) = inner.borrow().on_pop.as_ref() {
890 is_some = true;
891 for cursor in span.meta.cursors.iter_mut() {
892 transform_cursor(
896 cursor,
897 &remote_diff.lock(),
898 doc,
899 &self.container_remap.lock(),
900 );
901 }
902
903 on_pop(kind, span.span, span.meta.clone());
904 }
905 if is_some {
906 let take = inner.borrow_mut().last_popped_selection.take();
907 next_push_selection = take;
908 inner.borrow_mut().last_popped_selection = Some(span.meta.cursors);
909 }
910 }
911 let new_counter = get_counter_end(doc, self.peer());
912 if end_counter != new_counter {
913 let inner = self.inner.lock();
914 let mut meta = inner
915 .borrow()
916 .on_push
917 .as_ref()
918 .map(|x| {
919 x(
920 kind.opposite(),
921 CounterSpan::new(end_counter, new_counter),
922 None,
923 )
924 })
925 .unwrap_or_default();
926
927 if matches!(kind, UndoOrRedo::Undo)
928 && get_opposite(&mut inner.borrow_mut()).is_empty()
929 {
930 } else if let Some(inner) = next_push_selection.take() {
932 meta.cursors = inner;
934 }
935
936 get_opposite(&mut inner.borrow_mut())
937 .push(CounterSpan::new(end_counter, new_counter), meta);
938 inner.borrow_mut().next_counter = Some(new_counter);
939 executed = true;
940 break;
941 } else {
942 top = get_stack(&mut self.inner.lock().borrow_mut()).pop();
944 continue;
945 }
946 }
947
948 Ok(executed)
949 }
950
951 pub fn can_undo(&self) -> bool {
952 !self.inner.lock().borrow().undo_stack.is_empty()
953 }
954
955 pub fn can_redo(&self) -> bool {
956 !self.inner.lock().borrow().redo_stack.is_empty()
957 }
958
959 pub fn undo_count(&self) -> usize {
960 self.inner.lock().borrow().undo_stack.len()
961 }
962
963 pub fn redo_count(&self) -> usize {
964 self.inner.lock().borrow().redo_stack.len()
965 }
966
967 pub fn top_undo_meta(&self) -> Option<UndoItemMeta> {
969 self.inner.lock().borrow().undo_stack.peek_top_meta()
970 }
971
972 pub fn top_redo_meta(&self) -> Option<UndoItemMeta> {
974 self.inner.lock().borrow().redo_stack.peek_top_meta()
975 }
976
977 pub fn top_undo_value(&self) -> Option<LoroValue> {
979 self.top_undo_meta().map(|m| m.value)
980 }
981
982 pub fn top_redo_value(&self) -> Option<LoroValue> {
984 self.top_redo_meta().map(|m| m.value)
985 }
986
987 pub fn set_on_push(&self, on_push: Option<OnPush>) {
988 self.inner.lock().borrow_mut().on_push = on_push;
989 }
990
991 pub fn set_on_pop(&self, on_pop: Option<OnPop>) {
992 self.inner.lock().borrow_mut().on_pop = on_pop;
993 }
994
995 pub fn clear(&self) {
996 self.inner.lock().borrow_mut().undo_stack.clear();
997 self.inner.lock().borrow_mut().redo_stack.clear();
998 }
999
1000 pub fn clear_redo(&self) {
1002 self.inner.lock().borrow_mut().redo_stack.clear();
1003 }
1004
1005 pub fn clear_undo(&self) {
1007 self.inner.lock().borrow_mut().undo_stack.clear();
1008 }
1009
1010 pub fn pause(&self) {
1023 self.inner.lock().borrow_mut().paused = true;
1024 }
1025
1026 pub fn resume(&self) {
1028 self.inner.lock().borrow_mut().paused = false;
1029 }
1030
1031 pub fn is_paused(&self) -> bool {
1033 self.inner.lock().borrow().paused
1034 }
1035
1036 pub fn set_top_undo_meta(&self, meta: UndoItemMeta) {
1037 self.inner.lock().borrow_mut().undo_stack.set_top_meta(meta);
1038 }
1039
1040 pub fn set_top_redo_meta(&self, meta: UndoItemMeta) {
1041 self.inner.lock().borrow_mut().redo_stack.set_top_meta(meta);
1042 }
1043}
1044
1045pub(crate) fn undo(
1059 spans: Vec<(IdSpan, Frontiers)>,
1060 last_frontiers_or_last_bi: Either<&Frontiers, &DiffBatch>,
1061 calc_diff: impl Fn(&Frontiers, &Frontiers) -> DiffBatch,
1062 on_last_event_a: &mut dyn FnMut(&DiffBatch),
1063) -> DiffBatch {
1064 let mut last_ci: Option<DiffBatch> = None;
1082 for i in 0..spans.len() {
1083 debug_span!("Undo", ?i, "Undo span {:?}", &spans[i]).in_scope(|| {
1084 let (this_id_span, this_deps) = &spans[i];
1085 let mut event_a_i = debug_span!("1. Calc event A_i").in_scope(|| {
1089 calc_diff(&this_id_span.id_last().into(), this_deps)
1091 });
1092
1093 let stack_diff_batch;
1099 let event_b_i = 'block: {
1100 let next = if i + 1 < spans.len() {
1101 spans[i + 1].0.id_last().into()
1102 } else {
1103 match last_frontiers_or_last_bi {
1104 Either::Left(last_frontiers) => last_frontiers.clone(),
1105 Either::Right(right) => break 'block right,
1106 }
1107 };
1108 stack_diff_batch = Some(calc_diff(&this_id_span.id_last().into(), &next));
1109 stack_diff_batch.as_ref().unwrap()
1110 };
1111
1112 let mut event_a_prime = if let Some(mut last_ci) = last_ci.take() {
1116 last_ci.transform(&event_a_i, true);
1120
1121 event_a_i.compose(&last_ci);
1122 event_a_i
1123 } else {
1124 event_a_i
1125 };
1126 if i == spans.len() - 1 {
1127 on_last_event_a(&event_a_prime);
1128 }
1129 event_a_prime.transform(event_b_i, true);
1133
1134 let c_i = event_a_prime;
1137 last_ci = Some(c_i);
1138 });
1139 }
1140
1141 last_ci.unwrap()
1142}