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::TableResized {
227 name,
228 new_range,
229 new_empty_body,
230 ..
231 } => {
232 graph.resize_table_body(name, *new_range, *new_empty_body)?;
233 }
234 ChangeEvent::SetRowVisibility { .. } => {
235 }
237 ChangeEvent::AddVertex {
238 coord,
239 sheet_id,
240 kind,
241 ..
242 } => {
243 let mut editor = VertexEditor::new(graph);
244 let meta = VertexMeta::new(
245 coord.row(),
246 coord.col(),
247 *sheet_id,
248 kind.unwrap_or(crate::engine::vertex::VertexKind::Cell),
249 );
250 editor.try_add_vertex(meta)?;
251 }
252 ChangeEvent::RemoveVertex {
253 coord, sheet_id, ..
254 } => {
255 if let (Some(c), Some(sid)) = (coord, sheet_id) {
256 let mut editor = VertexEditor::new(graph);
257 let cell_ref = crate::reference::CellRef::new(
258 *sid,
259 crate::reference::Coord::new(c.row(), c.col(), true, true),
260 );
261 let _ = editor.remove_vertex_at(cell_ref);
262 }
263 }
264 ChangeEvent::VertexMoved { id, new_coord, .. } => {
265 let mut editor = VertexEditor::new(graph);
266 let _ = editor.move_vertex(*id, *new_coord);
267 }
268 ChangeEvent::FormulaAdjusted { id, new_ast, .. } => {
269 let _ = graph.update_vertex_formula(*id, new_ast.clone());
270 graph.mark_vertex_dirty(*id);
271 }
272 ChangeEvent::DefineName {
273 name,
274 scope,
275 definition,
276 } => {
277 let mut editor = VertexEditor::new(graph);
278 let _ = editor.define_name(name, definition.clone(), *scope);
279 }
280 ChangeEvent::UpdateName {
281 name,
282 scope,
283 new_definition,
284 ..
285 } => {
286 let mut editor = VertexEditor::new(graph);
287 let _ = editor.update_name(name, new_definition.clone(), *scope);
288 }
289 ChangeEvent::DeleteName { name, scope, .. } => {
290 let mut editor = VertexEditor::new(graph);
291 let _ = editor.delete_name(name, *scope);
292 }
293 ChangeEvent::NamedRangeAdjusted {
294 name,
295 scope,
296 new_definition,
297 ..
298 } => {
299 let mut editor = VertexEditor::new(graph);
300 let _ = editor.update_name(name, new_definition.clone(), *scope);
301 }
302 ChangeEvent::SpillCommitted { anchor, new, .. } => {
303 let _ = graph.restore_spill_snapshot(*anchor, new);
304 }
305 ChangeEvent::SpillCleared { anchor, .. } => {
306 graph.clear_spill_region(*anchor);
307 }
308 ChangeEvent::EdgeAdded { from, to } => {
309 let mut editor = VertexEditor::new(graph);
310 let _ = editor.add_edge(*from, *to);
311 }
312 ChangeEvent::EdgeRemoved { from, to } => {
313 let mut editor = VertexEditor::new(graph);
314 let _ = editor.remove_edge(*from, *to);
315 }
316 ChangeEvent::CompoundStart { description, .. } => {
317 graph.replay_structural_marker(description, true);
318 }
319 ChangeEvent::CompoundEnd { .. } | ChangeEvent::StagedFormulaCellChanged { .. } => {}
320 }
321 Ok(())
322}
323
324#[derive(Debug, Clone, Default, PartialEq)]
325pub struct ActionJournal {
326 pub name: String,
327 pub graph: GraphUndoBatch,
328 pub arrow: ArrowUndoBatch,
329 pub affected_cells: usize,
330}