1use std::collections::HashSet;
2use std::fmt::Formatter;
3use std::ops::{Deref, DerefMut};
4use std::sync::atomic::{AtomicPtr, Ordering};
5use std::sync::Arc;
6
7use crate::block::ItemPtr;
8use crate::branch::{Branch, BranchPtr};
9use crate::iter::TxnIterator;
10use crate::slice::BlockSlice;
11use crate::sync::Clock;
12use crate::transaction::Origin;
13use crate::{DeleteSet, Doc, Observer, ReadTxn, Transact, TransactionAcqError, TransactionMut, ID};
14
15pub struct UndoManager<M> {
37 state: Arc<Inner<M>>,
38 doc: Doc,
39}
40
41#[cfg(feature = "sync")]
42type UndoFn<M> = Box<dyn Fn(&TransactionMut, &mut Event<M>) + Send + Sync + 'static>;
43
44#[cfg(not(feature = "sync"))]
45type UndoFn<M> = Box<dyn Fn(&TransactionMut, &mut Event<M>) + 'static>;
46
47#[cfg(feature = "sync")]
48pub trait Meta: Default + Send + Sync {}
49#[cfg(feature = "sync")]
50impl<M> Meta for M where M: Default + Send + Sync {}
51
52#[cfg(not(feature = "sync"))]
53pub trait Meta: Default {}
54#[cfg(not(feature = "sync"))]
55impl<M> Meta for M where M: Default {}
56
57struct Inner<M> {
58 scope: HashSet<BranchPtr>,
59 options: Options,
60 undo_stack: UndoStack<M>,
61 redo_stack: UndoStack<M>,
62 undoing: bool,
63 redoing: bool,
64 last_change: u64,
65 observer_added: Observer<UndoFn<M>>,
66 observer_updated: Observer<UndoFn<M>>,
67 observer_popped: Observer<UndoFn<M>>,
68}
69
70impl<M> UndoManager<M>
71where
72 M: Meta + 'static,
73{
74 #[cfg(not(target_family = "wasm"))]
78 pub fn new<T>(doc: &Doc, scope: &T) -> Self
79 where
80 T: AsRef<Branch>,
81 {
82 Self::with_scope_and_options(doc, scope, Options::default())
83 }
84
85 #[inline]
86 pub fn doc(&self) -> &Doc {
87 &self.doc
88 }
89
90 pub fn with_options(doc: &Doc, options: Options) -> Self {
95 let mut inner = Arc::new(Inner {
96 scope: HashSet::new(),
97 options,
98 undo_stack: UndoStack::default(),
99 redo_stack: UndoStack::default(),
100 undoing: false,
101 redoing: false,
102 last_change: 0,
103 observer_added: Observer::new(),
104 observer_updated: Observer::new(),
105 observer_popped: Observer::new(),
106 });
107 let origin = Origin::from(Arc::as_ptr(&inner) as usize);
108 let inner_mut = Arc::get_mut(&mut inner).unwrap();
109 inner_mut.options.tracked_origins.insert(origin.clone());
110 let ptr = AtomicPtr::new(inner_mut as *mut Inner<M>);
111
112 doc.observe_destroy_with(origin.clone(), move |txn, _| {
113 let ptr = ptr.load(Ordering::Acquire);
114 let inner = unsafe { ptr.as_mut().unwrap() };
115 Self::handle_destroy(txn, inner)
116 })
117 .unwrap();
118 let ptr = AtomicPtr::new(inner_mut as *mut Inner<M>);
119
120 doc.observe_after_transaction_with(origin, move |txn| {
121 let ptr = ptr.load(Ordering::Acquire);
122 let inner = unsafe { ptr.as_mut().unwrap() };
123 Self::handle_after_transaction(inner, txn);
124 })
125 .unwrap();
126
127 UndoManager {
128 state: inner,
129 doc: doc.clone(),
130 }
131 }
132
133 pub fn with_scope_and_options<T>(doc: &Doc, scope: &T, options: Options) -> Self
137 where
138 T: AsRef<Branch>,
139 {
140 let mut mgr = Self::with_options(doc, options);
141 mgr.expand_scope(scope);
142 mgr
143 }
144
145 fn should_skip(inner: &Inner<M>, txn: &TransactionMut) -> bool {
146 if let Some(capture_transaction) = &inner.options.capture_transaction {
147 if !capture_transaction(txn) {
148 return true;
149 }
150 }
151 !inner
152 .scope
153 .iter()
154 .any(|parent| txn.changed_parent_types.contains(parent))
155 || !txn
156 .origin()
157 .map(|o| inner.options.tracked_origins.contains(o))
158 .unwrap_or(inner.options.tracked_origins.len() == 1) }
160
161 fn handle_after_transaction(inner: &mut Inner<M>, txn: &mut TransactionMut) {
162 if Self::should_skip(inner, txn) {
163 return;
164 }
165 let undoing = inner.undoing;
166 let redoing = inner.redoing;
167 if undoing {
168 inner.last_change = 0; } else if !redoing {
170 let len = inner.redo_stack.len();
172 for item in inner.redo_stack.drain(0..len) {
173 Self::clear_item(&inner.scope, txn, item);
174 }
175 }
176
177 let mut insertions = DeleteSet::new();
178 for (client, &end_clock) in txn.after_state().iter() {
179 let start_clock = txn.before_state.get(client);
180 let diff = end_clock - start_clock;
181 if diff != 0 {
182 insertions.insert(ID::new(*client, start_clock), diff);
183 }
184 }
185 let now = inner.options.timestamp.now();
186 let stack = if undoing {
187 &mut inner.redo_stack
188 } else {
189 &mut inner.undo_stack
190 };
191 let extend = !undoing
192 && !redoing
193 && !stack.is_empty()
194 && inner.last_change > 0
195 && now - inner.last_change < inner.options.capture_timeout_millis;
196
197 if extend {
198 if let Some(last_op) = stack.last_mut() {
200 last_op.deletions.merge(txn.delete_set.clone());
202 last_op.insertions.merge(insertions);
203 }
204 } else {
205 let item = StackItem::new(txn.delete_set.clone(), insertions);
207 stack.push(item);
208 }
209
210 if !undoing && !redoing {
211 inner.last_change = now;
212 }
213 let ds = txn.delete_set.clone();
215 let mut deleted = ds.deleted_blocks();
216 while let Some(slice) = deleted.next(txn) {
217 if let Some(item) = slice.as_item() {
218 if inner.scope.iter().any(|b| b.is_parent_of(Some(item))) {
219 item.keep(true);
220 }
221 }
222 }
223
224 let last_op = stack.last_mut().unwrap();
225 let meta = std::mem::take(&mut last_op.meta);
226 let mut event = if undoing {
227 Event::undo(meta, txn.origin.clone(), txn.changed_parent_types.clone())
228 } else {
229 Event::redo(meta, txn.origin.clone(), txn.changed_parent_types.clone())
230 };
231 if !extend {
232 if inner.observer_added.has_subscribers() {
233 inner.observer_added.trigger(|fun| fun(txn, &mut event));
234 }
235 } else {
236 if inner.observer_updated.has_subscribers() {
237 inner.observer_updated.trigger(|fun| fun(txn, &mut event));
238 }
239 }
240 last_op.meta = event.meta;
241 }
242
243 fn handle_destroy(txn: &TransactionMut, inner: &mut Inner<M>) {
244 let origin = Origin::from(inner as *mut Inner<M> as usize);
245 if inner.options.tracked_origins.remove(&origin) {
246 if let Some(events) = txn.events() {
247 events.destroy_events.unsubscribe(&origin);
248 events.after_transaction_events.unsubscribe(&origin);
249 }
250 }
251 }
252
253 #[cfg(feature = "sync")]
260 pub fn observe_item_added<F>(&self, f: F) -> crate::Subscription
261 where
262 F: Fn(&TransactionMut, &mut Event<M>) + Send + Sync + 'static,
263 {
264 self.state.observer_added.subscribe(Box::new(f))
265 }
266
267 #[cfg(not(feature = "sync"))]
274 pub fn observe_item_added<F>(&self, f: F) -> crate::Subscription
275 where
276 F: Fn(&TransactionMut, &mut Event<M>) + 'static,
277 {
278 self.state.observer_added.subscribe(Box::new(f))
279 }
280
281 #[cfg(feature = "sync")]
289 pub fn observe_item_added_with<K, F>(&self, key: K, f: F)
290 where
291 K: Into<Origin>,
292 F: Fn(&TransactionMut, &mut Event<M>) + Send + Sync + 'static,
293 {
294 self.state
295 .observer_added
296 .subscribe_with(key.into(), Box::new(f))
297 }
298
299 #[cfg(not(feature = "sync"))]
307 pub fn observe_item_added_with<K, F>(&self, key: K, f: F)
308 where
309 K: Into<Origin>,
310 F: Fn(&TransactionMut, &mut Event<M>) + 'static,
311 {
312 self.state
313 .observer_added
314 .subscribe_with(key.into(), Box::new(f))
315 }
316
317 pub fn unobserve_item_added<K>(&self, key: K) -> bool
318 where
319 K: Into<Origin>,
320 {
321 self.state.observer_added.unsubscribe(&key.into())
322 }
323
324 #[cfg(feature = "sync")]
330 pub fn observe_item_updated<F>(&self, f: F) -> crate::Subscription
331 where
332 F: Fn(&TransactionMut, &mut Event<M>) + Send + Sync + 'static,
333 {
334 self.state.observer_updated.subscribe(Box::new(f))
335 }
336
337 #[cfg(not(feature = "sync"))]
343 pub fn observe_item_updated<F>(&self, f: F) -> crate::Subscription
344 where
345 F: Fn(&TransactionMut, &mut Event<M>) + 'static,
346 {
347 self.state.observer_updated.subscribe(Box::new(f))
348 }
349
350 #[cfg(feature = "sync")]
357 pub fn observe_item_updated_with<K, F>(&self, key: K, f: F)
358 where
359 K: Into<Origin>,
360 F: Fn(&TransactionMut, &mut Event<M>) + Send + Sync + 'static,
361 {
362 self.state
363 .observer_updated
364 .subscribe_with(key.into(), Box::new(f))
365 }
366
367 #[cfg(not(feature = "sync"))]
374 pub fn observe_item_updated_with<K, F>(&self, key: K, f: F)
375 where
376 K: Into<Origin>,
377 F: Fn(&TransactionMut, &mut Event<M>) + 'static,
378 {
379 self.state
380 .observer_updated
381 .subscribe_with(key.into(), Box::new(f))
382 }
383
384 pub fn unobserve_item_updated<K>(&self, key: K) -> bool
385 where
386 K: Into<Origin>,
387 {
388 self.state.observer_updated.unsubscribe(&key.into())
389 }
390
391 #[cfg(feature = "sync")]
396 pub fn observe_item_popped<F>(&self, f: F) -> crate::Subscription
397 where
398 F: Fn(&TransactionMut, &mut Event<M>) + Send + Sync + 'static,
399 {
400 self.state.observer_popped.subscribe(Box::new(f))
401 }
402
403 #[cfg(not(feature = "sync"))]
408 pub fn observe_item_popped<F>(&self, f: F) -> crate::Subscription
409 where
410 F: Fn(&TransactionMut, &mut Event<M>) + 'static,
411 {
412 self.state.observer_popped.subscribe(Box::new(f))
413 }
414
415 #[cfg(feature = "sync")]
421 pub fn observe_item_popped_with<K, F>(&self, key: K, f: F)
422 where
423 K: Into<Origin>,
424 F: Fn(&TransactionMut, &mut Event<M>) + Send + Sync + 'static,
425 {
426 self.state
427 .observer_popped
428 .subscribe_with(key.into(), Box::new(f))
429 }
430
431 #[cfg(not(feature = "sync"))]
437 pub fn observe_item_popped_with<K, F>(&self, key: K, f: F)
438 where
439 K: Into<Origin>,
440 F: Fn(&TransactionMut, &mut Event<M>) + 'static,
441 {
442 self.state
443 .observer_popped
444 .subscribe_with(key.into(), Box::new(f))
445 }
446
447 pub fn unobserve_item_popped<K>(&self, key: K) -> bool
448 where
449 K: Into<Origin>,
450 {
451 self.state.observer_popped.unsubscribe(&key.into())
452 }
453
454 pub fn expand_scope<T>(&mut self, scope: &T)
456 where
457 T: AsRef<Branch>,
458 {
459 let ptr = BranchPtr::from(scope.as_ref());
460 let inner = Arc::get_mut(&mut self.state).unwrap();
461 inner.scope.insert(ptr);
462 }
463
464 pub fn include_origin<O>(&mut self, origin: O)
468 where
469 O: Into<Origin>,
470 {
471 let inner = Arc::get_mut(&mut self.state).unwrap();
472 inner.options.tracked_origins.insert(origin.into());
473 }
474
475 pub fn exclude_origin<O>(&mut self, origin: O)
477 where
478 O: Into<Origin>,
479 {
480 let inner = Arc::get_mut(&mut self.state).unwrap();
481 inner.options.tracked_origins.remove(&origin.into());
482 }
483
484 pub fn clear(&mut self) {
494 let txn = self.doc.transact();
495 let inner = Arc::get_mut(&mut self.state).unwrap();
496
497 let len = inner.undo_stack.len();
498 for item in inner.undo_stack.drain(0..len) {
499 Self::clear_item(&inner.scope, &txn, item);
500 }
501
502 let len = inner.redo_stack.len();
503 for item in inner.redo_stack.drain(0..len) {
504 Self::clear_item(&inner.scope, &txn, item);
505 }
506 }
507
508 fn clear_item<T: ReadTxn>(scope: &HashSet<BranchPtr>, txn: &T, stack_item: StackItem<M>) {
509 let mut deleted = stack_item.deletions.deleted_blocks();
510 while let Some(slice) = deleted.next(txn) {
511 if let Some(item) = slice.as_item() {
512 if scope.iter().any(|b| b.is_parent_of(Some(item))) {
513 item.keep(false);
514 }
515 }
516 }
517 }
518
519 pub fn as_origin(&self) -> Origin {
520 let mgr_ptr: *const Inner<M> = &*self.state;
521 Origin::from(mgr_ptr as usize)
522 }
523
524 pub fn reset(&mut self) {
551 let inner = Arc::get_mut(&mut self.state).unwrap();
552 inner.last_change = 0;
553 }
554
555 pub fn can_undo(&self) -> bool {
557 !self.state.undo_stack.is_empty()
558 }
559
560 pub fn undo_stack(&self) -> &[StackItem<M>] {
563 &self.state.undo_stack.0
564 }
565
566 pub fn redo_stack(&self) -> &[StackItem<M>] {
569 &self.state.redo_stack.0
570 }
571
572 pub async fn undo(&mut self) -> bool {
586 let origin = self.as_origin();
587 let inner = Arc::get_mut(&mut self.state).unwrap();
588 let txn = crate::AsyncTransact::transact_mut_with(&self.doc, origin.clone()).await;
589 Self::undo_inner(inner, txn, origin)
590 }
591
592 pub fn undo_blocking(&mut self) -> bool {
606 let origin = self.as_origin();
607 let inner = Arc::get_mut(&mut self.state).unwrap();
608 let txn = self.doc.transact_mut_with(origin.clone());
609 Self::undo_inner(inner, txn, origin)
610 }
611
612 pub fn try_undo(&mut self) -> Result<bool, TransactionAcqError> {
626 let origin = self.as_origin();
627 let inner = Arc::get_mut(&mut self.state).unwrap();
628 let txn = self.doc.try_transact_mut_with(origin.clone())?;
629 let changed = Self::undo_inner(inner, txn, origin);
630 Ok(changed)
631 }
632
633 fn undo_inner(inner: &mut Inner<M>, mut txn: TransactionMut, origin: Origin) -> bool {
634 inner.undoing = true;
635 let result = Self::pop(
636 &mut inner.undo_stack,
637 &inner.redo_stack,
638 &mut txn,
639 &inner.scope,
640 );
641 txn.commit();
642 let changed = if let Some(item) = result {
643 let mut e = Event::undo(item.meta, Some(origin), txn.changed_parent_types.clone());
644 if inner.observer_popped.has_subscribers() {
645 inner.observer_popped.trigger(|fun| fun(&txn, &mut e));
646 }
647 true
648 } else {
649 false
650 };
651 inner.undoing = false;
652 changed
653 }
654
655 pub fn can_redo(&self) -> bool {
657 !self.state.redo_stack.is_empty()
658 }
659
660 pub async fn redo(&mut self) -> bool {
674 let origin = self.as_origin();
675 let inner = Arc::get_mut(&mut self.state).unwrap();
676 let txn = crate::AsyncTransact::transact_mut_with(&self.doc, origin.clone()).await;
677 let changed = Self::redo_inner(inner, txn, origin);
678 changed
679 }
680
681 pub fn redo_blocking(&mut self) -> bool {
695 let origin = self.as_origin();
696 let inner = Arc::get_mut(&mut self.state).unwrap();
697 let txn = self.doc.transact_mut_with(origin.clone());
698 let changed = Self::redo_inner(inner, txn, origin);
699 changed
700 }
701
702 pub fn try_redo(&mut self) -> Result<bool, TransactionAcqError> {
714 let origin = self.as_origin();
715 let inner = Arc::get_mut(&mut self.state).unwrap();
716 let txn = self.doc.try_transact_mut_with(origin.clone())?;
717 let changed = Self::redo_inner(inner, txn, origin);
718 Ok(changed)
719 }
720
721 fn redo_inner(inner: &mut Inner<M>, mut txn: TransactionMut, origin: Origin) -> bool {
722 inner.redoing = true;
723 let result = Self::pop(
724 &mut inner.redo_stack,
725 &inner.undo_stack,
726 &mut txn,
727 &inner.scope,
728 );
729 txn.commit();
730 let changed = if let Some(item) = result {
731 let mut e = Event::redo(item.meta, Some(origin), txn.changed_parent_types.clone());
732 if inner.observer_popped.has_subscribers() {
733 inner.observer_popped.trigger(|fun| fun(&txn, &mut e));
734 }
735 true
736 } else {
737 false
738 };
739 inner.redoing = false;
740 changed
741 }
742
743 fn pop(
744 stack: &mut UndoStack<M>,
745 other: &UndoStack<M>,
746 txn: &mut TransactionMut,
747 scope: &HashSet<BranchPtr>,
748 ) -> Option<StackItem<M>> {
749 let mut result = None;
750 while let Some(item) = stack.pop() {
751 let mut to_redo = HashSet::<ItemPtr>::new();
752 let mut to_delete = Vec::<ItemPtr>::new();
753 let mut change_performed = false;
754
755 let deleted: Vec<_> = item.insertions.deleted_blocks().collect(txn);
756 for slice in deleted {
757 if let BlockSlice::Item(slice) = slice {
758 let mut item = txn.store.materialize(slice);
759 if item.redone.is_some() {
760 let slice = txn.store_mut().follow_redone(item.id())?;
761 item = txn.store.materialize(slice);
762 }
763
764 if !item.is_deleted() && scope.iter().any(|b| b.is_parent_of(Some(item))) {
765 to_delete.push(item);
766 }
767 }
768 }
769
770 let mut deleted = item.deletions.deleted_blocks();
771 while let Some(slice) = deleted.next(txn) {
772 if let BlockSlice::Item(slice) = slice {
773 let ptr = txn.store.materialize(slice);
774 if scope.iter().any(|b| b.is_parent_of(Some(ptr)))
775 && !item.insertions.is_deleted(ptr.id())
776 {
778 to_redo.insert(ptr);
779 }
780 }
781 }
782
783 for &ptr in to_redo.iter() {
784 let mut ptr = ptr;
785 change_performed |= ptr
786 .redo(txn, &to_redo, &item.insertions, stack, other)
787 .is_some();
788 }
789
790 for &item in to_delete.iter().rev() {
793 txn.delete(item);
795 change_performed = true;
796 }
797
798 if change_performed {
799 result = Some(item);
800 break;
801 }
802 }
803 result
804 }
805}
806
807impl<M: std::fmt::Debug> std::fmt::Debug for UndoManager<M> {
808 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
809 let mut s = f.debug_struct("UndoManager");
810 let state = &self.state;
811 s.field("scope", &state.scope);
812 s.field("tracked_origins", &state.options.tracked_origins);
813 if !state.undo_stack.is_empty() {
814 s.field("undo", &state.undo_stack);
815 }
816 if !state.redo_stack.is_empty() {
817 s.field("redo", &state.redo_stack);
818 }
819 s.finish()
820 }
821}
822
823impl<M> Drop for UndoManager<M> {
824 fn drop(&mut self) {
825 let origin = Origin::from(Arc::as_ptr(&self.state) as usize);
826 self.doc.unobserve_destroy(origin.clone()).unwrap();
827 self.doc.unobserve_after_transaction(origin).unwrap();
828 }
829}
830
831#[repr(transparent)]
832#[derive(Debug, Clone, Eq, PartialEq, Default)]
833pub(crate) struct UndoStack<M>(Vec<StackItem<M>>);
834
835impl<M> Deref for UndoStack<M> {
836 type Target = Vec<StackItem<M>>;
837
838 fn deref(&self) -> &Self::Target {
839 &self.0
840 }
841}
842
843impl<M> DerefMut for UndoStack<M> {
844 fn deref_mut(&mut self) -> &mut Self::Target {
845 &mut self.0
846 }
847}
848
849impl<M> UndoStack<M> {
850 pub fn is_deleted(&self, id: &ID) -> bool {
851 for item in self.0.iter() {
852 if item.deletions.is_deleted(id) {
853 return true;
854 }
855 }
856 false
857 }
858}
859
860pub struct Options {
862 pub capture_timeout_millis: u64,
865
866 pub tracked_origins: HashSet<Origin>,
870
871 pub capture_transaction: Option<CaptureTransactionFn>,
874
875 pub timestamp: Arc<dyn Clock>,
878}
879
880pub type CaptureTransactionFn = Arc<dyn Fn(&TransactionMut) -> bool + Send + Sync + 'static>;
881
882#[cfg(not(target_family = "wasm"))]
883impl Default for Options {
884 fn default() -> Self {
885 Options {
886 capture_timeout_millis: 500,
887 tracked_origins: HashSet::new(),
888 capture_transaction: None,
889 timestamp: Arc::new(crate::sync::time::SystemClock),
890 }
891 }
892}
893
894#[derive(Debug, Clone, Eq, PartialEq, Hash)]
905pub struct StackItem<T> {
906 deletions: DeleteSet,
907 insertions: DeleteSet,
908
909 pub meta: T,
913}
914
915impl<M: Default> StackItem<M> {
916 fn new(deletions: DeleteSet, insertions: DeleteSet) -> Self {
917 StackItem {
918 deletions,
919 insertions,
920 meta: M::default(),
921 }
922 }
923
924 pub fn deletions(&self) -> &DeleteSet {
927 &self.deletions
928 }
929
930 pub fn insertions(&self) -> &DeleteSet {
933 &self.insertions
934 }
935}
936
937impl<M> std::fmt::Display for StackItem<M> {
938 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
939 write!(f, "StackItem(")?;
940 if !self.deletions.is_empty() {
941 write!(f, "-{}", self.deletions)?;
942 }
943 if !self.insertions.is_empty() {
944 write!(f, "+{}", self.insertions)?;
945 }
946 write!(f, ")")
947 }
948}
949
950#[derive(Debug)]
951pub struct Event<M> {
952 meta: M,
953 origin: Option<Origin>,
954 kind: EventKind,
955 changed_parent_types: Vec<BranchPtr>,
956}
957
958impl<M> Event<M> {
959 fn undo(meta: M, origin: Option<Origin>, changed_parent_types: Vec<BranchPtr>) -> Self {
960 Event {
961 meta,
962 origin,
963 changed_parent_types,
964 kind: EventKind::Undo,
965 }
966 }
967
968 fn redo(meta: M, origin: Option<Origin>, changed_parent_types: Vec<BranchPtr>) -> Self {
969 Event {
970 meta,
971 origin,
972 changed_parent_types,
973 kind: EventKind::Redo,
974 }
975 }
976
977 pub fn meta(&self) -> &M {
978 &self.meta
979 }
980
981 pub fn meta_mut(&mut self) -> &mut M {
982 &mut self.meta
983 }
984
985 pub fn has_changed<T: AsRef<Branch>>(&self, target: &T) -> bool {
987 let ptr = BranchPtr::from(target.as_ref());
988 self.changed_parent_types.contains(&ptr)
989 }
990
991 pub fn origin(&self) -> Option<&Origin> {
993 self.origin.as_ref()
994 }
995
996 pub fn kind(&self) -> EventKind {
998 self.kind
999 }
1000
1001 pub fn changed_parent_types(&self) -> &[BranchPtr] {
1003 &self.changed_parent_types
1004 }
1005}
1006
1007#[repr(u8)]
1010#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
1011pub enum EventKind {
1012 Undo,
1014 Redo,
1016}
1017
1018#[cfg(test)]
1019mod test {
1020 use std::collections::HashMap;
1021 use std::convert::TryInto;
1022 use std::sync::atomic::{AtomicUsize, Ordering};
1023 use std::sync::Arc;
1024
1025 use crate::test_utils::exchange_updates;
1026 use crate::types::text::{Diff, YChange};
1027 use crate::types::{Attrs, ToJson};
1028 use crate::undo::Options;
1029 use crate::updates::decoder::Decode;
1030 use crate::{
1031 any, Any, Array, ArrayPrelim, Doc, GetString, Map, MapPrelim, MapRef, ReadTxn, StateVector,
1032 Text, TextPrelim, TextRef, Transact, UndoManager, Update, Xml, XmlElementPrelim,
1033 XmlElementRef, XmlFragment, XmlTextPrelim,
1034 };
1035
1036 #[test]
1037 fn undo_text() {
1038 let d1 = Doc::with_client_id(1);
1039 let txt1 = d1.get_or_insert_text("test");
1040 let mut mgr = UndoManager::new(&d1, &txt1);
1041
1042 let d2 = Doc::with_client_id(2);
1043 let txt2 = d2.get_or_insert_text("test");
1044
1045 txt1.insert(&mut d1.transact_mut(), 0, "test");
1047 txt1.remove_range(&mut d1.transact_mut(), 0, 4);
1048 mgr.undo_blocking();
1049 assert_eq!(txt1.get_string(&d1.transact()), "");
1050
1051 txt1.insert(&mut d1.transact_mut(), 0, "a");
1053 mgr.reset();
1054 txt1.remove_range(&mut d1.transact_mut(), 0, 1);
1055 mgr.reset();
1056 mgr.undo_blocking();
1057 assert_eq!(txt1.get_string(&d1.transact()), "a");
1058 mgr.undo_blocking();
1059 assert_eq!(txt1.get_string(&d1.transact()), "");
1060
1061 txt1.insert(&mut d1.transact_mut(), 0, "abc");
1062 txt2.insert(&mut d2.transact_mut(), 0, "xyz");
1063
1064 exchange_updates(&[&d1, &d2]);
1065 mgr.undo_blocking();
1066 assert_eq!(txt1.get_string(&d1.transact()), "xyz");
1067 mgr.redo_blocking();
1068 assert_eq!(txt1.get_string(&d1.transact()), "abcxyz");
1069
1070 exchange_updates(&[&d1, &d2]);
1071
1072 txt2.remove_range(&mut d2.transact_mut(), 0, 1);
1073
1074 exchange_updates(&[&d1, &d2]);
1075
1076 mgr.undo_blocking();
1077 assert_eq!(txt1.get_string(&d1.transact()), "xyz");
1078 mgr.redo_blocking();
1079 assert_eq!(txt1.get_string(&d1.transact()), "bcxyz");
1080
1081 let attrs = Attrs::from([("bold".into(), true.into())]);
1083 txt1.format(&mut d1.transact_mut(), 1, 3, attrs.clone());
1084 let diff = txt1.diff(&d1.transact(), YChange::identity);
1085 assert_eq!(
1086 diff,
1087 vec![
1088 Diff::new("b".into(), None),
1089 Diff::new("cxy".into(), Some(Box::new(attrs.clone()))),
1090 Diff::new("z".into(), None),
1091 ]
1092 );
1093
1094 mgr.undo_blocking();
1095 let diff = txt1.diff(&d1.transact(), YChange::identity);
1096 assert_eq!(diff, vec![Diff::new("bcxyz".into(), None)]);
1097
1098 mgr.redo_blocking();
1099 let diff = txt1.diff(&d1.transact(), YChange::identity);
1100 assert_eq!(
1101 diff,
1102 vec![
1103 Diff::new("b".into(), None),
1104 Diff::new("cxy".into(), Some(Box::new(attrs.clone()))),
1105 Diff::new("z".into(), None),
1106 ]
1107 );
1108 }
1109
1110 #[test]
1111 fn double_undo() {
1112 let doc = Doc::with_client_id(1);
1113 let txt = doc.get_or_insert_text("test");
1114 txt.insert(&mut doc.transact_mut(), 0, "1221");
1115
1116 let mut mgr = UndoManager::new(&doc, &txt);
1117 txt.insert(&mut doc.transact_mut(), 2, "3");
1118 txt.insert(&mut doc.transact_mut(), 3, "3");
1119
1120 mgr.undo_blocking();
1121 mgr.undo_blocking();
1122
1123 txt.insert(&mut doc.transact_mut(), 2, "3");
1124 assert_eq!(txt.get_string(&doc.transact()), "12321");
1125 }
1126
1127 #[test]
1128 fn undo_map() {
1129 let d1 = Doc::with_client_id(1);
1130 let map1 = d1.get_or_insert_map("test");
1131
1132 let d2 = Doc::with_client_id(2);
1133 let map2 = d2.get_or_insert_map("test");
1134
1135 map1.insert(&mut d1.transact_mut(), "a", 0);
1136 let mut mgr = UndoManager::new(&d1, &map1);
1137 map1.insert(&mut d1.transact_mut(), "a", 1);
1138 mgr.undo_blocking();
1139 assert_eq!(map1.get(&d1.transact(), "a").unwrap(), 0.into());
1140 mgr.redo_blocking();
1141 assert_eq!(map1.get(&d1.transact(), "a").unwrap(), 1.into());
1142
1143 let sub_type = map1.insert(&mut d1.transact_mut(), "a", MapPrelim::default());
1145 sub_type.insert(&mut d1.transact_mut(), "x", 42);
1146 let actual = map1.to_json(&d1.transact());
1147 let expected = Any::from_json(r#"{ "a": { "x": 42 } }"#).unwrap();
1148 assert_eq!(actual, expected);
1149
1150 mgr.undo_blocking();
1151 assert_eq!(map1.get(&d1.transact(), "a").unwrap(), 1.into());
1152 mgr.redo_blocking();
1153 let actual = map1.to_json(&d1.transact());
1154 let expected = Any::from_json(r#"{ "a": { "x": 42 } }"#).unwrap();
1155 assert_eq!(actual, expected);
1156
1157 exchange_updates(&[&d1, &d2]);
1158
1159 map2.insert(&mut d2.transact_mut(), "a", 44);
1161
1162 exchange_updates(&[&d1, &d2]);
1163 exchange_updates(&[&d1, &d2]);
1164
1165 mgr.undo_blocking();
1166 assert_eq!(map1.get(&d1.transact(), "a").unwrap(), 44.into());
1167 mgr.redo_blocking();
1168 assert_eq!(map1.get(&d1.transact(), "a").unwrap(), 44.into());
1169
1170 map1.insert(&mut d1.transact_mut(), "b", "initial");
1172 mgr.reset();
1173 map1.insert(&mut d1.transact_mut(), "b", "val1");
1174 map1.insert(&mut d1.transact_mut(), "b", "val2");
1175 mgr.reset();
1176 mgr.undo_blocking();
1177 assert_eq!(map1.get(&d1.transact(), "b").unwrap(), "initial".into());
1178 }
1179
1180 #[test]
1181 fn undo_array() {
1182 let d1 = Doc::with_client_id(1);
1183 let array1 = d1.get_or_insert_array("test");
1184
1185 let d2 = Doc::with_client_id(2);
1186 let array2 = d2.get_or_insert_array("test");
1187
1188 let mut mgr = UndoManager::new(&d1, &array1);
1189 array1.insert_range(&mut d1.transact_mut(), 0, [1, 2, 3]);
1190 array2.insert_range(&mut d2.transact_mut(), 0, [4, 5, 6]);
1191
1192 exchange_updates(&[&d1, &d2]);
1193
1194 assert_eq!(
1195 array1.to_json(&d1.transact()),
1196 vec![1, 2, 3, 4, 5, 6].into()
1197 );
1198 mgr.undo_blocking();
1199 assert_eq!(array1.to_json(&d1.transact()), vec![4, 5, 6].into());
1200 mgr.redo_blocking();
1201 assert_eq!(
1202 array1.to_json(&d1.transact()),
1203 vec![1, 2, 3, 4, 5, 6].into()
1204 );
1205
1206 exchange_updates(&[&d1, &d2]);
1207
1208 array2.remove_range(&mut d2.transact_mut(), 0, 1); exchange_updates(&[&d1, &d2]);
1211
1212 mgr.undo_blocking();
1213 assert_eq!(array1.to_json(&d1.transact()), vec![4, 5, 6].into());
1214 mgr.redo_blocking();
1215 assert_eq!(array1.to_json(&d1.transact()), vec![2, 3, 4, 5, 6].into());
1216 array1.remove_range(&mut d1.transact_mut(), 0, 5);
1217
1218 let map = array1.insert(&mut d1.transact_mut(), 0, MapPrelim::default());
1220 let actual = array1.to_json(&d1.transact());
1221 let expected = Any::from_json(r#"[{}]"#).unwrap();
1222 assert_eq!(actual, expected);
1223 mgr.reset();
1224 map.insert(&mut d1.transact_mut(), "a", 1);
1225 let actual = array1.to_json(&d1.transact());
1226 let expected = Any::from_json(r#"[{"a":1}]"#).unwrap();
1227 assert_eq!(actual, expected);
1228
1229 mgr.undo_blocking();
1230 let actual = array1.to_json(&d1.transact());
1231 let expected = Any::from_json(r#"[{}]"#).unwrap();
1232 assert_eq!(actual, expected);
1233
1234 mgr.undo_blocking();
1235 assert_eq!(array1.to_json(&d1.transact()), vec![2, 3, 4, 5, 6].into());
1236
1237 mgr.redo_blocking();
1238 let actual = array1.to_json(&d1.transact());
1239 let expected = Any::from_json(r#"[{}]"#).unwrap();
1240 assert_eq!(actual, expected);
1241
1242 mgr.redo_blocking();
1243 let actual = array1.to_json(&d1.transact());
1244 let expected = Any::from_json(r#"[{"a":1}]"#).unwrap();
1245 assert_eq!(actual, expected);
1246
1247 exchange_updates(&[&d1, &d2]);
1248
1249 let map2 = array2
1250 .get(&d2.transact(), 0)
1251 .unwrap()
1252 .cast::<MapRef>()
1253 .unwrap();
1254 map2.insert(&mut d2.transact_mut(), "b", 2);
1255 exchange_updates(&[&d1, &d2]);
1256
1257 let actual = array1.to_json(&d1.transact());
1258 let expected = Any::from_json(r#"[{"a":1,"b":2}]"#).unwrap();
1259 assert_eq!(actual, expected);
1260
1261 mgr.undo_blocking();
1262 let actual = array1.to_json(&d1.transact());
1263 let expected = Any::from_json(r#"[{"b":2}]"#).unwrap();
1264 assert_eq!(actual, expected);
1265
1266 mgr.undo_blocking();
1267 assert_eq!(array1.to_json(&d1.transact()), vec![2, 3, 4, 5, 6].into());
1268
1269 mgr.redo_blocking();
1270 let actual = array1.to_json(&d1.transact());
1271 let expected = Any::from_json(r#"[{"b":2}]"#).unwrap();
1272 assert_eq!(actual, expected);
1273
1274 mgr.redo_blocking();
1275 let actual = array1.to_json(&d1.transact());
1276 let expected = Any::from_json(r#"[{"a":1,"b":2}]"#).unwrap();
1277 assert_eq!(actual, expected);
1278 }
1279
1280 #[test]
1281 fn undo_xml() {
1282 let d1 = Doc::with_client_id(1);
1283 let frag = d1.get_or_insert_xml_fragment("xml");
1284 let xml1 = frag.insert(
1285 &mut d1.transact_mut(),
1286 0,
1287 XmlElementPrelim::empty("undefined"),
1288 );
1289
1290 let mut mgr = UndoManager::new(&d1, &xml1);
1291 let child = xml1.insert(&mut d1.transact_mut(), 0, XmlElementPrelim::empty("p"));
1292 let text_child = child.insert(&mut d1.transact_mut(), 0, XmlTextPrelim::new("content"));
1293
1294 assert_eq!(
1295 xml1.get_string(&d1.transact()),
1296 "<undefined><p>content</p></undefined>"
1297 );
1298 mgr.reset();
1300 text_child.format(
1301 &mut d1.transact_mut(),
1302 3,
1303 4,
1304 Attrs::from([("bold".into(), any!({}))]),
1305 );
1306 assert_eq!(
1307 xml1.get_string(&d1.transact()),
1308 "<undefined><p>con<bold>tent</bold></p></undefined>"
1309 );
1310 mgr.undo_blocking();
1311 assert_eq!(
1312 xml1.get_string(&d1.transact()),
1313 "<undefined><p>content</p></undefined>"
1314 );
1315 mgr.redo_blocking();
1316 assert_eq!(
1317 xml1.get_string(&d1.transact()),
1318 "<undefined><p>con<bold>tent</bold></p></undefined>"
1319 );
1320 xml1.remove_range(&mut d1.transact_mut(), 0, 1);
1321 assert_eq!(xml1.get_string(&d1.transact()), "<undefined></undefined>");
1322 mgr.undo_blocking();
1323 assert_eq!(
1324 xml1.get_string(&d1.transact()),
1325 "<undefined><p>con<bold>tent</bold></p></undefined>"
1326 );
1327 }
1328
1329 #[test]
1330 fn undo_events() {
1331 use crate::undo::UndoManager;
1332 type Metadata = HashMap<String, usize>;
1333
1334 let doc = Doc::with_client_id(1);
1335 let txt = doc.get_or_insert_text("test");
1336 let mut mgr: UndoManager<Metadata> = UndoManager::new(&doc, &txt);
1337
1338 let result = Arc::new(AtomicUsize::new(0));
1339 let counter = AtomicUsize::new(1);
1340
1341 let txt_clone = txt.clone();
1342 let _sub1 = mgr.observe_item_added(move |_, e| {
1343 assert!(e.has_changed(&txt_clone));
1344 let c = counter.fetch_add(1, Ordering::SeqCst);
1345 let e = e.meta_mut().entry("test".to_string()).or_default();
1346 *e = c;
1347 });
1348
1349 let txt_clone = txt.clone();
1350 let result_clone = result.clone();
1351 let _sub2 = mgr.observe_item_popped(move |_, e| {
1352 assert!(e.has_changed(&txt_clone));
1353 if let Some(&v) = e.meta_mut().get("test") {
1354 result_clone.store(v, Ordering::Relaxed);
1355 }
1356 });
1357
1358 txt.insert(&mut doc.transact_mut(), 0, "abc");
1359 mgr.undo_blocking();
1360 assert_eq!(result.load(Ordering::SeqCst), 1);
1361 mgr.redo_blocking();
1362 assert_eq!(result.load(Ordering::SeqCst), 2);
1363 }
1364
1365 #[test]
1366 fn undo_until_change_performed() {
1367 let d1 = Doc::with_client_id(1);
1368 let arr1 = d1.get_or_insert_array("array");
1369
1370 let d2 = Doc::with_client_id(2);
1371 let arr2 = d2.get_or_insert_array("array");
1372
1373 let map1a = arr1.push_back(
1374 &mut d1.transact_mut(),
1375 MapPrelim::from([("hello".to_owned(), "world".to_owned())]),
1376 );
1377
1378 let map1b = arr1.push_back(
1379 &mut d1.transact_mut(),
1380 MapPrelim::from([("key".to_owned(), "value".to_owned())]),
1381 );
1382
1383 exchange_updates(&[&d1, &d2]);
1384
1385 let mut mgr1 = UndoManager::new(&d1, &arr1);
1386 mgr1.include_origin(d1.client_id());
1387
1388 let mut mgr2 = UndoManager::new(&d2, &arr2);
1389 mgr2.include_origin(d2.client_id());
1390
1391 map1b.insert(
1392 &mut d1.transact_mut_with(d1.client_id()),
1393 "key",
1394 "value modified",
1395 );
1396
1397 exchange_updates(&[&d1, &d2]);
1398 mgr1.reset();
1399
1400 map1a.insert(
1401 &mut d1.transact_mut_with(d1.client_id()),
1402 "hello",
1403 "world modified",
1404 );
1405
1406 exchange_updates(&[&d1, &d2]);
1407
1408 arr2.remove_range(&mut d2.transact_mut_with(d2.client_id()), 0, 1);
1409
1410 exchange_updates(&[&d1, &d2]);
1411 mgr2.undo_blocking();
1412
1413 exchange_updates(&[&d1, &d2]);
1414 mgr1.undo_blocking();
1415 exchange_updates(&[&d1, &d2]);
1416
1417 assert_eq!(map1b.get(&d1.transact(), "key"), Some("value".into()));
1418 }
1419
1420 #[test]
1421 fn nested_undo() {
1422 let doc = Doc::with_options(crate::doc::Options {
1424 skip_gc: true,
1425 client_id: 1,
1426 ..crate::doc::Options::default()
1427 });
1428 let design = doc.get_or_insert_map("map");
1429 let mut mgr = UndoManager::with_scope_and_options(&doc, &design, {
1430 let mut o = Options::default();
1431 o.capture_timeout_millis = 0;
1432 o
1433 });
1434 {
1435 let mut txn = doc.transact_mut();
1436 design.insert(
1437 &mut txn,
1438 "text",
1439 MapPrelim::from([(
1440 "blocks",
1441 MapPrelim::from([("text", "Type something".to_owned())]),
1442 )]),
1443 );
1444 }
1445 let text = design
1446 .get(&doc.transact(), "text")
1447 .unwrap()
1448 .cast::<MapRef>()
1449 .unwrap();
1450
1451 {
1452 let mut txn = doc.transact_mut();
1453 text.insert(&mut txn, "blocks", MapPrelim::from([("text", "Something")]));
1454 }
1455
1456 {
1457 let mut txn = doc.transact_mut();
1458 text.insert(
1459 &mut txn,
1460 "blocks",
1461 MapPrelim::from([("text", "Something else")]),
1462 );
1463 }
1464
1465 assert_eq!(
1466 design.to_json(&doc.transact()),
1467 Any::from_json(r#"{ "text": { "blocks": { "text": "Something else" } } }"#).unwrap()
1468 );
1469 mgr.undo_blocking();
1470 assert_eq!(
1471 design.to_json(&doc.transact()),
1472 Any::from_json(r#"{ "text": { "blocks": { "text": "Something" } } }"#).unwrap()
1473 );
1474 mgr.undo_blocking();
1475 assert_eq!(
1476 design.to_json(&doc.transact()),
1477 Any::from_json(r#"{ "text": { "blocks": { "text": "Type something" } } }"#).unwrap()
1478 );
1479 mgr.undo_blocking();
1480 assert_eq!(
1481 design.to_json(&doc.transact()),
1482 Any::from_json(r#"{}"#).unwrap()
1483 );
1484 mgr.redo_blocking();
1485 assert_eq!(
1486 design.to_json(&doc.transact()),
1487 Any::from_json(r#"{ "text": { "blocks": { "text": "Type something" } } }"#).unwrap()
1488 );
1489 mgr.redo_blocking();
1490 assert_eq!(
1491 design.to_json(&doc.transact()),
1492 Any::from_json(r#"{ "text": { "blocks": { "text": "Something" } } }"#).unwrap()
1493 );
1494 mgr.redo_blocking();
1495 assert_eq!(
1496 design.to_json(&doc.transact()),
1497 Any::from_json(r#"{ "text": { "blocks": { "text": "Something else" } } }"#).unwrap()
1498 );
1499 }
1500
1501 #[test]
1502 fn consecutive_redo_bug() {
1503 let doc = Doc::with_client_id(1);
1505 let root = doc.get_or_insert_map("root");
1506 let mut mgr = UndoManager::new(&doc, &root);
1507
1508 root.insert(
1509 &mut doc.transact_mut(),
1510 "a",
1511 MapPrelim::from([("x".to_owned(), Any::from(0)), ("y".to_owned(), 0.into())]),
1512 );
1513 let point = root
1514 .get(&doc.transact(), "a")
1515 .unwrap()
1516 .cast::<MapRef>()
1517 .unwrap();
1518 mgr.reset();
1519
1520 point.insert(&mut doc.transact_mut(), "x", 100);
1521 point.insert(&mut doc.transact_mut(), "y", 100);
1522 mgr.reset();
1523
1524 point.insert(&mut doc.transact_mut(), "x", 200);
1525 point.insert(&mut doc.transact_mut(), "y", 200);
1526 mgr.reset();
1527
1528 point.insert(&mut doc.transact_mut(), "x", 300);
1529 point.insert(&mut doc.transact_mut(), "y", 300);
1530 mgr.reset();
1531
1532 let actual = point.to_json(&doc.transact());
1533 assert_eq!(actual, Any::from_json(r#"{"x":300,"y":300}"#).unwrap());
1534
1535 mgr.undo_blocking(); let actual = point.to_json(&doc.transact());
1537 assert_eq!(actual, Any::from_json(r#"{"x":200,"y":200}"#).unwrap());
1538
1539 mgr.undo_blocking(); let actual = point.to_json(&doc.transact());
1541 assert_eq!(actual, Any::from_json(r#"{"x":100,"y":100}"#).unwrap());
1542
1543 mgr.undo_blocking(); let actual = point.to_json(&doc.transact());
1545 assert_eq!(actual, Any::from_json(r#"{"x":0,"y":0}"#).unwrap());
1546
1547 mgr.undo_blocking(); assert_eq!(root.get(&doc.transact(), "a"), None);
1549
1550 mgr.redo_blocking(); let point = root
1552 .get(&doc.transact(), "a")
1553 .unwrap()
1554 .cast::<MapRef>()
1555 .unwrap();
1556
1557 assert_eq!(actual, Any::from_json(r#"{"x":0,"y":0}"#).unwrap());
1558
1559 mgr.redo_blocking(); let actual = point.to_json(&doc.transact());
1561 assert_eq!(actual, Any::from_json(r#"{"x":100,"y":100}"#).unwrap());
1562
1563 mgr.redo_blocking(); let actual = point.to_json(&doc.transact());
1565 assert_eq!(actual, Any::from_json(r#"{"x":200,"y":200}"#).unwrap());
1566
1567 mgr.redo_blocking(); let actual = point.to_json(&doc.transact());
1569 assert_eq!(actual, Any::from_json(r#"{"x":300,"y":300}"#).unwrap());
1570 }
1571
1572 #[test]
1573 fn undo_xml_bug() {
1574 const ORIGIN: &str = "origin";
1576 let doc = Doc::with_client_id(1);
1577 let f = doc.get_or_insert_xml_fragment("t");
1578 let mut mgr = UndoManager::with_scope_and_options(&doc, &f, {
1579 let mut o = Options::default();
1580 o.capture_timeout_millis = 0;
1581 o
1582 });
1583 mgr.include_origin(ORIGIN);
1584
1585 {
1587 let mut txn = doc.transact_mut_with(ORIGIN);
1588 let e = f.insert(&mut txn, 0, XmlElementPrelim::empty("test-node"));
1589 e.insert_attribute(&mut txn, "a", "100");
1590 e.insert_attribute(&mut txn, "b", "0");
1591 }
1592
1593 {
1595 let mut txn = doc.transact_mut_with(ORIGIN);
1596 let e: XmlElementRef = f.get(&txn, 0).unwrap().try_into().unwrap();
1597 e.insert_attribute(&mut txn, "a", "200");
1598 }
1599
1600 {
1602 let mut txn = doc.transact_mut_with(ORIGIN);
1603 let e: XmlElementRef = f.get(&txn, 0).unwrap().try_into().unwrap();
1604 e.insert_attribute(&mut txn, "a", "180");
1605 e.insert_attribute(&mut txn, "b", "50");
1606 }
1607
1608 mgr.undo_blocking();
1609 mgr.undo_blocking();
1610 mgr.undo_blocking();
1611
1612 mgr.redo_blocking();
1613 mgr.redo_blocking();
1614 mgr.redo_blocking();
1615
1616 let str = f.get_string(&doc.transact());
1617 assert!(
1618 str == r#"<test-node a="180" b="50"></test-node>"#
1619 || str == r#"<test-node b="50" a="180"></test-node>"#
1620 );
1621 }
1622
1623 #[test]
1624 fn undo_block_bug() {
1625 let doc = Doc::with_options({
1627 let mut o = crate::doc::Options::default();
1628 o.client_id = 1;
1629 o.skip_gc = true;
1630 o
1631 });
1632 let design = doc.get_or_insert_map("map");
1633 let mut mgr = UndoManager::with_scope_and_options(&doc, &design, {
1634 let mut o = Options::default();
1635 o.capture_timeout_millis = 0;
1636 o
1637 });
1638 let text = {
1639 let mut txn = doc.transact_mut();
1640 design.insert(
1641 &mut txn,
1642 "text",
1643 MapPrelim::from([(
1644 "blocks",
1645 MapPrelim::from([("text".to_owned(), "1".to_owned())]),
1646 )]),
1647 )
1648 };
1649 {
1650 let mut txn = doc.transact_mut();
1651 text.insert(
1652 &mut txn,
1653 "blocks",
1654 MapPrelim::from([("text".to_owned(), "1".to_owned())]),
1655 );
1656 }
1657 {
1658 let mut txn = doc.transact_mut();
1659 text.insert(
1660 &mut txn,
1661 "blocks",
1662 MapPrelim::from([("text".to_owned(), "3".to_owned())]),
1663 );
1664 }
1665 {
1666 let mut txn = doc.transact_mut();
1667 text.insert(
1668 &mut txn,
1669 "blocks",
1670 MapPrelim::from([("text".to_owned(), "4".to_owned())]),
1671 );
1672 }
1673 mgr.undo_blocking(); mgr.undo_blocking(); mgr.undo_blocking(); mgr.undo_blocking(); mgr.redo_blocking(); mgr.redo_blocking(); mgr.redo_blocking(); mgr.redo_blocking(); let actual = design.to_json(&doc.transact());
1683 assert_eq!(
1684 actual,
1685 Any::from_json(r#"{"text":{"blocks":{"text":"4"}}}"#).unwrap()
1686 );
1687 }
1688
1689 #[test]
1690 fn undo_delete_text_format() {
1691 fn send(src: &Doc, dst: &Doc) {
1693 let update = Update::decode_v1(
1694 &src.transact()
1695 .encode_state_as_update_v1(&StateVector::default()),
1696 )
1697 .unwrap();
1698 dst.transact_mut().apply_update(update).unwrap();
1699 }
1700
1701 let doc1 = Doc::with_client_id(1);
1702 let txt = doc1.get_or_insert_text("test");
1703 txt.insert(
1704 &mut doc1.transact_mut(),
1705 0,
1706 "Attack ships on fire off the shoulder of Orion.",
1707 ); let doc2 = Doc::with_client_id(2);
1709 let txt2 = doc2.get_or_insert_text("test");
1710
1711 send(&doc1, &doc2); let mut mgr = UndoManager::new(&doc1, &txt);
1713
1714 let attrs = Attrs::from([("bold".into(), true.into())]);
1715 txt.format(&mut doc1.transact_mut(), 13, 7, attrs.clone()); mgr.reset();
1718
1719 send(&doc1, &doc2); let attrs2 = Attrs::from([("bold".into(), Any::Null)]);
1722 txt.format(&mut doc1.transact_mut(), 16, 4, attrs2.clone()); let expected = vec![
1725 Diff::new("Attack ships ".into(), None),
1726 Diff::new("on ".into(), Some(Box::new(attrs.clone()))),
1727 Diff::new("fire off the shoulder of Orion.".into(), None),
1728 ];
1729 let actual = txt.diff(&doc1.transact(), YChange::identity);
1730 assert_eq!(actual, expected);
1731
1732 mgr.reset();
1733 send(&doc1, &doc2); mgr.undo_blocking(); send(&doc1, &doc2); let expected = vec![
1739 Diff::new("Attack ships ".into(), None),
1740 Diff::new("on fire".into(), Some(Box::new(attrs))),
1741 Diff::new(" off the shoulder of Orion.".into(), None),
1742 ];
1743 let actual = txt.diff(&doc1.transact(), YChange::identity);
1744 assert_eq!(actual, expected);
1745 let actual = txt2.diff(&doc2.transact(), YChange::identity);
1746 assert_eq!(actual, expected);
1747 }
1748
1749 #[test]
1750 fn special_deletion_case() {
1751 const ORIGIN: &str = "undoable";
1753 let doc = Doc::with_client_id(1);
1754 let f = doc.get_or_insert_xml_fragment("test");
1755 let mut mgr = UndoManager::new(&doc, &f);
1756 mgr.include_origin(ORIGIN);
1757 {
1758 let mut txn = doc.transact_mut();
1759 let e = f.insert(&mut txn, 0, XmlElementPrelim::empty("test"));
1760 e.insert_attribute(&mut txn, "a", "1");
1761 e.insert_attribute(&mut txn, "b", "2");
1762 }
1763 let s = f.get_string(&doc.transact());
1764 assert!(s == r#"<test a="1" b="2"></test>"# || s == r#"<test b="2" a="1"></test>"#);
1765 {
1766 let mut txn = doc.transact_mut_with(ORIGIN);
1768 let e: XmlElementRef = f.get(&txn, 0).unwrap().try_into().unwrap();
1769 e.insert_attribute(&mut txn, "b", "3");
1770 f.remove_range(&mut txn, 0, 1);
1771 }
1772 assert_eq!(f.get_string(&doc.transact()), "");
1773
1774 mgr.undo_blocking();
1775 let s = f.get_string(&doc.transact());
1776 assert!(s == r#"<test a="1" b="2"></test>"# || s == r#"<test b="2" a="1"></test>"#);
1777 }
1778
1779 #[test]
1780 fn undo_in_embed() {
1781 let d1 = Doc::with_client_id(1);
1782 let txt1 = d1.get_or_insert_text("test");
1783 let mut mgr = UndoManager::new(&d1, &txt1);
1784
1785 let d2 = Doc::with_client_id(2);
1786 let txt2 = d2.get_or_insert_text("test");
1787
1788 let attrs = Attrs::from([("bold".into(), true.into())]);
1789 let nested = txt1.insert_embed_with_attributes(
1790 &mut d1.transact_mut(),
1791 0,
1792 TextPrelim::new("initial text"),
1793 attrs,
1794 );
1795 assert_eq!(
1796 nested.get_string(&d1.transact()),
1797 "initial text".to_string()
1798 );
1799 mgr.reset();
1800 {
1801 let mut txn = d1.transact_mut();
1802 let len = nested.len(&txn);
1803 nested.remove_range(&mut txn, 0, len);
1804 }
1805 nested.insert(&mut d1.transact_mut(), 0, "other text");
1806 assert_eq!(nested.get_string(&d1.transact()), "other text".to_string());
1807 mgr.undo_blocking();
1808 assert_eq!(
1809 nested.get_string(&d1.transact()),
1810 "initial text".to_string()
1811 );
1812
1813 exchange_updates(&[&d1, &d2]);
1814 let diff = txt2.diff(&d1.transact(), YChange::identity);
1815 let nested2 = diff[0].insert.clone().cast::<TextRef>().unwrap();
1816 assert_eq!(
1817 nested2.get_string(&d2.transact()),
1818 "initial text".to_string()
1819 );
1820
1821 mgr.undo_blocking();
1822 assert_eq!(nested.len(&d1.transact()), 0);
1823 }
1824
1825 #[test]
1826 fn github_issue_345() {
1827 let doc = Doc::new();
1829 let map = doc.get_or_insert_map("r");
1830 let mut mgr = UndoManager::with_scope_and_options(&doc, &map, Options::default());
1831 mgr.include_origin(doc.client_id());
1832
1833 let s1 = map.insert(
1834 &mut doc.transact_mut_with(doc.client_id()),
1835 "s1",
1836 MapPrelim::default(),
1837 );
1838 mgr.reset();
1839
1840 let mut txn = doc.transact_mut_with(doc.client_id());
1841 let a = s1.insert(&mut txn, "a", ArrayPrelim::default());
1842 a.insert(&mut txn, 0, "a1");
1843 drop(txn);
1844 mgr.reset();
1845
1846 let mut txn = doc.transact_mut_with(doc.client_id());
1847 let b = s1.insert(&mut txn, "b", ArrayPrelim::default());
1848 b.insert(&mut txn, 0, "b1");
1849 drop(txn);
1850 mgr.reset();
1851
1852 b.insert(&mut doc.transact_mut_with(doc.client_id()), 1, "b2");
1853 mgr.reset();
1854
1855 a.insert(&mut doc.transact_mut_with(doc.client_id()), 1, "a3");
1856 mgr.reset();
1857
1858 a.insert(&mut doc.transact_mut_with(doc.client_id()), 2, "a4");
1859 mgr.reset();
1860
1861 a.insert(&mut doc.transact_mut_with(doc.client_id()), 3, "a5");
1862 mgr.reset();
1863
1864 let actual = map.to_json(&doc.transact());
1865 assert_eq!(
1866 actual,
1867 any!({"s1": {"a": ["a1", "a3", "a4", "a5"], "b": ["b1", "b2"]}})
1868 );
1869
1870 mgr.undo_blocking(); mgr.undo_blocking(); mgr.undo_blocking(); mgr.undo_blocking(); let actual = map.to_json(&doc.transact());
1875 assert_eq!(actual, any!({"s1": {"a": ["a1"], "b": ["b1"]}}));
1876
1877 mgr.redo_blocking();
1878 let actual = map.to_json(&doc.transact());
1879 assert_eq!(actual, any!({"s1": {"b": ["b1", "b2"], "a": ["a1"]}}));
1880
1881 mgr.redo_blocking();
1882 let actual = map.to_json(&doc.transact());
1883 assert_eq!(actual, any!({"s1": {"a": ["a1", "a3"], "b": ["b1", "b2"]}}));
1884
1885 mgr.redo_blocking();
1886 let actual = map.to_json(&doc.transact());
1887 assert_eq!(
1888 actual,
1889 any!({"s1": {"a": ["a1", "a3", "a4"], "b": ["b1", "b2"]}})
1890 );
1891
1892 mgr.redo_blocking();
1893 let actual = map.to_json(&doc.transact());
1894 assert_eq!(
1895 actual,
1896 any!({"s1": {"a": ["a1", "a3", "a4", "a5"], "b": ["b1", "b2"]}})
1897 );
1898 }
1899
1900 #[test]
1901 fn github_issue_345_part_2() {
1902 let d = Doc::new();
1904 let r = d.get_or_insert_map("r");
1905
1906 let s1 = r.insert(&mut d.transact_mut(), "s1", MapPrelim::default());
1907
1908 let mut mgr = UndoManager::with_scope_and_options(&d, &r, Options::default());
1909 {
1910 let mut txn = d.transact_mut();
1911 let b1 = s1.insert(&mut txn, "b1", MapPrelim::default());
1912 b1.insert(&mut txn, "f1", 11);
1913 }
1914 mgr.reset();
1915
1916 s1.remove(&mut d.transact_mut(), "b1");
1917 mgr.reset();
1918
1919 {
1920 let mut txn = d.transact_mut();
1921 let b1 = s1.insert(&mut txn, "b1", MapPrelim::default());
1922 b1.insert(&mut txn, "f1", 20);
1923 }
1924 mgr.reset();
1925
1926 let actual = r.to_json(&d.transact());
1927 assert_eq!(actual, any!({"s1": {"b1": {"f1": 20}}}));
1928
1929 mgr.undo_blocking();
1930 let actual = r.to_json(&d.transact());
1931 assert_eq!(actual, any!({"s1": {}}));
1932 assert!(mgr.can_undo(), "should be able to undo");
1933
1934 mgr.undo_blocking();
1935 let actual = r.to_json(&d.transact());
1936 assert_eq!(actual, any!({"s1": {"b1": {"f1": 11}}}));
1937 assert!(mgr.can_undo(), "should be able to undo to the init state");
1938 }
1939
1940 #[test]
1941 fn issue_371() {
1942 let doc = Doc::with_client_id(1);
1943
1944 let r = doc.get_or_insert_map("r");
1945 let s1 = r.insert(&mut doc.transact_mut(), "s1", MapPrelim::default()); let b1_arr = s1.insert(&mut doc.transact_mut(), "b1", ArrayPrelim::default()); let el1 = b1_arr.insert(&mut doc.transact_mut(), 0, MapPrelim::default()); el1.insert(&mut doc.transact_mut(), "f1", 8); el1.insert(&mut doc.transact_mut(), "f2", true); let mut mgr = UndoManager::with_scope_and_options(&doc, &r, Options::default());
1952 {
1953 let mut txn = doc.transact_mut();
1954 let el0 = b1_arr.insert(&mut txn, 0, MapPrelim::default()); el0.insert(&mut txn, "f1", 8); el0.insert(&mut txn, "f2", false); el1.insert(&mut txn, "f1", 13); el1.remove(&mut txn, "f2"); }
1961 mgr.reset();
1962
1963 el1.insert(&mut doc.transact_mut(), "f2", false); mgr.reset();
1965
1966 el1.insert(&mut doc.transact_mut(), "f2", true); mgr.reset();
1968
1969 mgr.undo_blocking(); assert_eq!(
1971 r.to_json(&doc.transact()),
1972 any!({ "s1": { "b1": [{ "f1": 8, "f2": false }, { "f1": 13, "f2": false }] } })
1973 );
1974 mgr.undo_blocking(); assert_eq!(
1976 r.to_json(&doc.transact()),
1977 any!({ "s1": { "b1": [{ "f1": 8, "f2": false }, { "f1": 13 }] } })
1978 );
1979 mgr.undo_blocking(); assert_eq!(
1981 r.to_json(&doc.transact()),
1982 any!({ "s1": { "b1": [{ "f1": 8, "f2": true }] } })
1983 );
1984 assert!(!mgr.undo_blocking()); }
1986
1987 #[test]
1988 fn issue_371_2() {
1989 let doc = Doc::with_client_id(1);
1990 let r = doc.get_or_insert_map("r");
1991 let s1 = r.insert(&mut doc.transact_mut(), "s1", MapPrelim::default()); s1.insert(&mut doc.transact_mut(), "f2", "AAA"); s1.insert(&mut doc.transact_mut(), "f1", false); let mut mgr = UndoManager::with_scope_and_options(&doc, &r, Options::default());
1996 s1.remove(&mut doc.transact_mut(), "f2"); mgr.reset();
1998
1999 s1.insert(&mut doc.transact_mut(), "f2", "C1"); mgr.reset();
2001
2002 s1.insert(&mut doc.transact_mut(), "f2", "C2"); mgr.reset();
2004
2005 mgr.undo_blocking(); assert_eq!(
2007 r.to_json(&doc.transact()),
2008 any!({ "s1": { "f1": false, "f2": "C1" } })
2009 );
2010 mgr.undo_blocking(); assert_eq!(r.to_json(&doc.transact()), any!({ "s1": { "f1": false } }));
2012 mgr.undo_blocking(); assert_eq!(
2014 r.to_json(&doc.transact()),
2015 any!({ "s1": { "f1": false, "f2": "AAA" } })
2016 );
2017 assert!(!mgr.undo_blocking()); }
2019
2020 #[test]
2021 fn issue_380() {
2022 let d = Doc::with_client_id(1);
2023 let r = d.get_or_insert_map("r"); let s1 = r.insert(&mut d.transact_mut(), "s1", MapPrelim::default()); let b1_arr = s1.insert(&mut d.transact_mut(), "b1", ArrayPrelim::default()); let b1_el1 = b1_arr.insert(&mut d.transact_mut(), 0, MapPrelim::default()); let b2_arr = b1_el1.insert(&mut d.transact_mut(), "b2", ArrayPrelim::default()); let b2_arr_nest = b2_arr.insert(&mut d.transact_mut(), 0, ArrayPrelim::default()); b2_arr_nest.insert(&mut d.transact_mut(), 0, 232291652); b2_arr_nest.insert(&mut d.transact_mut(), 1, -30); let mut mgr = UndoManager::with_scope_and_options(&d, &r, Options::default());
2034
2035 let mut txn = d.transact_mut();
2036 b2_arr_nest.remove(&mut txn, 1); b2_arr_nest.insert(&mut txn, 1, -5); drop(txn);
2040 mgr.reset();
2041
2042 let mut txn = d.transact_mut();
2043
2044 let b1_el0 = b1_arr.insert(&mut txn, 0, MapPrelim::default()); let b2_0_arr = b1_el0.insert(&mut txn, "b2", ArrayPrelim::default()); let b2_0_arr_nest = b2_0_arr.insert(&mut txn, 0, ArrayPrelim::default()); b2_0_arr_nest.insert(&mut txn, 0, 232291652); b2_0_arr_nest.insert(&mut txn, 1, -6); b1_arr.remove(&mut txn, 1); let b1_el1 = b1_arr.insert(&mut txn, 1, MapPrelim::default()); b1_el1.insert(&mut txn, "f2", "C1"); drop(txn);
2055 mgr.reset();
2056 assert_eq!(
2057 r.to_json(&d.transact()),
2058 any!({"s1":{"b1":[{"b2":[[232291652, -6]]}, {"f2":"C1"}]}})
2059 );
2060
2061 mgr.undo_blocking(); assert_eq!(
2063 r.to_json(&d.transact()),
2064 any!({"s1":{"b1":[{"b2":[[232291652, -5]]}]}})
2065 );
2066
2067 mgr.undo_blocking(); assert_eq!(
2069 r.to_json(&d.transact()),
2070 any!({"s1":{"b1":[{"b2":[[232291652, -30]]}]}})
2071 );
2072 }
2073}