formualizer_eval/engine/graph/editor/
change_log.rs1use crate::SheetId;
9use crate::engine::named_range::{NameScope, NamedDefinition};
10use crate::engine::vertex::VertexId;
11use crate::reference::CellRef;
12use formualizer_common::Coord as AbsCoord;
13use formualizer_common::LiteralValue;
14use formualizer_parse::parser::ASTNode;
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct SpillSnapshot {
18 pub target_cells: Vec<CellRef>,
20 pub values: Vec<Vec<LiteralValue>>,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Default)]
29pub struct ChangeEventMeta {
30 pub actor_id: Option<String>,
31 pub correlation_id: Option<String>,
32 pub reason: Option<String>,
33}
34
35#[derive(Debug, Clone, PartialEq)]
37pub enum ChangeEvent {
38 SetValue {
40 addr: CellRef,
41 old_value: Option<LiteralValue>,
42 old_formula: Option<ASTNode>,
43 new: LiteralValue,
44 },
45 SetFormula {
46 addr: CellRef,
47 old_value: Option<LiteralValue>,
48 old_formula: Option<ASTNode>,
49 new: ASTNode,
50 },
51 AddVertex {
53 id: VertexId,
54 coord: AbsCoord,
55 sheet_id: SheetId,
56 value: Option<LiteralValue>,
57 formula: Option<ASTNode>,
58 kind: Option<crate::engine::vertex::VertexKind>,
59 flags: Option<u8>,
60 },
61 RemoveVertex {
62 id: VertexId,
63 old_value: Option<LiteralValue>,
65 old_formula: Option<ASTNode>,
66 old_dependencies: Vec<VertexId>, old_dependents: Vec<VertexId>, coord: Option<AbsCoord>,
69 sheet_id: Option<SheetId>,
70 kind: Option<crate::engine::vertex::VertexKind>,
71 flags: Option<u8>,
72 },
73
74 CompoundStart {
76 description: String, depth: usize,
78 },
79 CompoundEnd {
80 depth: usize,
81 },
82
83 VertexMoved {
85 id: VertexId,
86 sheet_id: SheetId,
87 old_coord: AbsCoord,
88 new_coord: AbsCoord,
89 },
90 FormulaAdjusted {
91 id: VertexId,
92 addr: Option<CellRef>,
94 old_ast: ASTNode,
95 new_ast: ASTNode,
96 },
97 NamedRangeAdjusted {
98 name: String,
99 scope: NameScope,
100 old_definition: NamedDefinition,
101 new_definition: NamedDefinition,
102 },
103 EdgeAdded {
104 from: VertexId,
105 to: VertexId,
106 },
107 EdgeRemoved {
108 from: VertexId,
109 to: VertexId,
110 },
111
112 DefineName {
114 name: String,
115 scope: NameScope,
116 definition: NamedDefinition,
117 },
118 UpdateName {
119 name: String,
120 scope: NameScope,
121 old_definition: NamedDefinition,
122 new_definition: NamedDefinition,
123 },
124 DeleteName {
125 name: String,
126 scope: NameScope,
127 old_definition: Option<NamedDefinition>,
128 },
129
130 SpillCommitted {
132 anchor: VertexId,
133 old: Option<SpillSnapshot>,
134 new: SpillSnapshot,
135 },
136 SpillCleared {
137 anchor: VertexId,
138 old: SpillSnapshot,
139 },
140}
141
142#[derive(Debug, Default)]
144pub struct ChangeLog {
145 events: Vec<ChangeEvent>,
146 metas: Vec<ChangeEventMeta>,
147 enabled: bool,
148 max_changelog_events: Option<usize>,
150 compound_depth: usize,
152 seqs: Vec<u64>,
154 groups: Vec<Option<u64>>,
156 next_seq: u64,
157 group_stack: Vec<u64>,
159 next_group_id: u64,
160
161 current_meta: ChangeEventMeta,
162}
163
164impl ChangeLog {
165 pub fn new() -> Self {
166 Self {
167 events: Vec::new(),
168 metas: Vec::new(),
169 enabled: true,
170 max_changelog_events: None,
171 compound_depth: 0,
172 seqs: Vec::new(),
173 groups: Vec::new(),
174 next_seq: 0,
175 group_stack: Vec::new(),
176 next_group_id: 1,
177 current_meta: ChangeEventMeta::default(),
178 }
179 }
180
181 pub fn with_max_changelog_events(max: usize) -> Self {
182 let mut out = Self::new();
183 out.max_changelog_events = Some(max);
184 out
185 }
186
187 pub fn set_max_changelog_events(&mut self, max: Option<usize>) {
188 self.max_changelog_events = max;
189 self.enforce_cap();
190 }
191
192 fn enforce_cap(&mut self) {
193 let Some(max) = self.max_changelog_events else {
194 return;
195 };
196 if max == 0 {
197 self.clear();
198 return;
199 }
200 if self.events.len() <= max {
201 return;
202 }
203 let drop_n = self.events.len() - max;
204 self.events.drain(0..drop_n);
205 self.metas.drain(0..drop_n);
206 self.seqs.drain(0..drop_n);
207 self.groups.drain(0..drop_n);
208 }
209
210 pub fn record(&mut self, event: ChangeEvent) {
211 if self.enabled {
212 let seq = self.next_seq;
213 self.next_seq += 1;
214 let current_group = self.group_stack.last().copied();
215 self.events.push(event);
216 self.metas.push(self.current_meta.clone());
217 self.seqs.push(seq);
218 self.groups.push(current_group);
219 self.enforce_cap();
220 }
221 }
222
223 pub fn record_with_meta(&mut self, event: ChangeEvent, meta: ChangeEventMeta) {
225 if self.enabled {
226 let seq = self.next_seq;
227 self.next_seq += 1;
228 let current_group = self.group_stack.last().copied();
229 self.events.push(event);
230 self.metas.push(meta);
231 self.seqs.push(seq);
232 self.groups.push(current_group);
233 self.enforce_cap();
234 }
235 }
236
237 pub fn begin_compound(&mut self, description: String) {
239 self.compound_depth += 1;
240 if self.compound_depth == 1 {
241 let gid = self.next_group_id;
243 self.next_group_id += 1;
244 self.group_stack.push(gid);
245 } else {
246 if let Some(&gid) = self.group_stack.last() {
248 self.group_stack.push(gid);
249 }
250 }
251 if self.enabled {
252 self.record(ChangeEvent::CompoundStart {
253 description,
254 depth: self.compound_depth,
255 });
256 }
257 }
258
259 pub fn end_compound(&mut self) {
261 if self.compound_depth > 0 {
262 if self.enabled {
263 self.record(ChangeEvent::CompoundEnd {
264 depth: self.compound_depth,
265 });
266 }
267 self.compound_depth -= 1;
268 self.group_stack.pop();
269 }
270 }
271
272 pub fn events(&self) -> &[ChangeEvent] {
273 &self.events
274 }
275
276 pub fn patch_last_cell_event_old_state(
277 &mut self,
278 addr: CellRef,
279 old_value: Option<LiteralValue>,
280 old_formula: Option<ASTNode>,
281 ) {
282 for ev in self.events.iter_mut().rev() {
286 match ev {
287 ChangeEvent::SetValue {
288 addr: a,
289 old_value: ov,
290 old_formula: of,
291 ..
292 }
293 | ChangeEvent::SetFormula {
294 addr: a,
295 old_value: ov,
296 old_formula: of,
297 ..
298 } if *a == addr => {
299 if ov.is_none() {
300 *ov = old_value;
301 }
302 if of.is_none() {
303 *of = old_formula;
304 }
305 break;
306 }
307 _ => {}
308 }
309 }
310 }
311
312 pub fn event_meta(&self, index: usize) -> Option<&ChangeEventMeta> {
313 self.metas.get(index)
314 }
315
316 pub fn set_actor_id(&mut self, actor_id: Option<String>) {
317 self.current_meta.actor_id = actor_id;
318 }
319
320 pub fn set_correlation_id(&mut self, correlation_id: Option<String>) {
321 self.current_meta.correlation_id = correlation_id;
322 }
323
324 pub fn set_reason(&mut self, reason: Option<String>) {
325 self.current_meta.reason = reason;
326 }
327
328 pub fn truncate(&mut self, len: usize) {
330 self.events.truncate(len);
331 self.metas.truncate(len);
332 self.seqs.truncate(len);
333 self.groups.truncate(len);
334 }
335
336 pub fn clear(&mut self) {
337 self.events.clear();
338 self.metas.clear();
339 self.seqs.clear();
340 self.groups.clear();
341 self.compound_depth = 0;
342 self.group_stack.clear();
343 }
344
345 pub fn len(&self) -> usize {
346 self.events.len()
347 }
348
349 pub fn is_empty(&self) -> bool {
350 self.events.is_empty()
351 }
352
353 pub fn take_from(&mut self, index: usize) -> Vec<ChangeEvent> {
355 let events = self.events.split_off(index);
356 let _ = self.metas.split_off(index);
357 let _ = self.seqs.split_off(index);
358 let _ = self.groups.split_off(index);
359 events
360 }
361
362 pub fn set_enabled(&mut self, enabled: bool) {
364 self.enabled = enabled;
365 }
366
367 pub fn compound_depth(&self) -> usize {
369 self.compound_depth
370 }
371
372 pub fn meta(&self, index: usize) -> Option<(u64, Option<u64>)> {
374 self.seqs
375 .get(index)
376 .copied()
377 .zip(self.groups.get(index).copied())
378 }
379
380 pub fn last_group_indices(&self) -> Vec<usize> {
382 if let Some(&last_gid) = self.groups.iter().rev().flatten().next() {
383 let idxs: Vec<usize> = self
384 .groups
385 .iter()
386 .enumerate()
387 .filter_map(|(i, g)| if *g == Some(last_gid) { Some(i) } else { None })
388 .collect();
389 if !idxs.is_empty() {
390 return idxs;
391 }
392 }
393 self.events.len().checked_sub(1).into_iter().collect()
394 }
395}
396
397pub trait ChangeLogger {
399 fn record(&mut self, event: ChangeEvent);
400 fn set_enabled(&mut self, enabled: bool);
401 fn begin_compound(&mut self, description: String);
402 fn end_compound(&mut self);
403}
404
405impl ChangeLogger for ChangeLog {
406 fn record(&mut self, event: ChangeEvent) {
407 ChangeLog::record(self, event);
408 }
409
410 fn set_enabled(&mut self, enabled: bool) {
411 self.enabled = enabled;
412 }
413
414 fn begin_compound(&mut self, description: String) {
415 ChangeLog::begin_compound(self, description);
416 }
417
418 fn end_compound(&mut self) {
419 ChangeLog::end_compound(self);
420 }
421}
422
423pub struct NullChangeLogger;
425
426impl ChangeLogger for NullChangeLogger {
427 fn record(&mut self, _: ChangeEvent) {}
428 fn set_enabled(&mut self, _: bool) {}
429 fn begin_compound(&mut self, _: String) {}
430 fn end_compound(&mut self) {}
431}