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