Skip to main content

mathtex_editor_session/
undo.rs

1use std::collections::VecDeque;
2
3use mathtex_editor_core::Snapshot;
4
5/// Undo steps a [`crate::Session`] keeps unless the host sets another limit.
6pub const DEFAULT_UNDO_LIMIT: usize = 200;
7
8/// Bounded undo and redo history of editor snapshots, where any new step clears the redo side.
9#[derive(Debug, Clone)]
10pub struct UndoStack {
11    undo: VecDeque<Snapshot>,
12    redo: Vec<Snapshot>,
13    limit: usize,
14}
15
16impl Default for UndoStack {
17    fn default() -> Self {
18        Self::new(DEFAULT_UNDO_LIMIT)
19    }
20}
21
22impl UndoStack {
23    /// An empty history keeping at most `limit` undo steps, 0 keeps none.
24    pub fn new(limit: usize) -> Self {
25        Self { undo: VecDeque::new(), redo: Vec::new(), limit }
26    }
27
28    /// The most undo steps kept.
29    pub fn limit(&self) -> usize {
30        self.limit
31    }
32
33    /// Change the limit, dropping the oldest steps beyond it.
34    pub fn set_limit(&mut self, limit: usize) {
35        self.limit = limit;
36        self.trim();
37    }
38
39    /// Record the state before an edit and clear the redo side.
40    pub fn record(&mut self, before: Snapshot) {
41        self.redo.clear();
42        self.undo.push_back(before);
43        self.trim();
44    }
45
46    /// Step back: returns the state to restore and keeps `current` for redo.
47    pub fn undo(&mut self, current: Snapshot) -> Option<Snapshot> {
48        let target = self.undo.pop_back()?;
49        self.redo.push(current);
50        Some(target)
51    }
52
53    /// Step forward again: returns the state to restore and keeps `current` for undo.
54    pub fn redo(&mut self, current: Snapshot) -> Option<Snapshot> {
55        let target = self.redo.pop()?;
56        self.undo.push_back(current);
57        self.trim();
58        Some(target)
59    }
60
61    /// Whether there is a step to undo.
62    pub fn can_undo(&self) -> bool {
63        !self.undo.is_empty()
64    }
65
66    /// Whether there is a step to redo.
67    pub fn can_redo(&self) -> bool {
68        !self.redo.is_empty()
69    }
70
71    /// Drop every step.
72    pub fn clear(&mut self) {
73        self.undo.clear();
74        self.redo.clear();
75    }
76
77    /// Every kept snapshot, undo steps oldest first and then redo steps.
78    pub fn snapshots(&self) -> impl Iterator<Item = &Snapshot> {
79        self.undo.iter().chain(&self.redo)
80    }
81
82    fn trim(&mut self) {
83        while self.undo.len() > self.limit {
84            self.undo.pop_front();
85        }
86    }
87}