Skip to main content

ui/
history.rs

1//! Bounded snapshot storage. Callers decide which edits form a group.
2
3use std::collections::VecDeque;
4
5pub struct SnapshotHistory<S> {
6    undo: VecDeque<S>,
7    redo: Vec<S>,
8    limit: usize,
9}
10
11impl<S> SnapshotHistory<S> {
12    pub fn new(limit: usize) -> Self {
13        Self {
14            undo: VecDeque::new(),
15            redo: Vec::new(),
16            limit,
17        }
18    }
19
20    pub fn set_limit(&mut self, limit: usize) {
21        self.limit = limit;
22        self.trim();
23        let excess = self.redo.len().saturating_sub(limit);
24        self.redo.drain(..excess);
25    }
26
27    pub fn clear(&mut self) {
28        self.undo.clear();
29        self.redo.clear();
30    }
31
32    pub fn can_undo(&self) -> bool {
33        !self.undo.is_empty()
34    }
35
36    /// Every edit discards redo. `None` continues the caller's current group.
37    pub fn record(&mut self, before: Option<S>) {
38        self.redo.clear();
39        if let Some(before) = before {
40            self.undo.push_back(before);
41            self.trim();
42        }
43    }
44
45    pub fn undo(&mut self, current: impl FnOnce() -> S) -> Option<S> {
46        let previous = self.undo.pop_back()?;
47        self.redo.push(current());
48        Some(previous)
49    }
50
51    pub fn redo(&mut self, current: impl FnOnce() -> S) -> Option<S> {
52        let next = self.redo.pop()?;
53        self.undo.push_back(current());
54        self.trim();
55        Some(next)
56    }
57
58    fn trim(&mut self) {
59        while self.undo.len() > self.limit {
60            self.undo.pop_front();
61        }
62    }
63}