1use crate::SheetId;
8use crate::engine::DependencyGraph;
9use crate::engine::graph::editor::change_log::ChangeEvent;
10use crate::engine::graph::editor::vertex_editor::{EditorError, VertexEditor};
11use formualizer_common::LiteralValue;
12
13#[derive(Debug, Clone, PartialEq)]
14pub enum ArrowOp {
15 SetDeltaCell {
16 sheet_id: SheetId,
17 row0: u32,
18 col0: u32,
19 old: Option<LiteralValue>,
20 new: Option<LiteralValue>,
21 },
22 SetComputedCell {
23 sheet_id: SheetId,
24 row0: u32,
25 col0: u32,
26 old: Option<LiteralValue>,
27 new: Option<LiteralValue>,
28 },
29 RestoreComputedRect {
30 sheet_id: SheetId,
31 sr0: u32,
32 sc0: u32,
33 er0: u32,
34 ec0: u32,
35 old: Vec<Vec<LiteralValue>>,
36 new: Vec<Vec<LiteralValue>>,
37 },
38 InsertRows {
39 sheet_id: SheetId,
40 before0: u32,
41 count: u32,
42 },
43 InsertCols {
44 sheet_id: SheetId,
45 before0: u32,
46 count: u32,
47 },
48}
49
50#[derive(Debug, Clone, Default, PartialEq)]
51pub struct ArrowUndoBatch {
52 pub ops: Vec<ArrowOp>,
53}
54
55impl ArrowUndoBatch {
56 #[inline]
57 pub fn is_empty(&self) -> bool {
58 self.ops.is_empty()
59 }
60
61 #[inline]
62 pub fn record_delta_cell(
63 &mut self,
64 sheet_id: SheetId,
65 row0: u32,
66 col0: u32,
67 old: Option<LiteralValue>,
68 new: Option<LiteralValue>,
69 ) {
70 if old == new {
71 return;
72 }
73 self.ops.push(ArrowOp::SetDeltaCell {
74 sheet_id,
75 row0,
76 col0,
77 old,
78 new,
79 });
80 }
81
82 #[inline]
83 pub fn record_computed_cell(
84 &mut self,
85 sheet_id: SheetId,
86 row0: u32,
87 col0: u32,
88 old: Option<LiteralValue>,
89 new: Option<LiteralValue>,
90 ) {
91 if old == new {
92 return;
93 }
94 self.ops.push(ArrowOp::SetComputedCell {
95 sheet_id,
96 row0,
97 col0,
98 old,
99 new,
100 });
101 }
102
103 #[inline]
104 pub fn record_restore_computed_rect(
105 &mut self,
106 sheet_id: SheetId,
107 sr0: u32,
108 sc0: u32,
109 er0: u32,
110 ec0: u32,
111 old: Vec<Vec<LiteralValue>>,
112 new: Vec<Vec<LiteralValue>>,
113 ) {
114 if old == new {
115 return;
116 }
117 self.ops.push(ArrowOp::RestoreComputedRect {
118 sheet_id,
119 sr0,
120 sc0,
121 er0,
122 ec0,
123 old,
124 new,
125 });
126 }
127
128 #[inline]
129 pub fn record_insert_rows(&mut self, sheet_id: SheetId, before0: u32, count: u32) {
130 if count == 0 {
131 return;
132 }
133 self.ops.push(ArrowOp::InsertRows {
134 sheet_id,
135 before0,
136 count,
137 });
138 }
139
140 #[inline]
141 pub fn record_insert_cols(&mut self, sheet_id: SheetId, before0: u32, count: u32) {
142 if count == 0 {
143 return;
144 }
145 self.ops.push(ArrowOp::InsertCols {
146 sheet_id,
147 before0,
148 count,
149 });
150 }
151}
152
153#[derive(Debug, Clone, Default, PartialEq)]
154pub struct GraphUndoBatch {
155 pub events: Vec<ChangeEvent>,
156}
157
158impl GraphUndoBatch {
159 #[inline]
160 pub fn is_empty(&self) -> bool {
161 self.events.is_empty()
162 }
163
164 pub fn undo(&self, graph: &mut DependencyGraph) -> Result<(), EditorError> {
165 let mut editor = VertexEditor::new(graph);
166 let mut compound_stack: Vec<usize> = Vec::new();
167 for ev in self.events.iter().rev() {
168 match ev {
169 ChangeEvent::CompoundEnd { depth } => compound_stack.push(*depth),
170 ChangeEvent::CompoundStart { depth, .. } => {
171 if compound_stack.last() == Some(depth) {
172 compound_stack.pop();
173 }
174 }
175 _ => {
176 editor.apply_inverse(ev.clone())?;
177 }
178 }
179 }
180 Ok(())
181 }
182
183 pub fn redo(&self, graph: &mut DependencyGraph) -> Result<(), EditorError> {
184 for ev in &self.events {
185 apply_forward_change_event(graph, ev)?;
186 }
187 Ok(())
188 }
189}
190
191fn apply_forward_change_event(
192 graph: &mut DependencyGraph,
193 ev: &ChangeEvent,
194) -> Result<(), EditorError> {
195 use crate::engine::graph::editor::vertex_editor::VertexMeta;
196 match ev {
197 ChangeEvent::SetValue { addr, new, .. } => {
198 let mut editor = VertexEditor::new(graph);
199 editor.set_cell_value(*addr, new.clone());
200 }
201 ChangeEvent::SetFormula { addr, new, .. } => {
202 let mut editor = VertexEditor::new(graph);
203 editor.set_cell_formula(*addr, new.clone());
204 }
205 ChangeEvent::SetRowVisibility { .. } => {
206 }
208 ChangeEvent::AddVertex {
209 coord,
210 sheet_id,
211 kind,
212 ..
213 } => {
214 let mut editor = VertexEditor::new(graph);
215 let meta = VertexMeta::new(
216 coord.row(),
217 coord.col(),
218 *sheet_id,
219 kind.unwrap_or(crate::engine::vertex::VertexKind::Cell),
220 );
221 editor.add_vertex(meta);
222 }
223 ChangeEvent::RemoveVertex {
224 coord, sheet_id, ..
225 } => {
226 if let (Some(c), Some(sid)) = (coord, sheet_id) {
227 let mut editor = VertexEditor::new(graph);
228 let cell_ref = crate::reference::CellRef::new(
229 *sid,
230 crate::reference::Coord::new(c.row(), c.col(), true, true),
231 );
232 let _ = editor.remove_vertex_at(cell_ref);
233 }
234 }
235 ChangeEvent::VertexMoved { id, new_coord, .. } => {
236 let mut editor = VertexEditor::new(graph);
237 let _ = editor.move_vertex(*id, *new_coord);
238 }
239 ChangeEvent::FormulaAdjusted { id, new_ast, .. } => {
240 let _ = graph.update_vertex_formula(*id, new_ast.clone());
241 graph.mark_vertex_dirty(*id);
242 }
243 ChangeEvent::DefineName {
244 name,
245 scope,
246 definition,
247 } => {
248 let mut editor = VertexEditor::new(graph);
249 let _ = editor.define_name(name, definition.clone(), *scope);
250 }
251 ChangeEvent::UpdateName {
252 name,
253 scope,
254 new_definition,
255 ..
256 } => {
257 let mut editor = VertexEditor::new(graph);
258 let _ = editor.update_name(name, new_definition.clone(), *scope);
259 }
260 ChangeEvent::DeleteName { name, scope, .. } => {
261 let mut editor = VertexEditor::new(graph);
262 let _ = editor.delete_name(name, *scope);
263 }
264 ChangeEvent::NamedRangeAdjusted {
265 name,
266 scope,
267 new_definition,
268 ..
269 } => {
270 let mut editor = VertexEditor::new(graph);
271 let _ = editor.update_name(name, new_definition.clone(), *scope);
272 }
273 ChangeEvent::SpillCommitted { anchor, new, .. } => {
274 let _ = graph.commit_spill_region_atomic_with_fault(
275 *anchor,
276 new.target_cells.clone(),
277 new.values.clone(),
278 None,
279 );
280 }
281 ChangeEvent::SpillCleared { anchor, .. } => {
282 graph.clear_spill_region(*anchor);
283 }
284 ChangeEvent::EdgeAdded { from, to } => {
285 let mut editor = VertexEditor::new(graph);
286 let _ = editor.add_edge(*from, *to);
287 }
288 ChangeEvent::EdgeRemoved { from, to } => {
289 let mut editor = VertexEditor::new(graph);
290 let _ = editor.remove_edge(*from, *to);
291 }
292 ChangeEvent::CompoundStart { .. }
293 | ChangeEvent::CompoundEnd { .. }
294 | ChangeEvent::StagedFormulaCellChanged { .. } => {}
295 }
296 Ok(())
297}
298
299#[derive(Debug, Clone, Default, PartialEq)]
300pub struct ActionJournal {
301 pub name: String,
302 pub graph: GraphUndoBatch,
303 pub arrow: ArrowUndoBatch,
304 pub affected_cells: usize,
305}