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 graph.authority_set_replay(crate::engine::authority::history::Replay::Undo);
166 let replayed = self.undo_events(graph);
167 graph.authority_set_replay(crate::engine::authority::history::Replay::Forward);
168 replayed
169 }
170
171 fn undo_events(&self, graph: &mut DependencyGraph) -> Result<(), EditorError> {
172 let mut editor = VertexEditor::new(graph);
173 let mut compound_stack: Vec<usize> = Vec::new();
174 for (i, ev) in self.events.iter().enumerate().rev() {
175 match ev {
176 ChangeEvent::CompoundEnd { depth } => {
177 compound_stack.push(*depth);
178 if let Some(description) =
179 crate::engine::graph::editor::change_log::compound_start_description(
180 i,
181 |j| &self.events[j],
182 )
183 {
184 editor.inverse_compound_end(description);
185 }
186 }
187 ChangeEvent::CompoundStart { depth, .. } => {
188 if compound_stack.last() == Some(depth) {
189 compound_stack.pop();
190 }
191 editor.apply_inverse(ev.clone())?;
192 }
193 _ => {
194 editor.apply_inverse(ev.clone())?;
195 }
196 }
197 }
198 Ok(())
199 }
200
201 pub fn redo(&self, graph: &mut DependencyGraph) -> Result<(), EditorError> {
202 graph.authority_set_replay(crate::engine::authority::history::Replay::Redo);
203 let replayed = self
204 .events
205 .iter()
206 .try_for_each(|ev| apply_forward_change_event(graph, ev));
207 graph.authority_set_replay(crate::engine::authority::history::Replay::Forward);
208 replayed
209 }
210}
211
212fn apply_forward_change_event(
213 graph: &mut DependencyGraph,
214 ev: &ChangeEvent,
215) -> Result<(), EditorError> {
216 use crate::engine::graph::editor::vertex_editor::VertexMeta;
217 match ev {
218 ChangeEvent::SetValue { addr, new, .. } => {
219 let mut editor = VertexEditor::new(graph);
220 editor.set_cell_value(*addr, new.clone());
221 }
222 ChangeEvent::SetFormula { addr, new, .. } => {
223 let mut editor = VertexEditor::new(graph);
224 editor.set_cell_formula(*addr, new.clone());
225 }
226 ChangeEvent::SetRowVisibility { .. } => {
227 }
229 ChangeEvent::AddVertex {
230 coord,
231 sheet_id,
232 kind,
233 ..
234 } => {
235 let mut editor = VertexEditor::new(graph);
236 let meta = VertexMeta::new(
237 coord.row(),
238 coord.col(),
239 *sheet_id,
240 kind.unwrap_or(crate::engine::vertex::VertexKind::Cell),
241 );
242 editor.try_add_vertex(meta)?;
243 }
244 ChangeEvent::RemoveVertex {
245 coord, sheet_id, ..
246 } => {
247 if let (Some(c), Some(sid)) = (coord, sheet_id) {
248 let mut editor = VertexEditor::new(graph);
249 let cell_ref = crate::reference::CellRef::new(
250 *sid,
251 crate::reference::Coord::new(c.row(), c.col(), true, true),
252 );
253 let _ = editor.remove_vertex_at(cell_ref);
254 }
255 }
256 ChangeEvent::VertexMoved { id, new_coord, .. } => {
257 let mut editor = VertexEditor::new(graph);
258 let _ = editor.move_vertex(*id, *new_coord);
259 }
260 ChangeEvent::FormulaAdjusted { id, new_ast, .. } => {
261 let _ = graph.update_vertex_formula(*id, new_ast.clone());
262 graph.mark_vertex_dirty(*id);
263 }
264 ChangeEvent::DefineName {
265 name,
266 scope,
267 definition,
268 } => {
269 let mut editor = VertexEditor::new(graph);
270 let _ = editor.define_name(name, definition.clone(), *scope);
271 }
272 ChangeEvent::UpdateName {
273 name,
274 scope,
275 new_definition,
276 ..
277 } => {
278 let mut editor = VertexEditor::new(graph);
279 let _ = editor.update_name(name, new_definition.clone(), *scope);
280 }
281 ChangeEvent::DeleteName { name, scope, .. } => {
282 let mut editor = VertexEditor::new(graph);
283 let _ = editor.delete_name(name, *scope);
284 }
285 ChangeEvent::NamedRangeAdjusted {
286 name,
287 scope,
288 new_definition,
289 ..
290 } => {
291 let mut editor = VertexEditor::new(graph);
292 let _ = editor.update_name(name, new_definition.clone(), *scope);
293 }
294 ChangeEvent::SpillCommitted { anchor, new, .. } => {
295 let _ = graph.commit_spill_region_atomic_with_fault(
296 *anchor,
297 new.target_cells.clone(),
298 new.values.clone(),
299 None,
300 );
301 }
302 ChangeEvent::SpillCleared { anchor, .. } => {
303 graph.clear_spill_region(*anchor);
304 }
305 ChangeEvent::EdgeAdded { from, to } => {
306 let mut editor = VertexEditor::new(graph);
307 let _ = editor.add_edge(*from, *to);
308 }
309 ChangeEvent::EdgeRemoved { from, to } => {
310 let mut editor = VertexEditor::new(graph);
311 let _ = editor.remove_edge(*from, *to);
312 }
313 ChangeEvent::CompoundStart { description, .. } => {
314 graph.replay_structural_marker(description, true);
315 }
316 ChangeEvent::CompoundEnd { .. } | ChangeEvent::StagedFormulaCellChanged { .. } => {}
317 }
318 Ok(())
319}
320
321#[derive(Debug, Clone, Default, PartialEq)]
322pub struct ActionJournal {
323 pub name: String,
324 pub graph: GraphUndoBatch,
325 pub arrow: ArrowUndoBatch,
326 pub affected_cells: usize,
327}