interactive_parse/
undo.rs1use std::{
2 cell::Cell,
3 io::{stdout, Write},
4};
5
6use crossterm::{
7 cursor::MoveToPreviousLine,
8 queue,
9 terminal::{Clear, ClearType},
10};
11use log::debug;
12
13use crate::error::{SchemaError, SchemaResult};
14
15pub(crate) trait Undo {
16 type Output;
17 fn undo(self, current_depth: &Cell<u16>) -> SchemaResult<Self::Output>;
18}
19
20impl<T> Undo for Option<T> {
21 type Output = T;
22 fn undo(self, current_depth: &Cell<u16>) -> SchemaResult<Self::Output> {
23 let current_depth_val = current_depth.get();
24 match self {
25 Some(value) => {
26 debug!("Depth {} -> {}", current_depth_val, current_depth_val + 1);
27 current_depth.set(current_depth_val + 1);
28 Ok(value)
29 }
30 None => {
31 debug!("Undo at depth {}", current_depth_val);
32 Err(SchemaError::Undo {
33 depth: current_depth_val,
34 })
35 }
36 }
37 }
38}
39
40pub(crate) trait CatchUndo {
41 type Output;
42 fn catch_undo(self, current_depth: &Cell<u16>) -> SchemaResult<Self::Output>;
43}
44
45impl<T> CatchUndo for Result<T, SchemaError> {
46 type Output = T;
47 fn catch_undo(self, current_depth: &Cell<u16>) -> SchemaResult<Self::Output> {
48 let current_depth_val = current_depth.get();
49 match self {
50 Ok(value) => {
51 debug!("Depth {} -> {}", current_depth_val, current_depth_val + 1);
52 current_depth.set(current_depth_val + 1);
53 Ok(value)
54 }
55 Err(SchemaError::Undo { depth }) => {
56 debug!("Undo at depth {}", current_depth_val);
57 current_depth.set(depth);
58 Err(SchemaError::Undo { depth })
59 }
60 Err(err) => Err(err),
61 }
62 }
63}
64
65pub(crate) trait RecurseIter<T, U>
66where
67 Self: Iterator<Item = T> + Clone,
68 T: Clone,
69 U: Clone,
70{
71 fn recurse_iter<F: FnMut(T) -> SchemaResult<RecurseLoop<U>> + Clone>(
72 self,
73 current_depth: &Cell<u16>,
74 f: F,
75 ) -> SchemaResult<Vec<U>>;
76}
77
78impl<I, T, U> RecurseIter<T, U> for I
79where
80 I: Iterator<Item = T> + Clone,
81 T: Clone,
82 U: Clone,
83{
84 fn recurse_iter<F: FnMut(T) -> SchemaResult<RecurseLoop<U>> + Clone>(
85 self,
86 current_depth: &Cell<u16>,
87 f: F,
88 ) -> SchemaResult<Vec<U>> {
89 let mut acc = Vec::new();
90 recurse_loop(self, current_depth, &mut acc, f)?;
91 Ok(acc)
92 }
93}
94
95pub(crate) enum RecurseLoop<T> {
96 Continue(T),
97 Return(Option<T>),
98}
99
100pub(crate) fn recurse_loop<
101 I: Iterator<Item = T> + Clone,
102 T: Clone,
103 U: Clone,
104 F: Clone + FnMut(T) -> SchemaResult<RecurseLoop<U>>,
105>(
106 mut iter: I,
107 current_depth: &Cell<u16>,
108 acc: &mut Vec<U>,
109 mut f: F,
110) -> SchemaResult<()> {
111 let iter_checkpoint = iter.clone();
112 let acc_checkpoint = acc.clone();
113 let depth_checkpoint = current_depth.get();
114 let Some(item) = iter.next() else {
115 return Ok(());
116 };
117
118 let val = match f(item) {
119 Ok(RecurseLoop::Continue(item)) => {
120 acc.push(item);
121 recurse_loop(iter, current_depth, acc, f.clone())
122 }
123 Ok(RecurseLoop::Return(item)) => {
124 if let Some(item) = item {
125 acc.push(item);
126 }
127 Ok(())
128 }
129 Err(err) => Err(err),
130 };
131
132 match val {
133 Err(SchemaError::Undo { depth }) => {
134 if depth > depth_checkpoint {
135 current_depth.set(depth_checkpoint);
136 *acc = acc_checkpoint;
137 clear_lines(depth - depth_checkpoint + 1);
138 recurse_loop(iter_checkpoint, current_depth, acc, f)
139 } else {
140 Err(SchemaError::Undo { depth })
141 }
142 }
143 other => other,
144 }
145}
146
147pub(crate) fn clear_lines(n: u16) {
148 let mut stdout = stdout();
149 queue!(
150 stdout,
151 MoveToPreviousLine(n),
152 Clear(ClearType::FromCursorDown)
153 )
154 .unwrap();
155 stdout.flush().unwrap();
156}