1use std::sync::{Arc, Mutex};
2
3use loro::{LoroResult, PeerID};
4
5use crate::{Cursor, DiffEvent, LoroDoc, LoroValue, Side};
6
7pub struct UndoManager(Mutex<loro::UndoManager>);
8
9impl UndoManager {
10 pub fn new(doc: &LoroDoc) -> Self {
12 Self(Mutex::new(loro::UndoManager::new(doc)))
13 }
14
15 pub fn undo(&self) -> LoroResult<bool> {
17 self.0.lock().unwrap().undo()
18 }
19
20 pub fn redo(&self) -> LoroResult<bool> {
22 self.0.lock().unwrap().redo()
23 }
24
25 pub fn record_new_checkpoint(&self) -> LoroResult<()> {
27 self.0.lock().unwrap().record_new_checkpoint()
28 }
29
30 pub fn can_undo(&self) -> bool {
32 self.0.lock().unwrap().can_undo()
33 }
34
35 pub fn can_redo(&self) -> bool {
37 self.0.lock().unwrap().can_redo()
38 }
39
40 pub fn undo_count(&self) -> u32 {
42 self.0.lock().unwrap().undo_count() as u32
43 }
44
45 pub fn redo_count(&self) -> u32 {
47 self.0.lock().unwrap().redo_count() as u32
48 }
49
50 pub fn add_exclude_origin_prefix(&self, prefix: &str) {
53 self.0.lock().unwrap().add_exclude_origin_prefix(prefix)
54 }
55
56 pub fn set_max_undo_steps(&self, size: u32) {
58 self.0.lock().unwrap().set_max_undo_steps(size as usize)
59 }
60
61 pub fn set_merge_interval(&self, interval: i64) {
63 self.0.lock().unwrap().set_merge_interval(interval)
64 }
65
66 pub fn set_on_push(&self, on_push: Option<Arc<dyn OnPush>>) {
69 if let Some(on_push) = on_push {
70 self.0
71 .lock()
72 .unwrap()
73 .set_on_push(Some(Box::new(move |u, c, e| {
74 loro::UndoItemMeta::from(on_push.on_push(u, c, e.map(|x| x.into())))
75 })));
76 } else {
77 self.0.lock().unwrap().set_on_push(None);
78 }
79 }
80
81 pub fn set_on_pop(&self, on_pop: Option<Arc<dyn OnPop>>) {
84 if let Some(on_pop) = on_pop {
85 self.0
86 .lock()
87 .unwrap()
88 .set_on_pop(Some(Box::new(move |u, c, m| {
89 on_pop.on_pop(u, c, UndoItemMeta::from(m))
90 })));
91 } else {
92 self.0.lock().unwrap().set_on_pop(None);
93 }
94 }
95
96 pub fn group_start(&self) -> LoroResult<()> {
97 self.0.lock().unwrap().group_start()
98 }
99
100 pub fn group_end(&self) {
101 self.0.lock().unwrap().group_end()
102 }
103
104 pub fn peer(&self) -> PeerID {
105 self.0.lock().unwrap().peer()
106 }
107
108 pub fn top_undo_meta(&self) -> Option<UndoItemMeta> {
109 self.0
110 .lock()
111 .unwrap()
112 .top_undo_meta()
113 .map(UndoItemMeta::from)
114 }
115
116 pub fn top_redo_meta(&self) -> Option<UndoItemMeta> {
117 self.0
118 .lock()
119 .unwrap()
120 .top_redo_meta()
121 .map(UndoItemMeta::from)
122 }
123
124 pub fn top_undo_value(&self) -> Option<LoroValue> {
125 self.0.lock().unwrap().top_undo_value().map(Into::into)
126 }
127
128 pub fn top_redo_value(&self) -> Option<LoroValue> {
129 self.0.lock().unwrap().top_redo_value().map(Into::into)
130 }
131}
132
133pub trait OnPush: Send + Sync {
134 fn on_push(
135 &self,
136 undo_or_redo: loro::UndoOrRedo,
137 counter_span: loro::CounterSpan,
138 diff_event: Option<DiffEvent>,
139 ) -> UndoItemMeta;
140}
141
142pub trait OnPop: Send + Sync {
143 fn on_pop(
144 &self,
145 undo_or_redo: loro::undo::UndoOrRedo,
146 counter_span: loro::CounterSpan,
147 undo_meta: UndoItemMeta,
148 );
149}
150
151#[derive(Debug, Clone)]
152pub struct UndoItemMeta {
153 pub value: LoroValue,
154 pub cursors: Vec<CursorWithPos>,
155}
156
157impl From<loro::undo::UndoItemMeta> for UndoItemMeta {
158 fn from(meta: loro::undo::UndoItemMeta) -> Self {
159 Self {
160 value: meta.value.into(),
161 cursors: meta
162 .cursors
163 .into_iter()
164 .map(|c| CursorWithPos {
165 cursor: Arc::new(c.cursor.into()),
166 pos: AbsolutePosition {
167 pos: c.pos.pos as u32,
168 side: c.pos.side,
169 },
170 })
171 .collect(),
172 }
173 }
174}
175
176impl From<&UndoItemMeta> for loro::undo::UndoItemMeta {
177 fn from(meta: &UndoItemMeta) -> Self {
178 loro::undo::UndoItemMeta {
179 value: (&meta.value).into(),
180 cursors: meta
181 .cursors
182 .iter()
183 .map(|c| loro::undo::CursorWithPos {
184 cursor: c.cursor.as_ref().clone().into(),
185 pos: loro::cursor::AbsolutePosition {
186 pos: c.pos.pos as usize,
187 side: c.pos.side,
188 },
189 })
190 .collect(),
191 }
192 }
193}
194
195impl From<UndoItemMeta> for loro::undo::UndoItemMeta {
196 fn from(meta: UndoItemMeta) -> Self {
197 loro::undo::UndoItemMeta {
198 value: (meta.value).into(),
199 cursors: meta
200 .cursors
201 .into_iter()
202 .map(|c| loro::undo::CursorWithPos {
203 cursor: c.cursor.as_ref().clone().into(),
204 pos: loro::cursor::AbsolutePosition {
205 pos: c.pos.pos as usize,
206 side: c.pos.side,
207 },
208 })
209 .collect(),
210 }
211 }
212}
213
214#[derive(Debug, Clone)]
215pub struct CursorWithPos {
216 pub cursor: Arc<Cursor>,
217 pub pos: AbsolutePosition,
218}
219
220#[derive(Debug, Clone, Copy)]
221pub struct AbsolutePosition {
222 pub pos: u32,
223 pub side: Side,
224}