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
133#[uniffi::trait_interface]
134pub trait OnPush: Send + Sync {
135 fn on_push(
136 &self,
137 undo_or_redo: loro::UndoOrRedo,
138 counter_span: loro::CounterSpan,
139 diff_event: Option<DiffEvent>,
140 ) -> UndoItemMeta;
141}
142
143#[uniffi::trait_interface]
144pub trait OnPop: Send + Sync {
145 fn on_pop(
146 &self,
147 undo_or_redo: loro::undo::UndoOrRedo,
148 counter_span: loro::CounterSpan,
149 undo_meta: UndoItemMeta,
150 );
151}
152
153#[derive(Debug, Clone)]
154pub struct UndoItemMeta {
155 pub value: LoroValue,
156 pub cursors: Vec<CursorWithPos>,
157}
158
159impl From<loro::undo::UndoItemMeta> for UndoItemMeta {
160 fn from(meta: loro::undo::UndoItemMeta) -> Self {
161 Self {
162 value: meta.value.into(),
163 cursors: meta
164 .cursors
165 .into_iter()
166 .map(|c| CursorWithPos {
167 cursor: Arc::new(c.cursor.into()),
168 pos: AbsolutePosition {
169 pos: c.pos.pos as u32,
170 side: c.pos.side,
171 },
172 })
173 .collect(),
174 }
175 }
176}
177
178impl From<&UndoItemMeta> for loro::undo::UndoItemMeta {
179 fn from(meta: &UndoItemMeta) -> Self {
180 loro::undo::UndoItemMeta {
181 value: (&meta.value).into(),
182 cursors: meta
183 .cursors
184 .iter()
185 .map(|c| loro::undo::CursorWithPos {
186 cursor: c.cursor.as_ref().clone().into(),
187 pos: loro::cursor::AbsolutePosition {
188 pos: c.pos.pos as usize,
189 side: c.pos.side,
190 },
191 })
192 .collect(),
193 }
194 }
195}
196
197impl From<UndoItemMeta> for loro::undo::UndoItemMeta {
198 fn from(meta: UndoItemMeta) -> Self {
199 loro::undo::UndoItemMeta {
200 value: (meta.value).into(),
201 cursors: meta
202 .cursors
203 .into_iter()
204 .map(|c| loro::undo::CursorWithPos {
205 cursor: c.cursor.as_ref().clone().into(),
206 pos: loro::cursor::AbsolutePosition {
207 pos: c.pos.pos as usize,
208 side: c.pos.side,
209 },
210 })
211 .collect(),
212 }
213 }
214}
215
216#[derive(Debug, Clone)]
217pub struct CursorWithPos {
218 pub cursor: Arc<Cursor>,
219 pub pos: AbsolutePosition,
220}
221
222#[derive(Debug, Clone, Copy)]
223pub struct AbsolutePosition {
224 pub pos: u32,
225 pub side: Side,
226}