gpui_component/
history.rs1use std::{
2 fmt::Debug,
3 time::{Duration, Instant},
4};
5
6pub trait HistoryItem: Clone + PartialEq {
7 fn version(&self) -> usize;
8 fn set_version(&mut self, version: usize);
9}
10
11#[derive(Debug)]
22pub struct History<I: HistoryItem> {
23 undos: Vec<I>,
24 redos: Vec<I>,
25 last_changed_at: Instant,
26 version: usize,
27 pub(crate) ignore: bool,
28 max_undo: usize,
29 group_interval: Option<Duration>,
30 unique: bool,
31}
32
33impl<I> History<I>
34where
35 I: HistoryItem,
36{
37 pub fn new() -> Self {
38 Self {
39 undos: Default::default(),
40 redos: Default::default(),
41 ignore: false,
42 last_changed_at: Instant::now(),
43 version: 0,
44 max_undo: 1000,
45 group_interval: None,
46 unique: false,
47 }
48 }
49
50 pub fn max_undo(mut self, max_undo: usize) -> Self {
52 self.max_undo = max_undo;
53 self
54 }
55
56 pub fn unique(mut self) -> Self {
59 self.unique = true;
60 self
61 }
62
63 pub fn group_interval(mut self, group_interval: Duration) -> Self {
65 self.group_interval = Some(group_interval);
66 self
67 }
68
69 fn inc_version(&mut self) -> usize {
71 let t = Instant::now();
72 if Some(self.last_changed_at.elapsed()) > self.group_interval {
73 self.version += 1;
74 }
75
76 self.last_changed_at = t;
77 self.version
78 }
79
80 pub fn version(&self) -> usize {
82 self.version
83 }
84
85 pub fn push(&mut self, item: I) {
86 let version = self.inc_version();
87
88 if self.undos.len() >= self.max_undo {
89 self.undos.remove(0);
90 }
91
92 if self.unique {
93 self.undos.retain(|c| *c != item);
94 self.redos.retain(|c| *c != item);
95 }
96
97 let mut item = item;
98 item.set_version(version);
99 self.undos.push(item);
100 }
101
102 pub fn undos(&self) -> &Vec<I> {
104 &self.undos
105 }
106
107 pub fn redos(&self) -> &Vec<I> {
109 &self.redos
110 }
111
112 pub fn clear(&mut self) {
114 self.undos.clear();
115 self.redos.clear();
116 }
117
118 pub fn undo(&mut self) -> Option<Vec<I>> {
119 if let Some(first_change) = self.undos.pop() {
120 let mut changes = vec![first_change.clone()];
121 while self
123 .undos
124 .iter()
125 .filter(|c| c.version() == first_change.version())
126 .count()
127 > 0
128 {
129 let change = self.undos.pop().unwrap();
130 changes.push(change);
131 }
132
133 self.redos.extend(changes.clone());
134 Some(changes)
135 } else {
136 None
137 }
138 }
139
140 pub fn redo(&mut self) -> Option<Vec<I>> {
141 if let Some(first_change) = self.redos.pop() {
142 let mut changes = vec![first_change.clone()];
143 while self
145 .redos
146 .iter()
147 .filter(|c| c.version() == first_change.version())
148 .count()
149 > 0
150 {
151 let change = self.redos.pop().unwrap();
152 changes.push(change);
153 }
154 self.undos.extend(changes.clone());
155 Some(changes)
156 } else {
157 None
158 }
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[derive(Clone)]
167 struct TabIndex {
168 tab_index: usize,
169 version: usize,
170 }
171
172 impl PartialEq for TabIndex {
173 fn eq(&self, other: &Self) -> bool {
174 self.tab_index == other.tab_index
175 }
176 }
177
178 impl From<usize> for TabIndex {
179 fn from(value: usize) -> Self {
180 TabIndex {
181 tab_index: value,
182 version: 0,
183 }
184 }
185 }
186
187 impl HistoryItem for TabIndex {
188 fn version(&self) -> usize {
189 self.version
190 }
191 fn set_version(&mut self, version: usize) {
192 self.version = version;
193 }
194 }
195
196 #[test]
197 fn test_history() {
198 let mut history: History<TabIndex> = History::new().max_undo(100);
199 history.push(0.into());
200 history.push(3.into());
201 history.push(2.into());
202 history.push(1.into());
203
204 assert_eq!(history.version(), 4);
205 let changes = history.undo().unwrap();
206 assert_eq!(changes.len(), 1);
207 assert_eq!(changes[0].tab_index, 1);
208
209 let changes = history.undo().unwrap();
210 assert_eq!(changes.len(), 1);
211 assert_eq!(changes[0].tab_index, 2);
212
213 history.push(5.into());
214
215 let changes = history.redo().unwrap();
216 assert_eq!(changes[0].tab_index, 2);
217
218 let changes = history.redo().unwrap();
219 assert_eq!(changes[0].tab_index, 1);
220
221 let changes = history.undo().unwrap();
222 assert_eq!(changes[0].tab_index, 1);
223
224 let changes = history.undo().unwrap();
225 assert_eq!(changes[0].tab_index, 2);
226
227 let changes = history.undo().unwrap();
228 assert_eq!(changes[0].tab_index, 5);
229
230 let changes = history.undo().unwrap();
231 assert_eq!(changes[0].tab_index, 3);
232
233 let changes = history.undo().unwrap();
234 assert_eq!(changes[0].tab_index, 0);
235
236 assert_eq!(history.undo().is_none(), true);
237 }
238
239 #[test]
240 fn test_unique_history() {
241 let mut history: History<TabIndex> = History::new().max_undo(100).unique();
242
243 history.push(0.into());
245 history.push(1.into());
246 history.push(1.into()); history.push(2.into());
248 history.push(1.into()); assert_eq!(history.version(), 5);
252 assert_eq!(history.undos().len(), 3);
253 assert_eq!(history.undos().last().unwrap().tab_index, 1);
254
255 let changes = history.undo().unwrap();
257 assert_eq!(changes.len(), 1);
258 assert_eq!(changes[0].tab_index, 1);
259
260 assert_eq!(history.redos().len(), 1);
261 history.push(2.into());
263
264 assert_eq!(history.undos().len(), 2);
265 assert_eq!(history.redos().len(), 1);
266
267 let changes = history.redo().unwrap();
269 assert_eq!(changes.len(), 1);
270 assert_eq!(changes[0].tab_index, 1);
271
272 history.push(3.into());
274
275 assert_eq!(history.version(), 7);
277 assert_eq!(history.undos().len(), 4);
278
279 for _ in 0..4 {
281 history.undo();
282 }
283
284 assert_eq!(history.undos().len(), 0);
286 assert_eq!(history.redos().len(), 4);
287 }
288}