Skip to main content

escriba_buffer/
undo.rs

1//! Minimal undo tree — linear stack for phase 1; branching in phase 2.
2
3use escriba_core::Edit;
4
5/// One atomic edit (the thing Undo reverses) + the reverse edit to apply.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct UndoEntry {
8    pub applied: Edit,
9    pub reverse: Edit,
10}
11
12#[derive(Debug, Default, Clone)]
13pub struct UndoTree {
14    undo_stack: Vec<UndoEntry>,
15    redo_stack: Vec<UndoEntry>,
16}
17
18impl UndoTree {
19    #[must_use]
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    pub fn push(&mut self, entry: UndoEntry) {
25        self.undo_stack.push(entry);
26        self.redo_stack.clear();
27    }
28
29    #[must_use]
30    pub fn can_undo(&self) -> bool {
31        !self.undo_stack.is_empty()
32    }
33
34    #[must_use]
35    pub fn can_redo(&self) -> bool {
36        !self.redo_stack.is_empty()
37    }
38
39    pub fn pop_undo(&mut self) -> Option<UndoEntry> {
40        let e = self.undo_stack.pop()?;
41        self.redo_stack.push(e.clone());
42        Some(e)
43    }
44
45    pub fn pop_redo(&mut self) -> Option<UndoEntry> {
46        let e = self.redo_stack.pop()?;
47        self.undo_stack.push(e.clone());
48        Some(e)
49    }
50
51    #[must_use]
52    pub fn undo_len(&self) -> usize {
53        self.undo_stack.len()
54    }
55
56    #[must_use]
57    pub fn redo_len(&self) -> usize {
58        self.redo_stack.len()
59    }
60}