reedline/core_editor/
edit_stack.rs

1#[derive(Debug, PartialEq, Eq)]
2pub struct EditStack<T> {
3    internal_list: Vec<T>,
4    index: usize,
5}
6
7impl<T> EditStack<T> {
8    pub fn new() -> Self
9    where
10        T: Default,
11    {
12        EditStack {
13            internal_list: vec![T::default()],
14            index: 0,
15        }
16    }
17}
18
19impl<T> EditStack<T>
20where
21    T: Default + Clone + Send,
22{
23    /// Go back one point in the undo stack. If present on first edit do nothing
24    pub(super) fn undo(&mut self) -> &T {
25        self.index = if self.index == 0 { 0 } else { self.index - 1 };
26        &self.internal_list[self.index]
27    }
28
29    /// Go forward one point in the undo stack. If present on the last edit do nothing
30    pub(super) fn redo(&mut self) -> &T {
31        self.index = if self.index == self.internal_list.len() - 1 {
32            self.index
33        } else {
34            self.index + 1
35        };
36        &self.internal_list[self.index]
37    }
38
39    /// Insert a new entry to the undo stack.
40    /// NOTE: (IMP): If we have hit undo a few times then discard all the other values that come
41    /// after the current point
42    pub(super) fn insert(&mut self, value: T) {
43        if self.index < self.internal_list.len() - 1 {
44            self.internal_list.resize_with(self.index + 1, || {
45                panic!("Impossible state reached: Bug in UndoStack logic")
46            });
47        }
48        self.internal_list.push(value);
49        self.index += 1;
50    }
51
52    /// Reset the stack to the initial state
53    pub(super) fn reset(&mut self) {
54        self.index = 0;
55        self.internal_list = vec![T::default()];
56    }
57
58    /// Return the entry currently being pointed to
59    pub(super) fn current(&mut self) -> &T {
60        &self.internal_list[self.index]
61    }
62}
63
64#[cfg(test)]
65mod test {
66    use super::*;
67    use pretty_assertions::assert_eq;
68    use rstest::rstest;
69
70    fn edit_stack<T>(values: &[T], index: usize) -> EditStack<T>
71    where
72        T: Clone,
73    {
74        EditStack {
75            internal_list: values.to_vec(),
76            index,
77        }
78    }
79
80    #[rstest]
81    #[case(edit_stack(&[1, 2, 3][..], 2), 2)]
82    #[case(edit_stack(&[1][..], 0), 1)]
83    fn undo_works(#[case] stack: EditStack<isize>, #[case] value_after_undo: isize) {
84        let mut stack = stack;
85
86        let value = stack.undo();
87        assert_eq!(*value, value_after_undo);
88    }
89
90    #[rstest]
91    #[case(edit_stack(&[1, 2, 3][..], 1), 3)]
92    #[case(edit_stack(&[1][..], 0), 1)]
93    fn redo_works(#[case] stack: EditStack<isize>, #[case] value_after_undo: isize) {
94        let mut stack = stack;
95
96        let value = stack.redo();
97        assert_eq!(*value, value_after_undo);
98    }
99
100    #[rstest]
101    #[case(edit_stack(&[1, 2, 3][..], 1), 4, edit_stack(&[1, 2, 4], 2))]
102    #[case(edit_stack(&[1, 2, 3][..], 2), 3, edit_stack(&[1, 2, 3, 3], 3))]
103    fn insert_works(
104        #[case] old_stack: EditStack<isize>,
105        #[case] value_to_insert: isize,
106        #[case] expected_stack: EditStack<isize>,
107    ) {
108        let mut stack = old_stack;
109
110        stack.insert(value_to_insert);
111        assert_eq!(stack, expected_stack);
112    }
113}