1use xi_trace::trace_block;
20
21use std::collections::HashMap;
22use std::mem;
23
24use crate::edit_types::{BufferEvent, EventDomain};
25
26pub(crate) struct Recorder {
28 active_recording: Option<String>,
29 recording_buffer: Vec<EventDomain>,
30 recordings: HashMap<String, Recording>,
31}
32
33impl Recorder {
34 pub(crate) fn new() -> Recorder {
35 Recorder {
36 active_recording: None,
37 recording_buffer: Vec::new(),
38 recordings: HashMap::new(),
39 }
40 }
41
42 pub(crate) fn is_recording(&self) -> bool {
43 self.active_recording.is_some()
44 }
45
46 pub(crate) fn toggle_recording(&mut self, recording_name: Option<String>) {
59 let is_recording = self.is_recording();
60 let last_recording = self.active_recording.take();
61
62 match (is_recording, &last_recording, &recording_name) {
63 (true, Some(last_recording), None) => {
64 self.save_recording_buffer(last_recording.clone())
65 }
66 (true, Some(last_recording), Some(recording_name)) => {
67 if last_recording != recording_name {
68 self.recording_buffer.clear();
69 } else {
70 self.save_recording_buffer(last_recording.clone());
71 return;
72 }
73 }
74 _ => {}
75 }
76
77 mem::replace(&mut self.active_recording, recording_name);
78 }
79
80 pub(crate) fn record(&mut self, current_event: EventDomain) {
85 assert!(self.is_recording());
86
87 let recording_buffer = &mut self.recording_buffer;
88
89 if recording_buffer.last().is_none() {
90 recording_buffer.push(current_event);
91 return;
92 }
93
94 {
95 let last_event = recording_buffer.last_mut().unwrap();
96 if let (
97 EventDomain::Buffer(BufferEvent::Insert(old_characters)),
98 EventDomain::Buffer(BufferEvent::Insert(new_characters)),
99 ) = (last_event, ¤t_event)
100 {
101 old_characters.push_str(new_characters);
102 return;
103 }
104 }
105
106 recording_buffer.push(current_event);
107 }
108
109 pub(crate) fn play<F>(&self, recording_name: &str, action: F)
112 where
113 F: FnMut(&EventDomain) -> (),
114 {
115 let is_current_recording: bool = self
116 .active_recording
117 .as_ref()
118 .map_or(false, |current_recording| current_recording == recording_name);
119
120 if is_current_recording {
121 warn!("Cannot play recording while it's currently active!");
122 return;
123 }
124
125 self.recordings.get(recording_name).and_then(|recording| {
126 recording.play(action);
127 Some(())
128 });
129 }
130
131 pub(crate) fn clear(&mut self, recording_name: &str) {
133 self.recordings.remove(recording_name);
134 }
135
136 fn save_recording_buffer(&mut self, recording_name: String) {
142 let mut saw_undo = false;
143 let mut saw_redo = false;
144
145 let filtered: Vec<EventDomain> = self
147 .recording_buffer
148 .clone()
149 .into_iter()
150 .rev()
151 .filter(|event| {
152 if let EventDomain::Buffer(event) = event {
153 return match event {
154 BufferEvent::Undo => {
155 saw_undo = !saw_redo;
156 saw_redo = false;
157 false
158 }
159 BufferEvent::Redo => {
160 saw_redo = !saw_undo;
161 saw_undo = false;
162 false
163 }
164 _ => {
165 let ret = !saw_undo;
166 saw_undo = false;
167 saw_redo = false;
168 ret
169 }
170 };
171 }
172
173 true
174 })
175 .collect::<Vec<EventDomain>>()
176 .into_iter()
177 .rev()
178 .collect();
179
180 let current_recording = Recording::new(filtered);
181 self.recordings.insert(recording_name, current_recording);
182 self.recording_buffer.clear();
183 }
184}
185
186struct Recording {
187 events: Vec<EventDomain>,
188}
189
190impl Recording {
191 fn new(events: Vec<EventDomain>) -> Recording {
192 Recording { events }
193 }
194
195 fn play<F>(&self, action: F)
198 where
199 F: FnMut(&EventDomain) -> (),
200 {
201 let _guard = trace_block("Recording::play", &["core", "recording"]);
202 self.events.iter().for_each(action)
203 }
204}
205
206#[cfg(test)]
212mod tests {
213 use crate::edit_types::{BufferEvent, EventDomain};
214 use crate::recorder::Recorder;
215
216 #[test]
217 fn play_recording() {
218 let mut recorder = Recorder::new();
219
220 let recording_name = String::new();
221 let mut expected_events: Vec<EventDomain> = vec![
222 BufferEvent::Indent.into(),
223 BufferEvent::Outdent.into(),
224 BufferEvent::DuplicateLine.into(),
225 BufferEvent::Transpose.into(),
226 ];
227
228 recorder.toggle_recording(Some(recording_name.clone()));
229 for event in expected_events.iter().rev() {
230 recorder.record(event.clone());
231 }
232 recorder.toggle_recording(Some(recording_name.clone()));
233
234 recorder.play(&recording_name, |event| {
235 let expected_event = expected_events.pop();
237 assert!(expected_event.is_some());
238
239 assert_eq!(*event, expected_event.unwrap());
241 });
242
243 assert_eq!(expected_events.len(), 0);
245 }
246
247 #[test]
248 fn play_only_after_saved() {
249 let mut recorder = Recorder::new();
250
251 let recording_name = String::new();
252 let expected_events: Vec<EventDomain> = vec![
253 BufferEvent::Indent.into(),
254 BufferEvent::Outdent.into(),
255 BufferEvent::DuplicateLine.into(),
256 BufferEvent::Transpose.into(),
257 ];
258
259 recorder.toggle_recording(Some(recording_name.clone()));
260 for event in expected_events.iter().rev() {
261 recorder.record(event.clone());
262 }
263
264 recorder.play(&recording_name, |_| {
265 assert!(false);
267 });
268 }
269
270 #[test]
271 fn prevent_same_playback() {
272 let mut recorder = Recorder::new();
273
274 let recording_name = String::new();
275 let expected_events: Vec<EventDomain> = vec![
276 BufferEvent::Indent.into(),
277 BufferEvent::Outdent.into(),
278 BufferEvent::DuplicateLine.into(),
279 BufferEvent::Transpose.into(),
280 ];
281
282 recorder.toggle_recording(Some(recording_name.clone()));
283 for event in expected_events.iter().rev() {
284 recorder.record(event.clone());
285 }
286 recorder.toggle_recording(Some(recording_name.clone()));
287
288 recorder.toggle_recording(Some(recording_name.clone()));
289 recorder.play(&recording_name, |_| {
290 assert!(false);
292 });
293 }
294
295 #[test]
296 fn clear_recording() {
297 let mut recorder = Recorder::new();
298
299 let recording_name = String::new();
300
301 recorder.toggle_recording(Some(recording_name.clone()));
302 recorder.record(BufferEvent::Transpose.into());
303 recorder.record(BufferEvent::DuplicateLine.into());
304 recorder.record(BufferEvent::Outdent.into());
305 recorder.record(BufferEvent::Indent.into());
306 recorder.toggle_recording(Some(recording_name.clone()));
307
308 assert_eq!(recorder.recordings.get(&recording_name).unwrap().events.len(), 4);
309
310 recorder.clear(&recording_name);
311
312 assert!(recorder.recordings.get(&recording_name).is_none());
313 }
314
315 #[test]
316 fn multiple_recordings() {
317 let mut recorder = Recorder::new();
318
319 let recording_a = "a".to_string();
320 let recording_b = "b".to_string();
321
322 recorder.toggle_recording(Some(recording_a.clone()));
323 recorder.record(BufferEvent::Transpose.into());
324 recorder.record(BufferEvent::DuplicateLine.into());
325 recorder.toggle_recording(Some(recording_a.clone()));
326
327 recorder.toggle_recording(Some(recording_b.clone()));
328 recorder.record(BufferEvent::Outdent.into());
329 recorder.record(BufferEvent::Indent.into());
330 recorder.toggle_recording(Some(recording_b.clone()));
331
332 assert_eq!(
333 recorder.recordings.get(&recording_a).unwrap().events,
334 vec![BufferEvent::Transpose.into(), BufferEvent::DuplicateLine.into()]
335 );
336 assert_eq!(
337 recorder.recordings.get(&recording_b).unwrap().events,
338 vec![BufferEvent::Outdent.into(), BufferEvent::Indent.into()]
339 );
340
341 recorder.clear(&recording_a);
342
343 assert!(recorder.recordings.get(&recording_a).is_none());
344 assert!(recorder.recordings.get(&recording_b).is_some());
345 }
346
347 #[test]
348 fn text_playback() {
349 let mut recorder = Recorder::new();
350
351 let recording_name = String::new();
352
353 recorder.toggle_recording(Some(recording_name.clone()));
354 recorder.record(BufferEvent::Insert("Foo".to_owned()).into());
355 recorder.record(BufferEvent::Insert("B".to_owned()).into());
356 recorder.record(BufferEvent::Insert("A".to_owned()).into());
357 recorder.record(BufferEvent::Insert("R".to_owned()).into());
358
359 recorder.toggle_recording(Some(recording_name.clone()));
360 assert_eq!(
361 recorder.recordings.get(&recording_name).unwrap().events,
362 vec![BufferEvent::Insert("FooBAR".to_owned()).into()]
363 );
364 }
365
366 #[test]
367 fn basic_undo() {
368 let mut recorder = Recorder::new();
369
370 let recording_name = String::new();
371
372 recorder.toggle_recording(Some(recording_name.clone()));
375 recorder.record(BufferEvent::Transpose.into());
376 recorder.record(BufferEvent::Undo.into());
377 recorder.record(BufferEvent::DuplicateLine.into());
378 recorder.record(BufferEvent::Redo.into());
379 recorder.toggle_recording(Some(recording_name.clone()));
380 assert_eq!(
381 recorder.recordings.get(&recording_name).unwrap().events,
382 vec![BufferEvent::DuplicateLine.into()]
383 );
384 }
385
386 #[test]
387 fn basic_undo_swapped() {
388 let mut recorder = Recorder::new();
389
390 let recording_name = String::new();
391
392 recorder.toggle_recording(Some(recording_name.clone()));
395 recorder.record(BufferEvent::Transpose.into());
396 recorder.record(BufferEvent::Redo.into());
397 recorder.record(BufferEvent::DuplicateLine.into());
398 recorder.record(BufferEvent::Undo.into());
399 recorder.toggle_recording(Some(recording_name.clone()));
400 assert_eq!(
401 recorder.recordings.get(&recording_name).unwrap().events,
402 vec![BufferEvent::Transpose.into()]
403 );
404 }
405
406 #[test]
407 fn redo_cancels_undo() {
408 let mut recorder = Recorder::new();
409
410 let recording_name = String::new();
411
412 recorder.toggle_recording(Some(recording_name.clone()));
415 recorder.record(BufferEvent::Transpose.into());
416 recorder.record(BufferEvent::Undo.into());
417 recorder.record(BufferEvent::Redo.into());
418 recorder.record(BufferEvent::DuplicateLine.into());
419 recorder.toggle_recording(Some(recording_name.clone()));
420 assert_eq!(
421 recorder.recordings.get(&recording_name).unwrap().events,
422 vec![BufferEvent::Transpose.into(), BufferEvent::DuplicateLine.into()]
423 );
424 }
425
426 #[test]
427 fn undo_cancels_redo() {
428 let mut recorder = Recorder::new();
429
430 let recording_name = String::new();
431
432 recorder.toggle_recording(Some(recording_name.clone()));
435 recorder.record(BufferEvent::Transpose.into());
436 recorder.record(BufferEvent::Undo.into());
437 recorder.record(BufferEvent::Redo.into());
438 recorder.record(BufferEvent::Undo.into());
439 recorder.toggle_recording(Some(recording_name.clone()));
440 assert_eq!(recorder.recordings.get(&recording_name).unwrap().events, vec![]);
441 }
442
443 #[test]
444 fn undo_as_first_item() {
445 let mut recorder = Recorder::new();
446
447 let recording_name = String::new();
448
449 recorder.toggle_recording(Some(recording_name.clone()));
452 recorder.record(BufferEvent::Undo.into());
453 recorder.record(BufferEvent::Transpose.into());
454 recorder.record(BufferEvent::DuplicateLine.into());
455 recorder.record(BufferEvent::Redo.into());
456 recorder.toggle_recording(Some(recording_name.clone()));
457 assert_eq!(
458 recorder.recordings.get(&recording_name).unwrap().events,
459 vec![BufferEvent::Transpose.into(), BufferEvent::DuplicateLine.into()]
460 );
461 }
462
463 #[test]
464 fn redo_as_first_item() {
465 let mut recorder = Recorder::new();
466
467 let recording_name = String::new();
468
469 recorder.toggle_recording(Some(recording_name.clone()));
472 recorder.record(BufferEvent::Redo.into());
473 recorder.record(BufferEvent::Transpose.into());
474 recorder.record(BufferEvent::DuplicateLine.into());
475 recorder.record(BufferEvent::Undo.into());
476 recorder.toggle_recording(Some(recording_name.clone()));
477 assert_eq!(
478 recorder.recordings.get(&recording_name).unwrap().events,
479 vec![BufferEvent::Transpose.into()]
480 );
481 }
482}