1use crate::SheetId;
2use crate::engine::graph::DependencyGraph;
3use crate::engine::graph::editor::reference_adjuster::{
4 MoveReferenceAdjuster, ReferenceAdjuster, RelativeReferenceAdjuster, ShiftOperation,
5};
6use crate::engine::named_range::{NameScope, NamedDefinition};
7use crate::engine::{ChangeEvent, ChangeLogger, VertexId, VertexKind};
8use crate::reference::{CellRef, Coord};
9use formualizer_common::Coord as AbsCoord;
10use formualizer_common::{ExcelError, ExcelErrorKind, LiteralValue};
11use formualizer_parse::parser::ASTNode;
12use rustc_hash::FxHashMap;
13use std::sync::atomic::{AtomicU64, Ordering};
14
15#[derive(Debug, Clone)]
17pub struct VertexMeta {
18 pub coord: AbsCoord,
19 pub sheet_id: SheetId,
20 pub kind: VertexKind,
21 pub flags: u8,
22}
23
24impl VertexMeta {
25 pub fn new(row: u32, col: u32, sheet_id: SheetId, kind: VertexKind) -> Self {
26 Self {
27 coord: AbsCoord::new(row, col),
28 sheet_id,
29 kind,
30 flags: 0,
31 }
32 }
33
34 pub fn with_flags(mut self, flags: u8) -> Self {
35 self.flags = flags;
36 self
37 }
38
39 pub fn dirty(mut self) -> Self {
40 self.flags |= 0x01;
41 self
42 }
43
44 pub fn volatile(mut self) -> Self {
45 self.flags |= 0x02;
46 self
47 }
48}
49
50#[derive(Debug, Clone)]
52pub struct VertexMetaPatch {
53 pub kind: Option<VertexKind>,
54 pub coord: Option<AbsCoord>,
55 pub dirty: Option<bool>,
56 pub volatile: Option<bool>,
57}
58
59#[derive(Debug, Clone)]
61pub struct VertexDataPatch {
62 pub value: Option<LiteralValue>,
63 pub formula: Option<ASTNode>,
64}
65
66#[derive(Debug, Clone, Default)]
68pub struct MetaUpdateSummary {
69 pub coord_changed: bool,
70 pub kind_changed: bool,
71 pub flags_changed: bool,
72}
73
74#[derive(Debug, Clone, Default)]
76pub struct DataUpdateSummary {
77 pub value_changed: bool,
78 pub formula_changed: bool,
79 pub dependents_marked_dirty: Vec<VertexId>,
80}
81
82#[derive(Debug, Clone, Default)]
84pub struct ShiftSummary {
85 pub vertices_moved: Vec<VertexId>,
86 pub vertices_deleted: Vec<VertexId>,
87 pub references_adjusted: usize,
88 pub formulas_updated: usize,
89}
90
91#[derive(Debug, Clone, Default)]
93pub struct RangeSummary {
94 pub cells_affected: usize,
95 pub vertices_created: Vec<VertexId>,
96 pub vertices_updated: Vec<VertexId>,
97 pub cells_moved: usize,
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub struct TransactionId(u64);
103
104impl TransactionId {
105 fn new() -> Self {
106 static COUNTER: AtomicU64 = AtomicU64::new(0);
107 TransactionId(COUNTER.fetch_add(1, Ordering::Relaxed))
108 }
109}
110
111#[derive(Debug)]
113struct Transaction {
114 id: TransactionId,
115 start_index: usize, }
117
118#[derive(Debug, Clone)]
120pub enum EditorError {
121 TargetOccupied { cell: CellRef },
122 OutOfBounds { row: u32, col: u32 },
123 InvalidName { name: String, reason: String },
124 TransactionFailed { reason: String },
125 TransactionUnsupported { reason: String },
126 NoActiveTransaction,
127 VertexNotFound { id: VertexId },
128 Excel(ExcelError),
129}
130
131impl From<ExcelError> for EditorError {
132 fn from(e: ExcelError) -> Self {
133 EditorError::Excel(e)
134 }
135}
136
137impl std::fmt::Display for EditorError {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 match self {
140 EditorError::TargetOccupied { cell } => {
141 write!(
142 f,
143 "Target cell occupied at row {}, col {}",
144 cell.coord.row(),
145 cell.coord.col()
146 )
147 }
148 EditorError::OutOfBounds { row, col } => {
149 write!(f, "Cell position out of bounds: row {row}, col {col}")
150 }
151 EditorError::InvalidName { name, reason } => {
152 write!(f, "Invalid name '{name}': {reason}")
153 }
154 EditorError::TransactionFailed { reason } => {
155 write!(f, "Transaction failed: {reason}")
156 }
157 EditorError::TransactionUnsupported { reason } => {
158 write!(f, "Transaction unsupported: {reason}")
159 }
160 EditorError::NoActiveTransaction => {
161 write!(f, "No active transaction")
162 }
163 EditorError::VertexNotFound { id } => {
164 write!(f, "Vertex not found: {id:?}")
165 }
166 EditorError::Excel(e) => write!(f, "Excel error: {e:?}"),
167 }
168 }
169}
170
171impl std::error::Error for EditorError {}
172
173pub trait SpillValueReader {
208 fn read_cell_value(&self, sheet: &str, row: u32, col: u32) -> Option<LiteralValue>;
209}
210
211pub struct VertexEditor<'g> {
212 graph: &'g mut DependencyGraph,
213 change_logger: Option<&'g mut dyn ChangeLogger>,
214 spill_value_reader: Option<&'g dyn SpillValueReader>,
215 batch_mode: bool,
216}
217
218impl<'g> VertexEditor<'g> {
219 pub fn new(graph: &'g mut DependencyGraph) -> Self {
221 Self {
222 graph,
223 change_logger: None,
224 spill_value_reader: None,
225 batch_mode: false,
226 }
227 }
228
229 pub fn with_logger<L: ChangeLogger + 'g>(
231 graph: &'g mut DependencyGraph,
232 logger: &'g mut L,
233 ) -> Self {
234 Self {
235 graph,
236 change_logger: Some(logger as &'g mut dyn ChangeLogger),
237 spill_value_reader: None,
238 batch_mode: false,
239 }
240 }
241
242 pub fn with_logger_and_spill_reader<L: ChangeLogger + 'g>(
244 graph: &'g mut DependencyGraph,
245 logger: &'g mut L,
246 spill_value_reader: &'g dyn SpillValueReader,
247 ) -> Self {
248 Self {
249 graph,
250 change_logger: Some(logger as &'g mut dyn ChangeLogger),
251 spill_value_reader: Some(spill_value_reader),
252 batch_mode: false,
253 }
254 }
255
256 pub fn begin_batch(&mut self) {
258 if !self.batch_mode {
259 self.graph.begin_batch();
260 self.batch_mode = true;
261 }
262 }
263
264 pub fn commit_batch(&mut self) {
266 if self.batch_mode {
267 self.graph.end_batch();
268 self.batch_mode = false;
269 }
270 }
271
272 fn log_change(&mut self, event: ChangeEvent) {
274 if let Some(logger) = &mut self.change_logger {
275 logger.record(event);
276 }
277 }
278
279 fn snapshot_spill_for_anchor(
280 &self,
281 anchor: VertexId,
282 ) -> Option<crate::engine::graph::editor::change_log::SpillSnapshot> {
283 let cells = self.graph.spill_cells_for_anchor(anchor)?.to_vec();
284 if cells.is_empty() {
285 return None;
286 }
287
288 let max = self.graph.get_config().spill.max_spill_cells as usize;
290 let mut cells = cells;
291 if cells.len() > max {
292 cells.truncate(max);
293 }
294
295 let first = *cells.first().expect("non-empty spill cells");
296 let sheet_name = self.graph.sheet_name(first.sheet_id).to_string();
297 let row0 = first.coord.row();
298 let col0 = first.coord.col();
299
300 let mut max_row = row0;
301 let mut max_col = col0;
302 let mut by_coord: FxHashMap<(u32, u32), LiteralValue> = FxHashMap::default();
303 for cell in &cells {
304 max_row = max_row.max(cell.coord.row());
305 max_col = max_col.max(cell.coord.col());
306 let v = if let Some(reader) = self.spill_value_reader {
307 reader
308 .read_cell_value(&sheet_name, cell.coord.row() + 1, cell.coord.col() + 1)
309 .unwrap_or(LiteralValue::Empty)
310 } else {
311 self.graph
312 .get_cell_value(&sheet_name, cell.coord.row() + 1, cell.coord.col() + 1)
313 .unwrap_or(LiteralValue::Empty)
314 };
315 by_coord.insert((cell.coord.row(), cell.coord.col()), v);
316 }
317
318 let rows = (max_row - row0 + 1) as usize;
319 let cols = (max_col - col0 + 1) as usize;
320 let mut values: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
321 for r in 0..rows {
322 let mut row: Vec<LiteralValue> = Vec::with_capacity(cols);
323 for c in 0..cols {
324 row.push(
325 by_coord
326 .get(&(row0 + r as u32, col0 + c as u32))
327 .cloned()
328 .unwrap_or(LiteralValue::Empty),
329 );
330 }
331 values.push(row);
332 }
333
334 Some(crate::engine::graph::editor::change_log::SpillSnapshot {
335 target_cells: cells,
336 values,
337 })
338 }
339
340 pub fn commit_spill_region(
342 &mut self,
343 anchor: VertexId,
344 target_cells: Vec<CellRef>,
345 values: Vec<Vec<LiteralValue>>,
346 ) -> Result<(), EditorError> {
347 let old = self.snapshot_spill_for_anchor(anchor);
348 self.graph
349 .commit_spill_region_atomic_with_fault(
350 anchor,
351 target_cells.clone(),
352 values.clone(),
353 None,
354 )
355 .map_err(EditorError::Excel)?;
356 self.log_change(ChangeEvent::SpillCommitted {
357 anchor,
358 old,
359 new: crate::engine::graph::editor::change_log::SpillSnapshot {
360 target_cells,
361 values,
362 },
363 });
364 Ok(())
365 }
366
367 pub fn clear_spill_region(&mut self, anchor: VertexId) {
369 let Some(old) = self.snapshot_spill_for_anchor(anchor) else {
370 return;
371 };
372 self.graph.clear_spill_region(anchor);
373 self.log_change(ChangeEvent::SpillCleared { anchor, old });
374 }
375
376 pub fn has_logger(&self) -> bool {
378 self.change_logger.is_some()
379 }
380
381 fn get_formula_ast(&self, id: VertexId) -> Option<ASTNode> {
382 self.graph.get_formula_id(id).and_then(|ast_id| {
383 self.graph
384 .data_store()
385 .retrieve_ast(ast_id, self.graph.sheet_reg())
386 })
387 }
388
389 fn snapshot_named_definitions(&self) -> FxHashMap<(NameScope, String), NamedDefinition> {
390 let mut out: FxHashMap<(NameScope, String), NamedDefinition> = FxHashMap::default();
391 for (name, nr) in self.graph.named_ranges_iter() {
392 out.insert((NameScope::Workbook, name.clone()), nr.definition.clone());
393 }
394 for ((sheet_id, name), nr) in self.graph.sheet_named_ranges_iter() {
395 out.insert(
396 (NameScope::Sheet(*sheet_id), name.clone()),
397 nr.definition.clone(),
398 );
399 }
400 out
401 }
402
403 pub fn apply_inverse(&mut self, change: ChangeEvent) -> Result<(), EditorError> {
410 match change {
411 ChangeEvent::SetValue {
412 addr,
413 old_value,
414 old_formula,
415 new: _,
416 } => {
417 if let Some(old_formula) = old_formula {
419 self.set_cell_formula(addr, old_formula);
420 } else if let Some(old_value) = old_value {
421 self.set_cell_value(addr, old_value);
422 } else if let Some(&id) = self.graph.get_vertex_id_for_address(&addr) {
423 self.remove_vertex(id)?;
424 }
425 }
426 ChangeEvent::SetFormula {
427 addr,
428 old_value,
429 old_formula,
430 new: _,
431 } => {
432 if let Some(old_formula) = old_formula {
434 self.set_cell_formula(addr, old_formula);
435 } else if let Some(old_value) = old_value {
436 self.set_cell_value(addr, old_value);
437 } else if let Some(&id) = self.graph.get_vertex_id_for_address(&addr) {
438 self.remove_vertex(id)?;
439 }
440 }
441 ChangeEvent::SetRowVisibility { .. } => {
442 }
444 ChangeEvent::AddVertex { id, .. } => {
445 let _ = self.remove_vertex(id); }
448 ChangeEvent::RemoveVertex {
449 id: _,
450 old_value,
451 old_formula,
452 old_dependencies,
453 old_dependents,
454 coord,
455 sheet_id,
456 kind,
457 ..
458 } => {
459 if let (Some(c), Some(sid)) = (coord, sheet_id) {
460 let meta =
461 VertexMeta::new(c.row(), c.col(), sid, kind.unwrap_or(VertexKind::Cell));
462 let new_id = self.add_vertex(meta);
463 if let Some(v) = old_value {
464 let cell_ref = self.graph.make_cell_ref_internal(sid, c.row(), c.col());
465 self.set_cell_value(cell_ref, v);
466 }
467 if let Some(f) = old_formula {
468 let cell_ref = self.graph.make_cell_ref_internal(sid, c.row(), c.col());
469 self.set_cell_formula(cell_ref, f);
470 }
471 for dep in old_dependencies {
472 self.graph.add_dependency_edge(new_id, dep);
473 }
474 for parent in old_dependents {
475 self.graph.add_dependency_edge(parent, new_id);
476 }
477 }
478 }
479 ChangeEvent::DefineName { name, scope, .. } => {
480 self.graph.delete_name(&name, scope)?;
482 }
483 ChangeEvent::UpdateName {
484 name,
485 scope,
486 old_definition,
487 ..
488 } => {
489 self.graph.update_name(&name, old_definition, scope)?;
491 }
492 ChangeEvent::DeleteName {
493 name,
494 scope,
495 old_definition,
496 } => {
497 if let Some(def) = old_definition {
498 self.graph.define_name(&name, def, scope)?;
499 } else {
500 return Err(EditorError::TransactionFailed {
501 reason: "Missing old definition for name deletion rollback".to_string(),
502 });
503 }
504 }
505 ChangeEvent::SpillCommitted { anchor, old, .. } => {
506 if let Some(old) = old {
508 self.graph
509 .commit_spill_region_atomic_with_fault(
510 anchor,
511 old.target_cells,
512 old.values,
513 None,
514 )
515 .map_err(EditorError::Excel)?;
516 } else {
517 self.graph.clear_spill_region(anchor);
518 }
519 }
520 ChangeEvent::SpillCleared { anchor, old } => {
521 self.graph
523 .commit_spill_region_atomic_with_fault(
524 anchor,
525 old.target_cells,
526 old.values,
527 None,
528 )
529 .map_err(EditorError::Excel)?;
530 }
531 ChangeEvent::StagedFormulaStateChanged { .. } => {
532 }
534 ChangeEvent::CompoundStart { .. } | ChangeEvent::CompoundEnd { .. } => {
536 }
538 ChangeEvent::VertexMoved {
539 id,
540 sheet_id: _,
541 old_coord,
542 ..
543 } => {
544 self.move_vertex(id, old_coord)?;
546 }
547 ChangeEvent::FormulaAdjusted { id, old_ast, .. } => {
548 self.graph
550 .update_vertex_formula(id, old_ast)
551 .map_err(EditorError::Excel)?;
552 self.graph.mark_vertex_dirty(id);
553 }
554 ChangeEvent::NamedRangeAdjusted {
555 name,
556 scope,
557 old_definition,
558 ..
559 } => {
560 self.graph.update_name(&name, old_definition, scope)?;
562 }
563 ChangeEvent::EdgeAdded { from, to } => {
564 return Err(EditorError::TransactionFailed {
567 reason: "Cannot rollback edge addition yet".to_string(),
568 });
569 }
570 ChangeEvent::EdgeRemoved { from, to } => {
571 return Err(EditorError::TransactionFailed {
574 reason: "Cannot rollback edge removal yet".to_string(),
575 });
576 }
577 }
578 Ok(())
579 }
580
581 pub fn add_vertex(&mut self, meta: VertexMeta) -> VertexId {
583 let sheet_name = self.graph.sheet_name(meta.sheet_id).to_string();
586
587 let id = match meta.kind {
588 VertexKind::Cell => {
589 match self.graph.set_cell_value(
593 &sheet_name,
594 meta.coord.row() + 1,
595 meta.coord.col() + 1,
596 LiteralValue::Empty,
597 ) {
598 Ok(summary) => summary
599 .affected_vertices
600 .into_iter()
601 .next()
602 .unwrap_or(VertexId::new(0)),
603 Err(_) => VertexId::new(0),
604 }
605 }
606 _ => {
607 match self.graph.set_cell_value(
611 &sheet_name,
612 meta.coord.row() + 1,
613 meta.coord.col() + 1,
614 LiteralValue::Empty,
615 ) {
616 Ok(summary) => summary
617 .affected_vertices
618 .into_iter()
619 .next()
620 .unwrap_or(VertexId::new(0)),
621 Err(_) => VertexId::new(0),
622 }
623 }
624 };
625
626 if self.has_logger() && id.0 != 0 {
627 self.log_change(ChangeEvent::AddVertex {
628 id,
629 coord: meta.coord,
630 sheet_id: meta.sheet_id,
631 value: Some(LiteralValue::Empty),
632 formula: None,
633 kind: Some(meta.kind),
634 flags: Some(meta.flags),
635 });
636 }
637 id
638 }
639
640 pub fn remove_vertex(&mut self, id: VertexId) -> Result<(), EditorError> {
642 if !self.graph.vertex_exists(id) {
644 return Err(EditorError::Excel(
645 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
646 ));
647 }
648
649 let spill_snapshot = self.snapshot_spill_for_anchor(id);
652 let did_spill_clear = spill_snapshot.is_some();
653 if let Some(old_spill) = spill_snapshot {
654 if let Some(logger) = &mut self.change_logger {
655 logger.begin_compound(format!("RemoveVertexWithSpillClear id={}", id.0));
656 }
657 self.graph.clear_spill_region(id);
658 self.log_change(ChangeEvent::SpillCleared {
659 anchor: id,
660 old: old_spill,
661 });
662 }
663
664 let dependents = self.graph.get_dependents(id);
667
668 let (
670 old_value,
671 old_formula,
672 old_dependencies,
673 old_dependents,
674 coord,
675 sheet_id_opt,
676 kind,
677 flags,
678 ) = if self.has_logger() {
679 let coord = self.graph.get_coord(id);
680 let sheet_id = self.graph.get_sheet_id(id);
681 let kind = self.graph.get_vertex_kind(id);
682 let flags = 0u8;
684 (
685 self.graph.get_value(id),
686 self.get_formula_ast(id),
687 self.graph.get_dependencies(id), dependents.clone(), Some(coord),
690 Some(sheet_id),
691 Some(kind),
692 Some(flags),
693 )
694 } else {
695 (None, None, vec![], vec![], None, None, None, None)
696 };
697
698 if let Some(cell_ref) = self.graph.get_cell_ref_for_vertex(id) {
700 self.graph.remove_cell_mapping(&cell_ref);
701 }
702
703 self.graph.remove_all_edges(id);
705
706 for dep_id in &dependents {
708 self.graph.mark_as_ref_error(*dep_id);
709 }
710
711 self.graph.mark_deleted(id, true);
713
714 self.log_change(ChangeEvent::RemoveVertex {
716 id,
717 old_value,
718 old_formula,
719 old_dependencies,
720 old_dependents,
721 coord,
722 sheet_id: sheet_id_opt,
723 kind,
724 flags,
725 });
726
727 if did_spill_clear && let Some(logger) = &mut self.change_logger {
728 logger.end_compound();
729 }
730
731 Ok(())
732 }
733
734 pub fn remove_vertex_at(&mut self, cell: CellRef) -> Result<(), EditorError> {
736 if let Some(id) = self.graph.get_vertex_for_cell(&cell) {
737 self.remove_vertex(id)
738 } else {
739 Ok(())
740 }
741 }
742
743 pub fn move_vertex(&mut self, id: VertexId, new_coord: AbsCoord) -> Result<(), EditorError> {
745 if !self.graph.vertex_exists(id) {
747 return Err(EditorError::Excel(
748 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
749 ));
750 }
751
752 let old_cell_ref = self.graph.get_cell_ref_for_vertex(id);
754
755 let sheet_id = self.graph.get_sheet_id(id);
757 let new_cell_ref = CellRef::new(
758 sheet_id,
759 Coord::new(new_coord.row(), new_coord.col(), true, true),
760 );
761
762 self.graph.set_coord(id, new_coord);
764
765 self.graph.update_edge_coord(id, new_coord);
767
768 self.graph
770 .update_cell_mapping(id, old_cell_ref, new_cell_ref);
771
772 self.graph.mark_dependents_dirty(id);
774
775 Ok(())
776 }
777
778 pub fn patch_vertex_meta(
780 &mut self,
781 id: VertexId,
782 patch: VertexMetaPatch,
783 ) -> Result<MetaUpdateSummary, EditorError> {
784 if !self.graph.vertex_exists(id) {
785 return Err(EditorError::Excel(
786 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
787 ));
788 }
789
790 let mut summary = MetaUpdateSummary::default();
791
792 if let Some(coord) = patch.coord {
793 self.graph.set_coord(id, coord);
794 self.graph.update_edge_coord(id, coord);
795 summary.coord_changed = true;
796 }
797
798 if let Some(kind) = patch.kind {
799 self.graph.set_kind(id, kind);
800 summary.kind_changed = true;
801 }
802
803 if let Some(dirty) = patch.dirty {
804 self.graph.set_dirty(id, dirty);
805 summary.flags_changed = true;
806 }
807
808 if let Some(volatile) = patch.volatile {
809 self.graph.mark_volatile(id, volatile);
810 summary.flags_changed = true;
811 }
812
813 Ok(summary)
814 }
815
816 pub fn patch_vertex_data(
818 &mut self,
819 id: VertexId,
820 patch: VertexDataPatch,
821 ) -> Result<DataUpdateSummary, EditorError> {
822 if !self.graph.vertex_exists(id) {
823 return Err(EditorError::Excel(
824 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
825 ));
826 }
827
828 let mut summary = DataUpdateSummary::default();
829
830 if let Some(value) = patch.value {
831 self.graph.update_vertex_value(id, value);
832 summary.value_changed = true;
833
834 if self.graph.edges_delta_size() > 0 {
837 self.graph.rebuild_edges();
838 }
839
840 let dependents = self.graph.get_dependents(id);
842 for dep in &dependents {
843 self.graph.set_dirty(*dep, true);
844 }
845 summary.dependents_marked_dirty = dependents;
846 }
847
848 if let Some(_formula) = patch.formula {
849 summary.formula_changed = true;
852 }
853
854 Ok(summary)
855 }
856
857 pub fn add_edge(&mut self, from: VertexId, to: VertexId) -> bool {
859 if from == to {
860 return false; }
862
863 true
866 }
867
868 pub fn remove_edge(&mut self, _from: VertexId, _to: VertexId) -> bool {
870 true
872 }
873
874 pub fn insert_rows(
876 &mut self,
877 sheet_id: SheetId,
878 before: u32,
879 count: u32,
880 ) -> Result<ShiftSummary, EditorError> {
881 if count == 0 {
882 return Ok(ShiftSummary::default());
883 }
884
885 let mut summary = ShiftSummary::default();
886
887 self.begin_batch();
889
890 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
892 .graph
893 .vertices_in_sheet(sheet_id)
894 .filter_map(|id| {
895 let coord = self.graph.get_coord(id);
896 if coord.row() >= before {
897 Some((id, coord))
898 } else {
899 None
900 }
901 })
902 .collect();
903
904 if let Some(logger) = &mut self.change_logger {
905 logger.begin_compound(format!(
906 "InsertRows sheet={sheet_id} before={before} count={count}"
907 ));
908 }
909 for (id, old_coord) in vertices_to_shift {
911 let new_coord = AbsCoord::new(old_coord.row() + count, old_coord.col());
912 if self.has_logger() {
913 self.log_change(ChangeEvent::VertexMoved {
914 id,
915 sheet_id,
916 old_coord,
917 new_coord,
918 });
919 }
920 self.move_vertex(id, new_coord)?;
921 summary.vertices_moved.push(id);
922 }
923
924 let op = ShiftOperation::InsertRows {
926 sheet_id,
927 before,
928 count,
929 };
930 let adjuster = ReferenceAdjuster::new();
931
932 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
934
935 for id in formula_vertices {
936 if let Some(ast) = self.get_formula_ast(id) {
937 let adjusted = adjuster.adjust_ast(&ast, &op);
938 if format!("{ast:?}") != format!("{adjusted:?}") {
940 if self.has_logger() {
941 self.log_change(ChangeEvent::FormulaAdjusted {
942 id,
943 addr: self.graph.get_cell_ref_for_vertex(id),
944 old_ast: ast.clone(),
945 new_ast: adjusted.clone(),
946 });
947 }
948 self.graph.update_vertex_formula(id, adjusted)?;
949 self.graph.mark_vertex_dirty(id);
950 summary.formulas_updated += 1;
951 }
952 }
953 }
954
955 let old_names = if self.has_logger() {
957 Some(self.snapshot_named_definitions())
958 } else {
959 None
960 };
961 self.graph.adjust_named_ranges(&op)?;
962 if let Some(old_names) = old_names {
963 let new_names = self.snapshot_named_definitions();
964 for ((scope, name), old_definition) in old_names {
965 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
966 && *new_definition != old_definition
967 {
968 self.log_change(ChangeEvent::NamedRangeAdjusted {
969 name,
970 scope,
971 old_definition,
972 new_definition: new_definition.clone(),
973 });
974 }
975 }
976 }
977
978 if let Some(logger) = &mut self.change_logger {
980 logger.end_compound();
981 }
982
983 self.commit_batch();
984
985 Ok(summary)
986 }
987
988 pub fn delete_rows(
990 &mut self,
991 sheet_id: SheetId,
992 start: u32,
993 count: u32,
994 ) -> Result<ShiftSummary, EditorError> {
995 if count == 0 {
996 return Ok(ShiftSummary::default());
997 }
998
999 let mut summary = ShiftSummary::default();
1000
1001 self.begin_batch();
1002
1003 if let Some(logger) = &mut self.change_logger {
1004 logger.begin_compound(format!(
1005 "DeleteRows sheet={sheet_id} start={start} count={count}"
1006 ));
1007 }
1008
1009 let vertices_to_delete: Vec<VertexId> = self
1011 .graph
1012 .vertices_in_sheet(sheet_id)
1013 .filter(|&id| {
1014 let coord = self.graph.get_coord(id);
1015 coord.row() >= start && coord.row() < start + count
1016 })
1017 .collect();
1018
1019 for id in vertices_to_delete {
1020 self.remove_vertex(id)?;
1021 summary.vertices_deleted.push(id);
1022 }
1023 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
1025 .graph
1026 .vertices_in_sheet(sheet_id)
1027 .filter_map(|id| {
1028 let coord = self.graph.get_coord(id);
1029 if coord.row() >= start + count {
1030 Some((id, coord))
1031 } else {
1032 None
1033 }
1034 })
1035 .collect();
1036
1037 for (id, old_coord) in vertices_to_shift {
1038 let new_coord = AbsCoord::new(old_coord.row() - count, old_coord.col());
1039 if self.has_logger() {
1040 self.log_change(ChangeEvent::VertexMoved {
1041 id,
1042 sheet_id,
1043 old_coord,
1044 new_coord,
1045 });
1046 }
1047 self.move_vertex(id, new_coord)?;
1048 summary.vertices_moved.push(id);
1049 }
1050
1051 let op = ShiftOperation::DeleteRows {
1053 sheet_id,
1054 start,
1055 count,
1056 };
1057 let adjuster = ReferenceAdjuster::new();
1058
1059 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
1060
1061 for id in formula_vertices {
1062 if let Some(ast) = self.get_formula_ast(id) {
1063 let adjusted = adjuster.adjust_ast(&ast, &op);
1064 if format!("{ast:?}") != format!("{adjusted:?}") {
1065 if self.has_logger() {
1066 self.log_change(ChangeEvent::FormulaAdjusted {
1067 id,
1068 addr: self.graph.get_cell_ref_for_vertex(id),
1069 old_ast: ast.clone(),
1070 new_ast: adjusted.clone(),
1071 });
1072 }
1073 self.graph.update_vertex_formula(id, adjusted)?;
1074 self.graph.mark_vertex_dirty(id);
1075 summary.formulas_updated += 1;
1076 }
1077 }
1078 }
1079
1080 let old_names = if self.has_logger() {
1082 Some(self.snapshot_named_definitions())
1083 } else {
1084 None
1085 };
1086 self.graph.adjust_named_ranges(&op)?;
1087 if let Some(old_names) = old_names {
1088 let new_names = self.snapshot_named_definitions();
1089 for ((scope, name), old_definition) in old_names {
1090 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
1091 && *new_definition != old_definition
1092 {
1093 self.log_change(ChangeEvent::NamedRangeAdjusted {
1094 name,
1095 scope,
1096 old_definition,
1097 new_definition: new_definition.clone(),
1098 });
1099 }
1100 }
1101 }
1102
1103 if let Some(logger) = &mut self.change_logger {
1105 logger.end_compound();
1106 }
1107
1108 self.commit_batch();
1109
1110 Ok(summary)
1111 }
1112
1113 pub fn insert_columns(
1115 &mut self,
1116 sheet_id: SheetId,
1117 before: u32,
1118 count: u32,
1119 ) -> Result<ShiftSummary, EditorError> {
1120 if count == 0 {
1121 return Ok(ShiftSummary::default());
1122 }
1123
1124 let mut summary = ShiftSummary::default();
1125
1126 self.begin_batch();
1128
1129 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
1131 .graph
1132 .vertices_in_sheet(sheet_id)
1133 .filter_map(|id| {
1134 let coord = self.graph.get_coord(id);
1135 if coord.col() >= before {
1136 Some((id, coord))
1137 } else {
1138 None
1139 }
1140 })
1141 .collect();
1142
1143 if let Some(logger) = &mut self.change_logger {
1144 logger.begin_compound(format!(
1145 "InsertColumns sheet={sheet_id} before={before} count={count}"
1146 ));
1147 }
1148 for (id, old_coord) in vertices_to_shift {
1150 let new_coord = AbsCoord::new(old_coord.row(), old_coord.col() + count);
1151 if self.has_logger() {
1152 self.log_change(ChangeEvent::VertexMoved {
1153 id,
1154 sheet_id,
1155 old_coord,
1156 new_coord,
1157 });
1158 }
1159 self.move_vertex(id, new_coord)?;
1160 summary.vertices_moved.push(id);
1161 }
1162
1163 let op = ShiftOperation::InsertColumns {
1165 sheet_id,
1166 before,
1167 count,
1168 };
1169 let adjuster = ReferenceAdjuster::new();
1170
1171 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
1173
1174 for id in formula_vertices {
1175 if let Some(ast) = self.get_formula_ast(id) {
1176 let adjusted = adjuster.adjust_ast(&ast, &op);
1177 if format!("{ast:?}") != format!("{adjusted:?}") {
1179 if self.has_logger() {
1180 self.log_change(ChangeEvent::FormulaAdjusted {
1181 id,
1182 addr: self.graph.get_cell_ref_for_vertex(id),
1183 old_ast: ast.clone(),
1184 new_ast: adjusted.clone(),
1185 });
1186 }
1187 self.graph.update_vertex_formula(id, adjusted)?;
1188 self.graph.mark_vertex_dirty(id);
1189 summary.formulas_updated += 1;
1190 }
1191 }
1192 }
1193
1194 let old_names = if self.has_logger() {
1196 Some(self.snapshot_named_definitions())
1197 } else {
1198 None
1199 };
1200 self.graph.adjust_named_ranges(&op)?;
1201 if let Some(old_names) = old_names {
1202 let new_names = self.snapshot_named_definitions();
1203 for ((scope, name), old_definition) in old_names {
1204 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
1205 && *new_definition != old_definition
1206 {
1207 self.log_change(ChangeEvent::NamedRangeAdjusted {
1208 name,
1209 scope,
1210 old_definition,
1211 new_definition: new_definition.clone(),
1212 });
1213 }
1214 }
1215 }
1216
1217 if let Some(logger) = &mut self.change_logger {
1219 logger.end_compound();
1220 }
1221
1222 self.commit_batch();
1223
1224 Ok(summary)
1225 }
1226
1227 pub fn delete_columns(
1229 &mut self,
1230 sheet_id: SheetId,
1231 start: u32,
1232 count: u32,
1233 ) -> Result<ShiftSummary, EditorError> {
1234 if count == 0 {
1235 return Ok(ShiftSummary::default());
1236 }
1237
1238 let mut summary = ShiftSummary::default();
1239
1240 self.begin_batch();
1241
1242 if let Some(logger) = &mut self.change_logger {
1243 logger.begin_compound(format!(
1244 "DeleteColumns sheet={sheet_id} start={start} count={count}"
1245 ));
1246 }
1247
1248 let vertices_to_delete: Vec<VertexId> = self
1250 .graph
1251 .vertices_in_sheet(sheet_id)
1252 .filter(|&id| {
1253 let coord = self.graph.get_coord(id);
1254 coord.col() >= start && coord.col() < start + count
1255 })
1256 .collect();
1257
1258 for id in vertices_to_delete {
1259 self.remove_vertex(id)?;
1260 summary.vertices_deleted.push(id);
1261 }
1262 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
1264 .graph
1265 .vertices_in_sheet(sheet_id)
1266 .filter_map(|id| {
1267 let coord = self.graph.get_coord(id);
1268 if coord.col() >= start + count {
1269 Some((id, coord))
1270 } else {
1271 None
1272 }
1273 })
1274 .collect();
1275
1276 for (id, old_coord) in vertices_to_shift {
1277 let new_coord = AbsCoord::new(old_coord.row(), old_coord.col() - count);
1278 if self.has_logger() {
1279 self.log_change(ChangeEvent::VertexMoved {
1280 id,
1281 sheet_id,
1282 old_coord,
1283 new_coord,
1284 });
1285 }
1286 self.move_vertex(id, new_coord)?;
1287 summary.vertices_moved.push(id);
1288 }
1289
1290 let op = ShiftOperation::DeleteColumns {
1292 sheet_id,
1293 start,
1294 count,
1295 };
1296 let adjuster = ReferenceAdjuster::new();
1297
1298 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
1299
1300 for id in formula_vertices {
1301 if let Some(ast) = self.get_formula_ast(id) {
1302 let adjusted = adjuster.adjust_ast(&ast, &op);
1303 if format!("{ast:?}") != format!("{adjusted:?}") {
1304 if self.has_logger() {
1305 self.log_change(ChangeEvent::FormulaAdjusted {
1306 id,
1307 addr: self.graph.get_cell_ref_for_vertex(id),
1308 old_ast: ast.clone(),
1309 new_ast: adjusted.clone(),
1310 });
1311 }
1312 self.graph.update_vertex_formula(id, adjusted)?;
1313 self.graph.mark_vertex_dirty(id);
1314 summary.formulas_updated += 1;
1315 }
1316 }
1317 }
1318
1319 let old_names = if self.has_logger() {
1321 Some(self.snapshot_named_definitions())
1322 } else {
1323 None
1324 };
1325 self.graph.adjust_named_ranges(&op)?;
1326 if let Some(old_names) = old_names {
1327 let new_names = self.snapshot_named_definitions();
1328 for ((scope, name), old_definition) in old_names {
1329 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
1330 && *new_definition != old_definition
1331 {
1332 self.log_change(ChangeEvent::NamedRangeAdjusted {
1333 name,
1334 scope,
1335 old_definition,
1336 new_definition: new_definition.clone(),
1337 });
1338 }
1339 }
1340 }
1341
1342 if let Some(logger) = &mut self.change_logger {
1344 logger.end_compound();
1345 }
1346
1347 self.commit_batch();
1348
1349 Ok(summary)
1350 }
1351
1352 pub fn shift_rows(&mut self, sheet_id: SheetId, start_row: u32, delta: i32) {
1354 if delta == 0 {
1355 return;
1356 }
1357
1358 let change_event = ChangeEvent::SetValue {
1360 addr: CellRef {
1361 sheet_id,
1362 coord: Coord::new(start_row, 0, true, true),
1363 },
1364 old_value: None,
1365 old_formula: None,
1366 new: LiteralValue::Text(format!("Row shift: start={start_row}, delta={delta}")),
1367 };
1368 self.log_change(change_event);
1369
1370 }
1373
1374 pub fn shift_columns(&mut self, sheet_id: SheetId, start_col: u32, delta: i32) {
1376 if delta == 0 {
1377 return;
1378 }
1379
1380 let change_event = ChangeEvent::SetValue {
1382 addr: CellRef {
1383 sheet_id,
1384 coord: Coord::new(0, start_col, true, true),
1385 },
1386 old_value: None,
1387 old_formula: None,
1388 new: LiteralValue::Text(format!("Column shift: start={start_col}, delta={delta}")),
1389 };
1390 self.log_change(change_event);
1391
1392 }
1395
1396 pub fn set_cell_value(&mut self, cell_ref: CellRef, value: LiteralValue) -> VertexId {
1398 let sheet_name = self.graph.sheet_name(cell_ref.sheet_id).to_string();
1399
1400 let old_id = self.graph.get_vertex_id_for_address(&cell_ref).copied();
1402 let old_value = old_id.and_then(|id| self.graph.get_value(id));
1403 let old_formula = old_id.and_then(|id| self.get_formula_ast(id));
1404
1405 let spill_snapshot =
1408 old_id.and_then(|id| self.snapshot_spill_for_anchor(id).map(|s| (id, s)));
1409 let did_spill_clear = spill_snapshot.is_some();
1410 if let Some((anchor, old_spill)) = spill_snapshot {
1411 if let Some(logger) = &mut self.change_logger {
1412 logger.begin_compound(format!(
1413 "SetValueWithSpillClear sheet={} row={} col={}",
1414 cell_ref.sheet_id,
1415 cell_ref.coord.row(),
1416 cell_ref.coord.col()
1417 ));
1418 }
1419 self.graph.clear_spill_region(anchor);
1420 self.log_change(ChangeEvent::SpillCleared {
1421 anchor,
1422 old: old_spill,
1423 });
1424 }
1425
1426 match self.graph.set_cell_value(
1429 &sheet_name,
1430 cell_ref.coord.row() + 1,
1431 cell_ref.coord.col() + 1,
1432 value.clone(),
1433 ) {
1434 Ok(summary) => {
1435 let change_event = ChangeEvent::SetValue {
1437 addr: cell_ref,
1438 old_value,
1439 old_formula,
1440 new: value,
1441 };
1442 self.log_change(change_event);
1443
1444 if did_spill_clear && let Some(logger) = &mut self.change_logger {
1445 logger.end_compound();
1446 }
1447
1448 summary
1449 .affected_vertices
1450 .into_iter()
1451 .next()
1452 .unwrap_or(VertexId::new(0))
1453 }
1454 Err(_) => VertexId::new(0),
1455 }
1456 }
1457
1458 pub fn set_cell_formula(&mut self, cell_ref: CellRef, formula: ASTNode) -> VertexId {
1460 let sheet_name = self.graph.sheet_name(cell_ref.sheet_id).to_string();
1461
1462 let old_id = self.graph.get_vertex_id_for_address(&cell_ref).copied();
1464 let old_value = old_id.and_then(|id| self.graph.get_value(id));
1465 let old_formula = old_id.and_then(|id| self.get_formula_ast(id));
1466
1467 let spill_snapshot =
1469 old_id.and_then(|id| self.snapshot_spill_for_anchor(id).map(|s| (id, s)));
1470 let did_spill_clear = spill_snapshot.is_some();
1471 if let Some((anchor, old_spill)) = spill_snapshot {
1472 if let Some(logger) = &mut self.change_logger {
1473 logger.begin_compound(format!(
1474 "SetFormulaWithSpillClear sheet={} row={} col={}",
1475 cell_ref.sheet_id,
1476 cell_ref.coord.row(),
1477 cell_ref.coord.col()
1478 ));
1479 }
1480 self.graph.clear_spill_region(anchor);
1481 self.log_change(ChangeEvent::SpillCleared {
1482 anchor,
1483 old: old_spill,
1484 });
1485 }
1486
1487 match self.graph.set_cell_formula(
1490 &sheet_name,
1491 cell_ref.coord.row() + 1,
1492 cell_ref.coord.col() + 1,
1493 formula.clone(),
1494 ) {
1495 Ok(summary) => {
1496 let change_event = ChangeEvent::SetFormula {
1498 addr: cell_ref,
1499 old_value,
1500 old_formula,
1501 new: formula,
1502 };
1503 self.log_change(change_event);
1504
1505 if did_spill_clear && let Some(logger) = &mut self.change_logger {
1506 logger.end_compound();
1507 }
1508
1509 summary
1510 .affected_vertices
1511 .into_iter()
1512 .next()
1513 .unwrap_or(VertexId::new(0))
1514 }
1515 Err(_) => VertexId::new(0),
1516 }
1517 }
1518
1519 pub fn set_range_values(
1523 &mut self,
1524 sheet_id: SheetId,
1525 start_row: u32,
1526 start_col: u32,
1527 values: &[Vec<LiteralValue>],
1528 ) -> Result<RangeSummary, EditorError> {
1529 let mut summary = RangeSummary::default();
1530
1531 self.begin_batch();
1532
1533 for (row_offset, row_values) in values.iter().enumerate() {
1534 for (col_offset, value) in row_values.iter().enumerate() {
1535 let row = start_row + row_offset as u32;
1536 let col = start_col + col_offset as u32;
1537
1538 let cell_ref = self.graph.make_cell_ref_internal(sheet_id, row, col);
1540
1541 if let Some(&existing_id) = self.graph.get_vertex_id_for_address(&cell_ref) {
1542 self.graph.update_vertex_value(existing_id, value.clone());
1544 self.graph.mark_vertex_dirty(existing_id);
1545 summary.vertices_updated.push(existing_id);
1546 } else {
1547 let meta = VertexMeta::new(row, col, sheet_id, VertexKind::Cell);
1549 let id = self.add_vertex(meta);
1550 self.graph.update_vertex_value(id, value.clone());
1551 summary.vertices_created.push(id);
1552 }
1553
1554 summary.cells_affected += 1;
1555 }
1556 }
1557
1558 self.commit_batch();
1559
1560 Ok(summary)
1561 }
1562
1563 pub fn clear_range(
1565 &mut self,
1566 sheet_id: SheetId,
1567 start_row: u32,
1568 start_col: u32,
1569 end_row: u32,
1570 end_col: u32,
1571 ) -> Result<RangeSummary, EditorError> {
1572 let mut summary = RangeSummary::default();
1573
1574 self.begin_batch();
1575
1576 let vertices_in_range: Vec<_> = self
1578 .graph
1579 .vertices_in_sheet(sheet_id)
1580 .filter(|&id| {
1581 let coord = self.graph.get_coord(id);
1582 let row = coord.row();
1583 let col = coord.col();
1584 row >= start_row && row <= end_row && col >= start_col && col <= end_col
1585 })
1586 .collect();
1587
1588 for id in vertices_in_range {
1589 self.remove_vertex(id)?;
1590 summary.cells_affected += 1;
1591 }
1592
1593 self.commit_batch();
1594
1595 Ok(summary)
1596 }
1597
1598 pub fn copy_range(
1600 &mut self,
1601 sheet_id: SheetId,
1602 from_start_row: u32,
1603 from_start_col: u32,
1604 from_end_row: u32,
1605 from_end_col: u32,
1606 to_sheet_id: SheetId,
1607 to_row: u32,
1608 to_col: u32,
1609 ) -> Result<RangeSummary, EditorError> {
1610 let row_offset = to_row as i32 - from_start_row as i32;
1611 let col_offset = to_col as i32 - from_start_col as i32;
1612
1613 let mut summary = RangeSummary::default();
1614 let mut cell_data = Vec::new();
1615
1616 let vertices_in_range: Vec<_> = self
1618 .graph
1619 .vertices_in_sheet(sheet_id)
1620 .filter(|&id| {
1621 let coord = self.graph.get_coord(id);
1622 let row = coord.row();
1623 let col = coord.col();
1624 row >= from_start_row
1625 && row <= from_end_row
1626 && col >= from_start_col
1627 && col <= from_end_col
1628 })
1629 .collect();
1630
1631 for id in vertices_in_range {
1632 let coord = self.graph.get_coord(id);
1633 let row = coord.row();
1634 let col = coord.col();
1635
1636 if let Some(formula) = self.get_formula_ast(id) {
1638 cell_data.push((
1639 row - from_start_row,
1640 col - from_start_col,
1641 CellData::Formula(formula),
1642 ));
1643 } else if let Some(value) = self.graph.get_value(id) {
1644 cell_data.push((
1645 row - from_start_row,
1646 col - from_start_col,
1647 CellData::Value(value),
1648 ));
1649 }
1650 }
1651
1652 self.begin_batch();
1653
1654 for (row_idx, col_idx, data) in cell_data {
1656 let dest_row = (to_row as i32 + row_idx as i32) as u32;
1657 let dest_col = (to_col as i32 + col_idx as i32) as u32;
1658
1659 match data {
1660 CellData::Value(value) => {
1661 let cell_ref =
1662 self.graph
1663 .make_cell_ref_internal(to_sheet_id, dest_row, dest_col);
1664
1665 if let Some(&existing_id) = self.graph.get_vertex_id_for_address(&cell_ref) {
1666 self.graph.update_vertex_value(existing_id, value);
1667 self.graph.mark_vertex_dirty(existing_id);
1668 summary.vertices_updated.push(existing_id);
1669 } else {
1670 let meta =
1671 VertexMeta::new(dest_row, dest_col, to_sheet_id, VertexKind::Cell);
1672 let id = self.add_vertex(meta);
1673 self.graph.update_vertex_value(id, value);
1674 summary.vertices_created.push(id);
1675 }
1676 }
1677 CellData::Formula(formula) => {
1678 let adjuster = RelativeReferenceAdjuster::new(row_offset, col_offset);
1680 let adjusted = adjuster.adjust_formula(&formula);
1681
1682 let cell_ref =
1683 self.graph
1684 .make_cell_ref_internal(to_sheet_id, dest_row, dest_col);
1685
1686 if let Some(&existing_id) = self.graph.get_vertex_id_for_address(&cell_ref) {
1687 self.graph.update_vertex_formula(existing_id, adjusted)?;
1688 summary.vertices_updated.push(existing_id);
1689 } else {
1690 let meta = VertexMeta::new(
1691 dest_row,
1692 dest_col,
1693 to_sheet_id,
1694 VertexKind::FormulaScalar,
1695 );
1696 let id = self.add_vertex(meta);
1697 self.graph.update_vertex_formula(id, adjusted)?;
1698 summary.vertices_created.push(id);
1699 }
1700 }
1701 }
1702
1703 summary.cells_affected += 1;
1704 }
1705
1706 self.commit_batch();
1707
1708 Ok(summary)
1709 }
1710
1711 pub fn move_range(
1713 &mut self,
1714 sheet_id: SheetId,
1715 from_start_row: u32,
1716 from_start_col: u32,
1717 from_end_row: u32,
1718 from_end_col: u32,
1719 to_sheet_id: SheetId,
1720 to_row: u32,
1721 to_col: u32,
1722 ) -> Result<RangeSummary, EditorError> {
1723 let mut summary = self.copy_range(
1725 sheet_id,
1726 from_start_row,
1727 from_start_col,
1728 from_end_row,
1729 from_end_col,
1730 to_sheet_id,
1731 to_row,
1732 to_col,
1733 )?;
1734
1735 let clear_summary = self.clear_range(
1737 sheet_id,
1738 from_start_row,
1739 from_start_col,
1740 from_end_row,
1741 from_end_col,
1742 )?;
1743
1744 summary.cells_moved = clear_summary.cells_affected;
1745
1746 let row_offset = to_row as i32 - from_start_row as i32;
1748 let col_offset = to_col as i32 - from_start_col as i32;
1749
1750 let all_formula_vertices: Vec<_> = self.graph.vertices_with_formulas().collect();
1752
1753 let from_sheet_name = self.graph.sheet_name(sheet_id).to_string();
1754 let to_sheet_name = self.graph.sheet_name(to_sheet_id).to_string();
1755 let adjuster = MoveReferenceAdjuster::new(
1756 sheet_id,
1757 from_sheet_name,
1758 from_start_row,
1759 from_start_col,
1760 from_end_row,
1761 from_end_col,
1762 to_sheet_id,
1763 to_sheet_name,
1764 row_offset,
1765 col_offset,
1766 );
1767
1768 for formula_id in all_formula_vertices {
1769 if let Some(formula) = self.get_formula_ast(formula_id) {
1770 let formula_sheet_id = self.graph.get_vertex_sheet_id(formula_id);
1771 if let Some(adjusted) = adjuster.adjust_if_references(&formula, formula_sheet_id) {
1772 self.graph.update_vertex_formula(formula_id, adjusted)?;
1773 }
1774 }
1775 }
1776
1777 Ok(summary)
1778 }
1779
1780 pub fn define_name(
1782 &mut self,
1783 name: &str,
1784 definition: NamedDefinition,
1785 scope: NameScope,
1786 ) -> Result<(), EditorError> {
1787 self.graph.define_name(name, definition.clone(), scope)?;
1788
1789 self.log_change(ChangeEvent::DefineName {
1790 name: name.to_string(),
1791 scope,
1792 definition,
1793 });
1794
1795 Ok(())
1796 }
1797
1798 pub fn define_name_for_cell(
1800 &mut self,
1801 name: &str,
1802 sheet_name: &str,
1803 row: u32,
1804 col: u32,
1805 scope: NameScope,
1806 ) -> Result<(), EditorError> {
1807 let sheet_id = self
1808 .graph
1809 .sheet_id(sheet_name)
1810 .ok_or_else(|| EditorError::InvalidName {
1811 name: sheet_name.to_string(),
1812 reason: "Sheet not found".to_string(),
1813 })?;
1814 let cell_ref = CellRef::new(sheet_id, Coord::from_excel(row, col, true, true));
1815 self.define_name(name, NamedDefinition::Cell(cell_ref), scope)
1816 }
1817
1818 pub fn define_name_for_range(
1820 &mut self,
1821 name: &str,
1822 sheet_name: &str,
1823 start_row: u32,
1824 start_col: u32,
1825 end_row: u32,
1826 end_col: u32,
1827 scope: NameScope,
1828 ) -> Result<(), EditorError> {
1829 let sheet_id = self
1830 .graph
1831 .sheet_id(sheet_name)
1832 .ok_or_else(|| EditorError::InvalidName {
1833 name: sheet_name.to_string(),
1834 reason: "Sheet not found".to_string(),
1835 })?;
1836 let start = CellRef::new(
1837 sheet_id,
1838 Coord::from_excel(start_row, start_col, true, true),
1839 );
1840 let end = CellRef::new(sheet_id, Coord::from_excel(end_row, end_col, true, true));
1841 let range_ref = crate::reference::RangeRef::new(start, end);
1842 self.define_name(name, NamedDefinition::Range(range_ref), scope)
1843 }
1844
1845 pub fn update_name(
1847 &mut self,
1848 name: &str,
1849 new_definition: NamedDefinition,
1850 scope: NameScope,
1851 ) -> Result<(), EditorError> {
1852 let old_definition = self
1854 .graph
1855 .resolve_name(
1856 name,
1857 match scope {
1858 NameScope::Sheet(id) => id,
1859 NameScope::Workbook => 0,
1860 },
1861 )
1862 .cloned();
1863
1864 self.graph
1865 .update_name(name, new_definition.clone(), scope)?;
1866
1867 if let Some(old_def) = old_definition {
1868 self.log_change(ChangeEvent::UpdateName {
1869 name: name.to_string(),
1870 scope,
1871 old_definition: old_def,
1872 new_definition,
1873 });
1874 }
1875
1876 Ok(())
1877 }
1878
1879 pub fn delete_name(&mut self, name: &str, scope: NameScope) -> Result<(), EditorError> {
1881 let old_def = if self.has_logger() {
1883 self.graph
1884 .resolve_name(
1885 name,
1886 match scope {
1887 NameScope::Sheet(id) => id,
1888 NameScope::Workbook => 0,
1889 },
1890 )
1891 .cloned()
1892 } else {
1893 None
1894 };
1895
1896 self.graph.delete_name(name, scope)?;
1897 self.log_change(ChangeEvent::DeleteName {
1898 name: name.to_string(),
1899 scope,
1900 old_definition: old_def,
1901 });
1902
1903 Ok(())
1904 }
1905}
1906
1907enum CellData {
1909 Value(LiteralValue),
1910 Formula(ASTNode),
1911}
1912
1913impl<'g> Drop for VertexEditor<'g> {
1914 fn drop(&mut self) {
1915 if self.batch_mode {
1917 self.commit_batch();
1918 }
1919 }
1920}
1921
1922#[cfg(test)]
1923mod tests {
1924 use super::*;
1925 use crate::engine::graph::editor::change_log::{ChangeEvent, ChangeLog};
1926 use crate::reference::Coord;
1927
1928 fn create_test_graph() -> DependencyGraph {
1929 DependencyGraph::new()
1930 }
1931
1932 #[test]
1933 fn test_vertex_editor_creation() {
1934 let mut graph = create_test_graph();
1935 let editor = VertexEditor::new(&mut graph);
1936 assert!(!editor.has_logger());
1937 assert!(!editor.batch_mode);
1938 }
1939
1940 #[test]
1941 fn test_vertex_editor_with_logger() {
1942 let mut graph = create_test_graph();
1943 let mut log = ChangeLog::new();
1944 let editor = VertexEditor::with_logger(&mut graph, &mut log);
1945 assert!(editor.has_logger());
1946 assert!(!editor.batch_mode);
1947 }
1948
1949 #[test]
1950 fn test_add_vertex() {
1951 let mut graph = create_test_graph();
1952 let mut editor = VertexEditor::new(&mut graph);
1953
1954 let meta = VertexMeta::new(5, 10, 0, VertexKind::Cell).dirty();
1955 let vertex_id = editor.add_vertex(meta);
1956
1957 assert!(vertex_id.0 > 0);
1959 }
1960
1961 #[test]
1962 fn test_batch_operations() {
1963 let mut graph = create_test_graph();
1964 let mut editor = VertexEditor::new(&mut graph);
1965
1966 assert!(!editor.batch_mode);
1967 editor.begin_batch();
1968 assert!(editor.batch_mode);
1969
1970 let meta1 = VertexMeta::new(1, 1, 0, VertexKind::Cell);
1972 let meta2 = VertexMeta::new(2, 2, 0, VertexKind::Cell);
1973
1974 let id1 = editor.add_vertex(meta1);
1975 let id2 = editor.add_vertex(meta2);
1976
1977 assert!(editor.add_edge(id1, id2));
1979
1980 editor.commit_batch();
1981 assert!(!editor.batch_mode);
1982 }
1983
1984 #[test]
1985 fn test_remove_vertex() {
1986 let mut graph = create_test_graph();
1987 let mut editor = VertexEditor::new(&mut graph);
1988
1989 let meta = VertexMeta::new(3, 4, 0, VertexKind::Cell).dirty();
1990 let vertex_id = editor.add_vertex(meta);
1991
1992 assert!(editor.remove_vertex(vertex_id).is_ok());
1994 }
1995
1996 #[test]
1997 fn test_remove_vertex_clears_spill_registry_for_anchor() {
1998 let mut graph = create_test_graph();
1999 let sheet_id = graph.sheet_id_mut("Sheet1");
2000
2001 let anchor_cell = CellRef::new(sheet_id, Coord::new(0, 0, true, true));
2003 let anchor_vid = {
2004 let mut editor = VertexEditor::new(&mut graph);
2005 editor.set_cell_value(anchor_cell, LiteralValue::Number(0.0))
2006 };
2007
2008 let target_cells = vec![
2009 CellRef::new(sheet_id, Coord::new(0, 0, true, true)),
2010 CellRef::new(sheet_id, Coord::new(0, 1, true, true)),
2011 CellRef::new(sheet_id, Coord::new(1, 0, true, true)),
2012 CellRef::new(sheet_id, Coord::new(1, 1, true, true)),
2013 ];
2014 let values = vec![
2015 vec![LiteralValue::Number(1.0), LiteralValue::Number(2.0)],
2016 vec![LiteralValue::Number(3.0), LiteralValue::Number(4.0)],
2017 ];
2018
2019 graph
2020 .commit_spill_region_atomic_with_fault(anchor_vid, target_cells.clone(), values, None)
2021 .unwrap();
2022
2023 assert!(graph.spill_registry_has_anchor(anchor_vid));
2024 for cell in &target_cells {
2025 assert_eq!(
2026 graph.spill_registry_anchor_for_cell(*cell),
2027 Some(anchor_vid)
2028 );
2029 }
2030
2031 {
2032 let mut editor = VertexEditor::new(&mut graph);
2033 editor.remove_vertex(anchor_vid).unwrap();
2034 }
2035
2036 assert!(!graph.spill_registry_has_anchor(anchor_vid));
2037 for cell in &target_cells {
2038 assert_eq!(graph.spill_registry_anchor_for_cell(*cell), None);
2039 }
2040 assert_eq!(graph.spill_registry_counts(), (0, 0));
2041 }
2042
2043 #[test]
2044 fn test_edge_operations() {
2045 let mut graph = create_test_graph();
2046 let mut editor = VertexEditor::new(&mut graph);
2047
2048 let meta1 = VertexMeta::new(1, 1, 0, VertexKind::Cell);
2049 let meta2 = VertexMeta::new(2, 2, 0, VertexKind::FormulaScalar);
2050
2051 let id1 = editor.add_vertex(meta1);
2052 let id2 = editor.add_vertex(meta2);
2053
2054 assert!(editor.add_edge(id1, id2));
2056
2057 assert!(!editor.add_edge(id1, id1));
2059
2060 assert!(editor.remove_edge(id1, id2));
2062 }
2063
2064 #[test]
2065 fn test_set_cell_value() {
2066 let mut graph = create_test_graph();
2067 let mut log = ChangeLog::new();
2068
2069 let cell_ref = CellRef {
2070 sheet_id: 0,
2071 coord: Coord::new(2, 3, true, true),
2072 };
2073 let value = LiteralValue::Number(42.0);
2074
2075 let vertex_id = {
2076 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2077 editor.set_cell_value(cell_ref, value.clone())
2078 };
2079
2080 assert!(vertex_id.0 > 0);
2082
2083 assert_eq!(log.len(), 1);
2085 match &log.events()[0] {
2086 ChangeEvent::SetValue { addr, new, .. } => {
2087 assert_eq!(addr.sheet_id, cell_ref.sheet_id);
2088 assert_eq!(addr.coord.row(), cell_ref.coord.row());
2089 assert_eq!(addr.coord.col(), cell_ref.coord.col());
2090 assert_eq!(new, &value);
2091 }
2092 _ => panic!("Expected SetValue event"),
2093 }
2094 }
2095
2096 #[test]
2097 fn test_set_cell_formula() {
2098 let mut graph = create_test_graph();
2099 let mut log = ChangeLog::new();
2100
2101 let cell_ref = CellRef {
2102 sheet_id: 0,
2103 coord: Coord::new(1, 1, true, true),
2104 };
2105
2106 use formualizer_parse::parser::ASTNodeType;
2107 let formula = formualizer_parse::parser::ASTNode {
2108 node_type: ASTNodeType::Literal(LiteralValue::Number(100.0)),
2109 source_token: None,
2110 contains_volatile: false,
2111 };
2112
2113 let vertex_id = {
2114 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2115 editor.set_cell_formula(cell_ref, formula.clone())
2116 };
2117
2118 assert!(vertex_id.0 > 0);
2120
2121 assert_eq!(log.len(), 1);
2123 match &log.events()[0] {
2124 ChangeEvent::SetFormula { addr, .. } => {
2125 assert_eq!(addr.sheet_id, cell_ref.sheet_id);
2126 assert_eq!(addr.coord.row(), cell_ref.coord.row());
2127 assert_eq!(addr.coord.col(), cell_ref.coord.col());
2128 }
2129 _ => panic!("Expected SetFormula event"),
2130 }
2131 }
2132
2133 #[test]
2134 fn test_shift_rows() {
2135 let mut graph = create_test_graph();
2136 let mut log = ChangeLog::new();
2137
2138 {
2139 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2140
2141 let cell1 = CellRef {
2143 sheet_id: 0,
2144 coord: Coord::new(5, 1, true, true),
2145 };
2146 let cell2 = CellRef {
2147 sheet_id: 0,
2148 coord: Coord::new(10, 1, true, true),
2149 };
2150 let cell3 = CellRef {
2151 sheet_id: 0,
2152 coord: Coord::new(15, 1, true, true),
2153 };
2154
2155 editor.set_cell_value(cell1, LiteralValue::Number(1.0));
2156 editor.set_cell_value(cell2, LiteralValue::Number(2.0));
2157 editor.set_cell_value(cell3, LiteralValue::Number(3.0));
2158 }
2159
2160 log.clear();
2162
2163 {
2164 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2165 editor.shift_rows(0, 10, 2);
2167 }
2168
2169 assert_eq!(log.len(), 1);
2171 match &log.events()[0] {
2172 ChangeEvent::SetValue { addr, new, .. } => {
2173 assert_eq!(addr.sheet_id, 0);
2174 assert_eq!(addr.coord.row(), 10);
2175 if let LiteralValue::Text(msg) = new {
2176 assert!(msg.contains("Row shift"));
2177 assert!(msg.contains("start=10"));
2178 assert!(msg.contains("delta=2"));
2179 }
2180 }
2181 _ => panic!("Expected SetValue event for row shift"),
2182 }
2183 }
2184
2185 #[test]
2186 fn test_shift_columns() {
2187 let mut graph = create_test_graph();
2188 let mut log = ChangeLog::new();
2189
2190 {
2191 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2192
2193 let cell1 = CellRef {
2195 sheet_id: 0,
2196 coord: Coord::new(1, 5, true, true),
2197 };
2198 let cell2 = CellRef {
2199 sheet_id: 0,
2200 coord: Coord::new(1, 10, true, true),
2201 };
2202
2203 editor.set_cell_value(cell1, LiteralValue::Number(1.0));
2204 editor.set_cell_value(cell2, LiteralValue::Number(2.0));
2205 }
2206
2207 log.clear();
2209
2210 {
2211 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2212 editor.shift_columns(0, 8, 3);
2214 }
2215
2216 assert_eq!(log.len(), 1);
2218 match &log.events()[0] {
2219 ChangeEvent::SetValue { addr, new, .. } => {
2220 assert_eq!(addr.sheet_id, 0);
2221 assert_eq!(addr.coord.col(), 8);
2222 if let LiteralValue::Text(msg) = new {
2223 assert!(msg.contains("Column shift"));
2224 assert!(msg.contains("start=8"));
2225 assert!(msg.contains("delta=3"));
2226 }
2227 }
2228 _ => panic!("Expected SetValue event for column shift"),
2229 }
2230 }
2231
2232 #[test]
2233 fn test_move_vertex() {
2234 let mut graph = create_test_graph();
2235 let mut editor = VertexEditor::new(&mut graph);
2236
2237 let meta = VertexMeta::new(5, 10, 0, VertexKind::Cell);
2238 let vertex_id = editor.add_vertex(meta);
2239
2240 assert!(editor.move_vertex(vertex_id, AbsCoord::new(8, 12)).is_ok());
2242
2243 assert!(editor.move_vertex(vertex_id, AbsCoord::new(8, 12)).is_ok());
2245 }
2246
2247 #[test]
2248 fn test_vertex_meta_builder() {
2249 let meta = VertexMeta::new(1, 2, 3, VertexKind::FormulaScalar)
2250 .dirty()
2251 .volatile()
2252 .with_flags(0x08);
2253
2254 assert_eq!(meta.coord.row(), 1);
2255 assert_eq!(meta.coord.col(), 2);
2256 assert_eq!(meta.sheet_id, 3);
2257 assert_eq!(meta.kind, VertexKind::FormulaScalar);
2258 assert_eq!(meta.flags, 0x08); }
2260
2261 #[test]
2262 fn test_change_log_management() {
2263 let mut graph = create_test_graph();
2264 let mut log = ChangeLog::new();
2265
2266 {
2267 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2268 let cell_ref = CellRef {
2269 sheet_id: 0,
2270 coord: Coord::new(0, 0, true, true),
2271 };
2272 editor.set_cell_value(cell_ref, LiteralValue::Number(1.0));
2273 editor.set_cell_value(cell_ref, LiteralValue::Number(2.0));
2274 }
2275
2276 assert_eq!(log.len(), 2);
2277
2278 log.clear();
2279 assert_eq!(log.len(), 0);
2280 }
2281
2282 #[test]
2283 fn test_editor_drop_commits_batch() {
2284 let mut graph = create_test_graph();
2285 {
2286 let mut editor = VertexEditor::new(&mut graph);
2287 editor.begin_batch();
2288
2289 let meta = VertexMeta::new(1, 1, 0, VertexKind::Cell);
2290 editor.add_vertex(meta);
2291
2292 }
2294
2295 }
2297}