1use crate::Signal;
30use incular_text::{ComposingRange, TextEditingController, TextEditingValue, TextSelection};
31use std::{
32 cell::{Cell, RefCell},
33 rc::{Rc, Weak},
34};
35
36#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
38pub struct UndoHistoryState {
39 pub can_undo: bool,
40 pub can_redo: bool,
41}
42
43struct Step {
47 start: usize,
48 replaced: Box<str>,
49 inserted_len: usize,
50 selection: TextSelection,
51 composing: Option<ComposingRange>,
52}
53
54impl Step {
55 fn between(before: &TextEditingValue, after: &TextEditingValue) -> Self {
57 let (a, b) = (before.text.as_str(), after.text.as_str());
58 let mut prefix = a
59 .bytes()
60 .zip(b.bytes())
61 .take_while(|(left, right)| left == right)
62 .count();
63 while !(a.is_char_boundary(prefix) && b.is_char_boundary(prefix)) {
64 prefix -= 1;
65 }
66 let limit = a.len().min(b.len()) - prefix;
67 let mut suffix = a
68 .bytes()
69 .rev()
70 .zip(b.bytes().rev())
71 .take(limit)
72 .take_while(|(left, right)| left == right)
73 .count();
74 while !(a.is_char_boundary(a.len() - suffix) && b.is_char_boundary(b.len() - suffix)) {
75 suffix -= 1;
76 }
77 Self {
78 start: prefix,
79 replaced: a[prefix..a.len() - suffix].into(),
80 inserted_len: b.len() - suffix - prefix,
81 selection: before.selection,
82 composing: before.composing,
83 }
84 }
85
86 fn revert(&self, after: &TextEditingValue) -> TextEditingValue {
88 let text = &after.text;
89 let tail = &text[self.start + self.inserted_len..];
90 let mut out = String::with_capacity(self.start + self.replaced.len() + tail.len());
91 out.push_str(&text[..self.start]);
92 out.push_str(&self.replaced);
93 out.push_str(tail);
94 TextEditingValue {
95 text: out,
96 selection: self.selection,
97 composing: self.composing,
98 }
99 }
100}
101
102struct History {
103 current: TextEditingValue,
104 undo: Vec<Step>,
105 redo: Vec<Step>,
106 max_entries: usize,
107}
108
109impl History {
110 fn absorb(&mut self, value: TextEditingValue) {
114 if self.current.text != value.text {
115 for stack in [&mut self.undo, &mut self.redo] {
116 if let Some(top) = stack.last_mut() {
117 let target = top.revert(&self.current);
118 *top = Step::between(&target, &value);
119 }
120 }
121 }
122 self.current = value;
123 }
124}
125
126const DEFAULT_MAX_ENTRIES: usize = 100;
127
128fn trim_history(entries: &mut Vec<Step>, max_entries: usize) {
129 if entries.len() > max_entries {
130 let remove = entries.len() - max_entries;
131 entries.drain(..remove);
132 }
133}
134
135struct Inner {
136 editor: TextEditingController,
137 history: RefCell<History>,
138 applying: Cell<bool>,
139 restoration_generation: Cell<u64>,
140 state: Signal<UndoHistoryState>,
141 listener: usize,
142}
143
144impl Inner {
145 fn availability(&self) -> UndoHistoryState {
146 let history = self.history.borrow();
147 UndoHistoryState {
148 can_undo: !history.undo.is_empty(),
149 can_redo: !history.redo.is_empty(),
150 }
151 }
152
153 fn sync_state(&self) {
154 let _ = self.state.set(self.availability());
155 }
156
157 fn record(&self, value: TextEditingValue) {
158 let generation = self.editor.restoration_generation();
161 if generation != self.restoration_generation.get() {
162 self.restoration_generation.set(generation);
163 let mut history = self.history.borrow_mut();
164 history.current = value;
165 history.undo.clear();
166 history.redo.clear();
167 drop(history);
168 self.sync_state();
169 return;
170 }
171 if self.applying.get() {
172 self.history.borrow_mut().absorb(value);
173 return;
174 }
175
176 let changed = {
177 let mut history = self.history.borrow_mut();
178 if history.current == value {
179 false
180 } else if history.current.text == value.text {
181 history.current = value;
184 false
185 } else {
186 let previous = std::mem::replace(&mut history.current, value);
187 if history.max_entries > 0 {
188 let step = Step::between(&previous, &history.current);
189 history.undo.push(step);
190 let max_entries = history.max_entries;
191 trim_history(&mut history.undo, max_entries);
192 }
193 history.redo.clear();
194 true
195 }
196 };
197 if changed {
198 self.sync_state();
199 }
200 }
201
202 fn apply_history_value(&self, value: TextEditingValue) {
203 struct RestorePrevious<'a> {
204 inner: &'a Inner,
205 previous: bool,
206 }
207
208 impl Drop for RestorePrevious<'_> {
209 fn drop(&mut self) {
210 let value = self.inner.editor.value();
211 self.inner.history.borrow_mut().absorb(value);
212 self.inner.applying.set(self.previous);
213 if !std::thread::panicking() {
214 self.inner.sync_state();
215 }
216 }
217 }
218
219 let previous = self.applying.replace(true);
220 let _guard = RestorePrevious {
221 inner: self,
222 previous,
223 };
224 self.editor.set_value(value);
225 }
226}
227
228impl Drop for Inner {
229 fn drop(&mut self) {
230 self.editor.remove_listener(self.listener);
231 }
232}
233
234#[derive(Clone)]
236pub struct UndoHistoryController {
237 inner: Rc<Inner>,
238}
239
240impl std::fmt::Debug for UndoHistoryController {
241 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 formatter
243 .debug_struct("UndoHistoryController")
244 .field("editor", &self.inner.editor)
245 .field("state", &self.status())
246 .finish()
247 }
248}
249
250impl UndoHistoryController {
251 #[must_use]
254 pub fn new(editor: TextEditingController) -> Self {
255 let initial = editor.value();
256 let inner = Rc::new_cyclic(|weak: &Weak<Inner>| {
257 let listener = {
258 let weak = weak.clone();
259 editor.add_listener(move |_| {
260 if let Some(inner) = weak.upgrade() {
261 inner.record(inner.editor.value());
262 }
263 })
264 };
265 Inner {
266 editor: editor.clone(),
267 history: RefCell::new(History {
268 current: initial.clone(),
269 undo: Vec::new(),
270 redo: Vec::new(),
271 max_entries: DEFAULT_MAX_ENTRIES,
272 }),
273 applying: Cell::new(false),
274 restoration_generation: Cell::new(editor.restoration_generation()),
275 state: Signal::new(UndoHistoryState::default()),
276 listener,
277 }
278 });
279 Self { inner }
280 }
281
282 #[must_use]
283 pub fn editor(&self) -> TextEditingController {
284 self.inner.editor.clone()
285 }
286
287 #[must_use]
289 pub fn state_signal(&self) -> Signal<UndoHistoryState> {
290 self.inner.state.clone()
291 }
292
293 #[must_use]
295 pub fn signal(&self) -> Signal<UndoHistoryState> {
296 self.state_signal()
297 }
298
299 #[must_use]
300 pub fn status(&self) -> UndoHistoryState {
301 self.inner.state.get()
302 }
303
304 #[must_use]
305 pub fn can_undo(&self) -> bool {
306 self.status().can_undo
307 }
308
309 #[must_use]
310 pub fn can_redo(&self) -> bool {
311 self.status().can_redo
312 }
313
314 pub fn set_max_entries(&self, max_entries: usize) {
318 let mut history = self.inner.history.borrow_mut();
319 history.max_entries = max_entries;
320 trim_history(&mut history.undo, max_entries);
321 trim_history(&mut history.redo, max_entries);
322 drop(history);
323 self.inner.sync_state();
324 }
325
326 #[must_use]
327 pub fn max_entries(&self) -> usize {
328 self.inner.history.borrow().max_entries
329 }
330
331 #[must_use]
333 pub fn undo(&self) -> bool {
334 let target = {
335 let mut history = self.inner.history.borrow_mut();
336 let Some(step) = history.undo.pop() else {
337 return false;
338 };
339 let target = step.revert(&history.current);
340 let current = std::mem::replace(&mut history.current, target.clone());
341 if history.max_entries > 0 {
342 history.redo.push(Step::between(¤t, &target));
343 let max_entries = history.max_entries;
344 trim_history(&mut history.redo, max_entries);
345 }
346 target
347 };
348 self.inner.apply_history_value(target);
349 true
350 }
351
352 #[must_use]
354 pub fn redo(&self) -> bool {
355 let target = {
356 let mut history = self.inner.history.borrow_mut();
357 let Some(step) = history.redo.pop() else {
358 return false;
359 };
360 let target = step.revert(&history.current);
361 let current = std::mem::replace(&mut history.current, target.clone());
362 if history.max_entries > 0 {
363 history.undo.push(Step::between(¤t, &target));
364 let max_entries = history.max_entries;
365 trim_history(&mut history.undo, max_entries);
366 }
367 target
368 };
369 self.inner.apply_history_value(target);
370 true
371 }
372
373 pub fn clear(&self) {
375 let mut history = self.inner.history.borrow_mut();
376 history.current = self.inner.editor.value();
377 history.undo.clear();
378 history.redo.clear();
379 drop(history);
380 self.inner.sync_state();
381 }
382}