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