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::AddVertex { id, .. } => {
442 let _ = self.remove_vertex(id); }
445 ChangeEvent::RemoveVertex {
446 id: _,
447 old_value,
448 old_formula,
449 old_dependencies,
450 old_dependents,
451 coord,
452 sheet_id,
453 kind,
454 ..
455 } => {
456 if let (Some(c), Some(sid)) = (coord, sheet_id) {
457 let meta =
458 VertexMeta::new(c.row(), c.col(), sid, kind.unwrap_or(VertexKind::Cell));
459 let new_id = self.add_vertex(meta);
460 if let Some(v) = old_value {
461 let cell_ref = self.graph.make_cell_ref_internal(sid, c.row(), c.col());
462 self.set_cell_value(cell_ref, v);
463 }
464 if let Some(f) = old_formula {
465 let cell_ref = self.graph.make_cell_ref_internal(sid, c.row(), c.col());
466 self.set_cell_formula(cell_ref, f);
467 }
468 for dep in old_dependencies {
469 self.graph.add_dependency_edge(new_id, dep);
470 }
471 for parent in old_dependents {
472 self.graph.add_dependency_edge(parent, new_id);
473 }
474 }
475 }
476 ChangeEvent::DefineName { name, scope, .. } => {
477 self.graph.delete_name(&name, scope)?;
479 }
480 ChangeEvent::UpdateName {
481 name,
482 scope,
483 old_definition,
484 ..
485 } => {
486 self.graph.update_name(&name, old_definition, scope)?;
488 }
489 ChangeEvent::DeleteName {
490 name,
491 scope,
492 old_definition,
493 } => {
494 if let Some(def) = old_definition {
495 self.graph.define_name(&name, def, scope)?;
496 } else {
497 return Err(EditorError::TransactionFailed {
498 reason: "Missing old definition for name deletion rollback".to_string(),
499 });
500 }
501 }
502 ChangeEvent::SpillCommitted { anchor, old, .. } => {
503 if let Some(old) = old {
505 self.graph
506 .commit_spill_region_atomic_with_fault(
507 anchor,
508 old.target_cells,
509 old.values,
510 None,
511 )
512 .map_err(EditorError::Excel)?;
513 } else {
514 self.graph.clear_spill_region(anchor);
515 }
516 }
517 ChangeEvent::SpillCleared { anchor, old } => {
518 self.graph
520 .commit_spill_region_atomic_with_fault(
521 anchor,
522 old.target_cells,
523 old.values,
524 None,
525 )
526 .map_err(EditorError::Excel)?;
527 }
528 ChangeEvent::CompoundStart { .. } | ChangeEvent::CompoundEnd { .. } => {
530 }
532 ChangeEvent::VertexMoved {
533 id,
534 sheet_id: _,
535 old_coord,
536 ..
537 } => {
538 self.move_vertex(id, old_coord)?;
540 }
541 ChangeEvent::FormulaAdjusted { id, old_ast, .. } => {
542 self.graph
544 .update_vertex_formula(id, old_ast)
545 .map_err(EditorError::Excel)?;
546 self.graph.mark_vertex_dirty(id);
547 }
548 ChangeEvent::NamedRangeAdjusted {
549 name,
550 scope,
551 old_definition,
552 ..
553 } => {
554 self.graph.update_name(&name, old_definition, scope)?;
556 }
557 ChangeEvent::EdgeAdded { from, to } => {
558 return Err(EditorError::TransactionFailed {
561 reason: "Cannot rollback edge addition yet".to_string(),
562 });
563 }
564 ChangeEvent::EdgeRemoved { from, to } => {
565 return Err(EditorError::TransactionFailed {
568 reason: "Cannot rollback edge removal yet".to_string(),
569 });
570 }
571 }
572 Ok(())
573 }
574
575 pub fn add_vertex(&mut self, meta: VertexMeta) -> VertexId {
577 let sheet_name = self.graph.sheet_name(meta.sheet_id).to_string();
580
581 let id = match meta.kind {
582 VertexKind::Cell => {
583 match self.graph.set_cell_value(
587 &sheet_name,
588 meta.coord.row() + 1,
589 meta.coord.col() + 1,
590 LiteralValue::Empty,
591 ) {
592 Ok(summary) => summary
593 .affected_vertices
594 .into_iter()
595 .next()
596 .unwrap_or(VertexId::new(0)),
597 Err(_) => VertexId::new(0),
598 }
599 }
600 _ => {
601 match self.graph.set_cell_value(
605 &sheet_name,
606 meta.coord.row() + 1,
607 meta.coord.col() + 1,
608 LiteralValue::Empty,
609 ) {
610 Ok(summary) => summary
611 .affected_vertices
612 .into_iter()
613 .next()
614 .unwrap_or(VertexId::new(0)),
615 Err(_) => VertexId::new(0),
616 }
617 }
618 };
619
620 if self.has_logger() && id.0 != 0 {
621 self.log_change(ChangeEvent::AddVertex {
622 id,
623 coord: meta.coord,
624 sheet_id: meta.sheet_id,
625 value: Some(LiteralValue::Empty),
626 formula: None,
627 kind: Some(meta.kind),
628 flags: Some(meta.flags),
629 });
630 }
631 id
632 }
633
634 pub fn remove_vertex(&mut self, id: VertexId) -> Result<(), EditorError> {
636 if !self.graph.vertex_exists(id) {
638 return Err(EditorError::Excel(
639 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
640 ));
641 }
642
643 let spill_snapshot = self.snapshot_spill_for_anchor(id);
646 let did_spill_clear = spill_snapshot.is_some();
647 if let Some(old_spill) = spill_snapshot {
648 if let Some(logger) = &mut self.change_logger {
649 logger.begin_compound(format!("RemoveVertexWithSpillClear id={}", id.0));
650 }
651 self.graph.clear_spill_region(id);
652 self.log_change(ChangeEvent::SpillCleared {
653 anchor: id,
654 old: old_spill,
655 });
656 }
657
658 let dependents = self.graph.get_dependents(id);
661
662 let (
664 old_value,
665 old_formula,
666 old_dependencies,
667 old_dependents,
668 coord,
669 sheet_id_opt,
670 kind,
671 flags,
672 ) = if self.has_logger() {
673 let coord = self.graph.get_coord(id);
674 let sheet_id = self.graph.get_sheet_id(id);
675 let kind = self.graph.get_vertex_kind(id);
676 let flags = 0u8;
678 (
679 self.graph.get_value(id),
680 self.get_formula_ast(id),
681 self.graph.get_dependencies(id), dependents.clone(), Some(coord),
684 Some(sheet_id),
685 Some(kind),
686 Some(flags),
687 )
688 } else {
689 (None, None, vec![], vec![], None, None, None, None)
690 };
691
692 if let Some(cell_ref) = self.graph.get_cell_ref_for_vertex(id) {
694 self.graph.remove_cell_mapping(&cell_ref);
695 }
696
697 self.graph.remove_all_edges(id);
699
700 for dep_id in &dependents {
702 self.graph.mark_as_ref_error(*dep_id);
703 }
704
705 self.graph.mark_deleted(id, true);
707
708 self.log_change(ChangeEvent::RemoveVertex {
710 id,
711 old_value,
712 old_formula,
713 old_dependencies,
714 old_dependents,
715 coord,
716 sheet_id: sheet_id_opt,
717 kind,
718 flags,
719 });
720
721 if did_spill_clear && let Some(logger) = &mut self.change_logger {
722 logger.end_compound();
723 }
724
725 Ok(())
726 }
727
728 pub fn remove_vertex_at(&mut self, cell: CellRef) -> Result<(), EditorError> {
730 if let Some(id) = self.graph.get_vertex_for_cell(&cell) {
731 self.remove_vertex(id)
732 } else {
733 Ok(())
734 }
735 }
736
737 pub fn move_vertex(&mut self, id: VertexId, new_coord: AbsCoord) -> Result<(), EditorError> {
739 if !self.graph.vertex_exists(id) {
741 return Err(EditorError::Excel(
742 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
743 ));
744 }
745
746 let old_cell_ref = self.graph.get_cell_ref_for_vertex(id);
748
749 let sheet_id = self.graph.get_sheet_id(id);
751 let new_cell_ref = CellRef::new(
752 sheet_id,
753 Coord::new(new_coord.row(), new_coord.col(), true, true),
754 );
755
756 self.graph.set_coord(id, new_coord);
758
759 self.graph.update_edge_coord(id, new_coord);
761
762 self.graph
764 .update_cell_mapping(id, old_cell_ref, new_cell_ref);
765
766 self.graph.mark_dependents_dirty(id);
768
769 Ok(())
770 }
771
772 pub fn patch_vertex_meta(
774 &mut self,
775 id: VertexId,
776 patch: VertexMetaPatch,
777 ) -> Result<MetaUpdateSummary, EditorError> {
778 if !self.graph.vertex_exists(id) {
779 return Err(EditorError::Excel(
780 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
781 ));
782 }
783
784 let mut summary = MetaUpdateSummary::default();
785
786 if let Some(coord) = patch.coord {
787 self.graph.set_coord(id, coord);
788 self.graph.update_edge_coord(id, coord);
789 summary.coord_changed = true;
790 }
791
792 if let Some(kind) = patch.kind {
793 self.graph.set_kind(id, kind);
794 summary.kind_changed = true;
795 }
796
797 if let Some(dirty) = patch.dirty {
798 self.graph.set_dirty(id, dirty);
799 summary.flags_changed = true;
800 }
801
802 if let Some(volatile) = patch.volatile {
803 self.graph.mark_volatile(id, volatile);
804 summary.flags_changed = true;
805 }
806
807 Ok(summary)
808 }
809
810 pub fn patch_vertex_data(
812 &mut self,
813 id: VertexId,
814 patch: VertexDataPatch,
815 ) -> Result<DataUpdateSummary, EditorError> {
816 if !self.graph.vertex_exists(id) {
817 return Err(EditorError::Excel(
818 ExcelError::new(ExcelErrorKind::Ref).with_message("Vertex does not exist"),
819 ));
820 }
821
822 let mut summary = DataUpdateSummary::default();
823
824 if let Some(value) = patch.value {
825 self.graph.update_vertex_value(id, value);
826 summary.value_changed = true;
827
828 if self.graph.edges_delta_size() > 0 {
831 self.graph.rebuild_edges();
832 }
833
834 let dependents = self.graph.get_dependents(id);
836 for dep in &dependents {
837 self.graph.set_dirty(*dep, true);
838 }
839 summary.dependents_marked_dirty = dependents;
840 }
841
842 if let Some(_formula) = patch.formula {
843 summary.formula_changed = true;
846 }
847
848 Ok(summary)
849 }
850
851 pub fn add_edge(&mut self, from: VertexId, to: VertexId) -> bool {
853 if from == to {
854 return false; }
856
857 true
860 }
861
862 pub fn remove_edge(&mut self, _from: VertexId, _to: VertexId) -> bool {
864 true
866 }
867
868 pub fn insert_rows(
870 &mut self,
871 sheet_id: SheetId,
872 before: u32,
873 count: u32,
874 ) -> Result<ShiftSummary, EditorError> {
875 if count == 0 {
876 return Ok(ShiftSummary::default());
877 }
878
879 let mut summary = ShiftSummary::default();
880
881 self.begin_batch();
883
884 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
886 .graph
887 .vertices_in_sheet(sheet_id)
888 .filter_map(|id| {
889 let coord = self.graph.get_coord(id);
890 if coord.row() >= before {
891 Some((id, coord))
892 } else {
893 None
894 }
895 })
896 .collect();
897
898 if let Some(logger) = &mut self.change_logger {
899 logger.begin_compound(format!(
900 "InsertRows sheet={sheet_id} before={before} count={count}"
901 ));
902 }
903 for (id, old_coord) in vertices_to_shift {
905 let new_coord = AbsCoord::new(old_coord.row() + count, old_coord.col());
906 if self.has_logger() {
907 self.log_change(ChangeEvent::VertexMoved {
908 id,
909 sheet_id,
910 old_coord,
911 new_coord,
912 });
913 }
914 self.move_vertex(id, new_coord)?;
915 summary.vertices_moved.push(id);
916 }
917
918 let op = ShiftOperation::InsertRows {
920 sheet_id,
921 before,
922 count,
923 };
924 let adjuster = ReferenceAdjuster::new();
925
926 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
928
929 for id in formula_vertices {
930 if let Some(ast) = self.get_formula_ast(id) {
931 let adjusted = adjuster.adjust_ast(&ast, &op);
932 if format!("{ast:?}") != format!("{adjusted:?}") {
934 if self.has_logger() {
935 self.log_change(ChangeEvent::FormulaAdjusted {
936 id,
937 addr: self.graph.get_cell_ref_for_vertex(id),
938 old_ast: ast.clone(),
939 new_ast: adjusted.clone(),
940 });
941 }
942 self.graph.update_vertex_formula(id, adjusted)?;
943 self.graph.mark_vertex_dirty(id);
944 summary.formulas_updated += 1;
945 }
946 }
947 }
948
949 let old_names = if self.has_logger() {
951 Some(self.snapshot_named_definitions())
952 } else {
953 None
954 };
955 self.graph.adjust_named_ranges(&op)?;
956 if let Some(old_names) = old_names {
957 let new_names = self.snapshot_named_definitions();
958 for ((scope, name), old_definition) in old_names {
959 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
960 && *new_definition != old_definition
961 {
962 self.log_change(ChangeEvent::NamedRangeAdjusted {
963 name,
964 scope,
965 old_definition,
966 new_definition: new_definition.clone(),
967 });
968 }
969 }
970 }
971
972 if let Some(logger) = &mut self.change_logger {
974 logger.end_compound();
975 }
976
977 self.commit_batch();
978
979 Ok(summary)
980 }
981
982 pub fn delete_rows(
984 &mut self,
985 sheet_id: SheetId,
986 start: u32,
987 count: u32,
988 ) -> Result<ShiftSummary, EditorError> {
989 if count == 0 {
990 return Ok(ShiftSummary::default());
991 }
992
993 let mut summary = ShiftSummary::default();
994
995 self.begin_batch();
996
997 if let Some(logger) = &mut self.change_logger {
998 logger.begin_compound(format!(
999 "DeleteRows sheet={sheet_id} start={start} count={count}"
1000 ));
1001 }
1002
1003 let vertices_to_delete: Vec<VertexId> = self
1005 .graph
1006 .vertices_in_sheet(sheet_id)
1007 .filter(|&id| {
1008 let coord = self.graph.get_coord(id);
1009 coord.row() >= start && coord.row() < start + count
1010 })
1011 .collect();
1012
1013 for id in vertices_to_delete {
1014 self.remove_vertex(id)?;
1015 summary.vertices_deleted.push(id);
1016 }
1017 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
1019 .graph
1020 .vertices_in_sheet(sheet_id)
1021 .filter_map(|id| {
1022 let coord = self.graph.get_coord(id);
1023 if coord.row() >= start + count {
1024 Some((id, coord))
1025 } else {
1026 None
1027 }
1028 })
1029 .collect();
1030
1031 for (id, old_coord) in vertices_to_shift {
1032 let new_coord = AbsCoord::new(old_coord.row() - count, old_coord.col());
1033 if self.has_logger() {
1034 self.log_change(ChangeEvent::VertexMoved {
1035 id,
1036 sheet_id,
1037 old_coord,
1038 new_coord,
1039 });
1040 }
1041 self.move_vertex(id, new_coord)?;
1042 summary.vertices_moved.push(id);
1043 }
1044
1045 let op = ShiftOperation::DeleteRows {
1047 sheet_id,
1048 start,
1049 count,
1050 };
1051 let adjuster = ReferenceAdjuster::new();
1052
1053 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
1054
1055 for id in formula_vertices {
1056 if let Some(ast) = self.get_formula_ast(id) {
1057 let adjusted = adjuster.adjust_ast(&ast, &op);
1058 if format!("{ast:?}") != format!("{adjusted:?}") {
1059 if self.has_logger() {
1060 self.log_change(ChangeEvent::FormulaAdjusted {
1061 id,
1062 addr: self.graph.get_cell_ref_for_vertex(id),
1063 old_ast: ast.clone(),
1064 new_ast: adjusted.clone(),
1065 });
1066 }
1067 self.graph.update_vertex_formula(id, adjusted)?;
1068 self.graph.mark_vertex_dirty(id);
1069 summary.formulas_updated += 1;
1070 }
1071 }
1072 }
1073
1074 let old_names = if self.has_logger() {
1076 Some(self.snapshot_named_definitions())
1077 } else {
1078 None
1079 };
1080 self.graph.adjust_named_ranges(&op)?;
1081 if let Some(old_names) = old_names {
1082 let new_names = self.snapshot_named_definitions();
1083 for ((scope, name), old_definition) in old_names {
1084 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
1085 && *new_definition != old_definition
1086 {
1087 self.log_change(ChangeEvent::NamedRangeAdjusted {
1088 name,
1089 scope,
1090 old_definition,
1091 new_definition: new_definition.clone(),
1092 });
1093 }
1094 }
1095 }
1096
1097 if let Some(logger) = &mut self.change_logger {
1099 logger.end_compound();
1100 }
1101
1102 self.commit_batch();
1103
1104 Ok(summary)
1105 }
1106
1107 pub fn insert_columns(
1109 &mut self,
1110 sheet_id: SheetId,
1111 before: u32,
1112 count: u32,
1113 ) -> Result<ShiftSummary, EditorError> {
1114 if count == 0 {
1115 return Ok(ShiftSummary::default());
1116 }
1117
1118 let mut summary = ShiftSummary::default();
1119
1120 self.begin_batch();
1122
1123 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
1125 .graph
1126 .vertices_in_sheet(sheet_id)
1127 .filter_map(|id| {
1128 let coord = self.graph.get_coord(id);
1129 if coord.col() >= before {
1130 Some((id, coord))
1131 } else {
1132 None
1133 }
1134 })
1135 .collect();
1136
1137 if let Some(logger) = &mut self.change_logger {
1138 logger.begin_compound(format!(
1139 "InsertColumns sheet={sheet_id} before={before} count={count}"
1140 ));
1141 }
1142 for (id, old_coord) in vertices_to_shift {
1144 let new_coord = AbsCoord::new(old_coord.row(), old_coord.col() + count);
1145 if self.has_logger() {
1146 self.log_change(ChangeEvent::VertexMoved {
1147 id,
1148 sheet_id,
1149 old_coord,
1150 new_coord,
1151 });
1152 }
1153 self.move_vertex(id, new_coord)?;
1154 summary.vertices_moved.push(id);
1155 }
1156
1157 let op = ShiftOperation::InsertColumns {
1159 sheet_id,
1160 before,
1161 count,
1162 };
1163 let adjuster = ReferenceAdjuster::new();
1164
1165 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
1167
1168 for id in formula_vertices {
1169 if let Some(ast) = self.get_formula_ast(id) {
1170 let adjusted = adjuster.adjust_ast(&ast, &op);
1171 if format!("{ast:?}") != format!("{adjusted:?}") {
1173 if self.has_logger() {
1174 self.log_change(ChangeEvent::FormulaAdjusted {
1175 id,
1176 addr: self.graph.get_cell_ref_for_vertex(id),
1177 old_ast: ast.clone(),
1178 new_ast: adjusted.clone(),
1179 });
1180 }
1181 self.graph.update_vertex_formula(id, adjusted)?;
1182 self.graph.mark_vertex_dirty(id);
1183 summary.formulas_updated += 1;
1184 }
1185 }
1186 }
1187
1188 let old_names = if self.has_logger() {
1190 Some(self.snapshot_named_definitions())
1191 } else {
1192 None
1193 };
1194 self.graph.adjust_named_ranges(&op)?;
1195 if let Some(old_names) = old_names {
1196 let new_names = self.snapshot_named_definitions();
1197 for ((scope, name), old_definition) in old_names {
1198 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
1199 && *new_definition != old_definition
1200 {
1201 self.log_change(ChangeEvent::NamedRangeAdjusted {
1202 name,
1203 scope,
1204 old_definition,
1205 new_definition: new_definition.clone(),
1206 });
1207 }
1208 }
1209 }
1210
1211 if let Some(logger) = &mut self.change_logger {
1213 logger.end_compound();
1214 }
1215
1216 self.commit_batch();
1217
1218 Ok(summary)
1219 }
1220
1221 pub fn delete_columns(
1223 &mut self,
1224 sheet_id: SheetId,
1225 start: u32,
1226 count: u32,
1227 ) -> Result<ShiftSummary, EditorError> {
1228 if count == 0 {
1229 return Ok(ShiftSummary::default());
1230 }
1231
1232 let mut summary = ShiftSummary::default();
1233
1234 self.begin_batch();
1235
1236 if let Some(logger) = &mut self.change_logger {
1237 logger.begin_compound(format!(
1238 "DeleteColumns sheet={sheet_id} start={start} count={count}"
1239 ));
1240 }
1241
1242 let vertices_to_delete: Vec<VertexId> = self
1244 .graph
1245 .vertices_in_sheet(sheet_id)
1246 .filter(|&id| {
1247 let coord = self.graph.get_coord(id);
1248 coord.col() >= start && coord.col() < start + count
1249 })
1250 .collect();
1251
1252 for id in vertices_to_delete {
1253 self.remove_vertex(id)?;
1254 summary.vertices_deleted.push(id);
1255 }
1256 let vertices_to_shift: Vec<(VertexId, AbsCoord)> = self
1258 .graph
1259 .vertices_in_sheet(sheet_id)
1260 .filter_map(|id| {
1261 let coord = self.graph.get_coord(id);
1262 if coord.col() >= start + count {
1263 Some((id, coord))
1264 } else {
1265 None
1266 }
1267 })
1268 .collect();
1269
1270 for (id, old_coord) in vertices_to_shift {
1271 let new_coord = AbsCoord::new(old_coord.row(), old_coord.col() - count);
1272 if self.has_logger() {
1273 self.log_change(ChangeEvent::VertexMoved {
1274 id,
1275 sheet_id,
1276 old_coord,
1277 new_coord,
1278 });
1279 }
1280 self.move_vertex(id, new_coord)?;
1281 summary.vertices_moved.push(id);
1282 }
1283
1284 let op = ShiftOperation::DeleteColumns {
1286 sheet_id,
1287 start,
1288 count,
1289 };
1290 let adjuster = ReferenceAdjuster::new();
1291
1292 let formula_vertices: Vec<VertexId> = self.graph.vertices_with_formulas().collect();
1293
1294 for id in formula_vertices {
1295 if let Some(ast) = self.get_formula_ast(id) {
1296 let adjusted = adjuster.adjust_ast(&ast, &op);
1297 if format!("{ast:?}") != format!("{adjusted:?}") {
1298 if self.has_logger() {
1299 self.log_change(ChangeEvent::FormulaAdjusted {
1300 id,
1301 addr: self.graph.get_cell_ref_for_vertex(id),
1302 old_ast: ast.clone(),
1303 new_ast: adjusted.clone(),
1304 });
1305 }
1306 self.graph.update_vertex_formula(id, adjusted)?;
1307 self.graph.mark_vertex_dirty(id);
1308 summary.formulas_updated += 1;
1309 }
1310 }
1311 }
1312
1313 let old_names = if self.has_logger() {
1315 Some(self.snapshot_named_definitions())
1316 } else {
1317 None
1318 };
1319 self.graph.adjust_named_ranges(&op)?;
1320 if let Some(old_names) = old_names {
1321 let new_names = self.snapshot_named_definitions();
1322 for ((scope, name), old_definition) in old_names {
1323 if let Some(new_definition) = new_names.get(&(scope, name.clone()))
1324 && *new_definition != old_definition
1325 {
1326 self.log_change(ChangeEvent::NamedRangeAdjusted {
1327 name,
1328 scope,
1329 old_definition,
1330 new_definition: new_definition.clone(),
1331 });
1332 }
1333 }
1334 }
1335
1336 if let Some(logger) = &mut self.change_logger {
1338 logger.end_compound();
1339 }
1340
1341 self.commit_batch();
1342
1343 Ok(summary)
1344 }
1345
1346 pub fn shift_rows(&mut self, sheet_id: SheetId, start_row: u32, delta: i32) {
1348 if delta == 0 {
1349 return;
1350 }
1351
1352 let change_event = ChangeEvent::SetValue {
1354 addr: CellRef {
1355 sheet_id,
1356 coord: Coord::new(start_row, 0, true, true),
1357 },
1358 old_value: None,
1359 old_formula: None,
1360 new: LiteralValue::Text(format!("Row shift: start={start_row}, delta={delta}")),
1361 };
1362 self.log_change(change_event);
1363
1364 }
1367
1368 pub fn shift_columns(&mut self, sheet_id: SheetId, start_col: u32, delta: i32) {
1370 if delta == 0 {
1371 return;
1372 }
1373
1374 let change_event = ChangeEvent::SetValue {
1376 addr: CellRef {
1377 sheet_id,
1378 coord: Coord::new(0, start_col, true, true),
1379 },
1380 old_value: None,
1381 old_formula: None,
1382 new: LiteralValue::Text(format!("Column shift: start={start_col}, delta={delta}")),
1383 };
1384 self.log_change(change_event);
1385
1386 }
1389
1390 pub fn set_cell_value(&mut self, cell_ref: CellRef, value: LiteralValue) -> VertexId {
1392 let sheet_name = self.graph.sheet_name(cell_ref.sheet_id).to_string();
1393
1394 let old_id = self.graph.get_vertex_id_for_address(&cell_ref).copied();
1396 let old_value = old_id.and_then(|id| self.graph.get_value(id));
1397 let old_formula = old_id.and_then(|id| self.get_formula_ast(id));
1398
1399 let spill_snapshot =
1402 old_id.and_then(|id| self.snapshot_spill_for_anchor(id).map(|s| (id, s)));
1403 let did_spill_clear = spill_snapshot.is_some();
1404 if let Some((anchor, old_spill)) = spill_snapshot {
1405 if let Some(logger) = &mut self.change_logger {
1406 logger.begin_compound(format!(
1407 "SetValueWithSpillClear sheet={} row={} col={}",
1408 cell_ref.sheet_id,
1409 cell_ref.coord.row(),
1410 cell_ref.coord.col()
1411 ));
1412 }
1413 self.graph.clear_spill_region(anchor);
1414 self.log_change(ChangeEvent::SpillCleared {
1415 anchor,
1416 old: old_spill,
1417 });
1418 }
1419
1420 match self.graph.set_cell_value(
1423 &sheet_name,
1424 cell_ref.coord.row() + 1,
1425 cell_ref.coord.col() + 1,
1426 value.clone(),
1427 ) {
1428 Ok(summary) => {
1429 let change_event = ChangeEvent::SetValue {
1431 addr: cell_ref,
1432 old_value,
1433 old_formula,
1434 new: value,
1435 };
1436 self.log_change(change_event);
1437
1438 if did_spill_clear && let Some(logger) = &mut self.change_logger {
1439 logger.end_compound();
1440 }
1441
1442 summary
1443 .affected_vertices
1444 .into_iter()
1445 .next()
1446 .unwrap_or(VertexId::new(0))
1447 }
1448 Err(_) => VertexId::new(0),
1449 }
1450 }
1451
1452 pub fn set_cell_formula(&mut self, cell_ref: CellRef, formula: ASTNode) -> VertexId {
1454 let sheet_name = self.graph.sheet_name(cell_ref.sheet_id).to_string();
1455
1456 let old_id = self.graph.get_vertex_id_for_address(&cell_ref).copied();
1458 let old_value = old_id.and_then(|id| self.graph.get_value(id));
1459 let old_formula = old_id.and_then(|id| self.get_formula_ast(id));
1460
1461 let spill_snapshot =
1463 old_id.and_then(|id| self.snapshot_spill_for_anchor(id).map(|s| (id, s)));
1464 let did_spill_clear = spill_snapshot.is_some();
1465 if let Some((anchor, old_spill)) = spill_snapshot {
1466 if let Some(logger) = &mut self.change_logger {
1467 logger.begin_compound(format!(
1468 "SetFormulaWithSpillClear sheet={} row={} col={}",
1469 cell_ref.sheet_id,
1470 cell_ref.coord.row(),
1471 cell_ref.coord.col()
1472 ));
1473 }
1474 self.graph.clear_spill_region(anchor);
1475 self.log_change(ChangeEvent::SpillCleared {
1476 anchor,
1477 old: old_spill,
1478 });
1479 }
1480
1481 match self.graph.set_cell_formula(
1484 &sheet_name,
1485 cell_ref.coord.row() + 1,
1486 cell_ref.coord.col() + 1,
1487 formula.clone(),
1488 ) {
1489 Ok(summary) => {
1490 let change_event = ChangeEvent::SetFormula {
1492 addr: cell_ref,
1493 old_value,
1494 old_formula,
1495 new: formula,
1496 };
1497 self.log_change(change_event);
1498
1499 if did_spill_clear && let Some(logger) = &mut self.change_logger {
1500 logger.end_compound();
1501 }
1502
1503 summary
1504 .affected_vertices
1505 .into_iter()
1506 .next()
1507 .unwrap_or(VertexId::new(0))
1508 }
1509 Err(_) => VertexId::new(0),
1510 }
1511 }
1512
1513 pub fn set_range_values(
1517 &mut self,
1518 sheet_id: SheetId,
1519 start_row: u32,
1520 start_col: u32,
1521 values: &[Vec<LiteralValue>],
1522 ) -> Result<RangeSummary, EditorError> {
1523 let mut summary = RangeSummary::default();
1524
1525 self.begin_batch();
1526
1527 for (row_offset, row_values) in values.iter().enumerate() {
1528 for (col_offset, value) in row_values.iter().enumerate() {
1529 let row = start_row + row_offset as u32;
1530 let col = start_col + col_offset as u32;
1531
1532 let cell_ref = self.graph.make_cell_ref_internal(sheet_id, row, col);
1534
1535 if let Some(&existing_id) = self.graph.get_vertex_id_for_address(&cell_ref) {
1536 self.graph.update_vertex_value(existing_id, value.clone());
1538 self.graph.mark_vertex_dirty(existing_id);
1539 summary.vertices_updated.push(existing_id);
1540 } else {
1541 let meta = VertexMeta::new(row, col, sheet_id, VertexKind::Cell);
1543 let id = self.add_vertex(meta);
1544 self.graph.update_vertex_value(id, value.clone());
1545 summary.vertices_created.push(id);
1546 }
1547
1548 summary.cells_affected += 1;
1549 }
1550 }
1551
1552 self.commit_batch();
1553
1554 Ok(summary)
1555 }
1556
1557 pub fn clear_range(
1559 &mut self,
1560 sheet_id: SheetId,
1561 start_row: u32,
1562 start_col: u32,
1563 end_row: u32,
1564 end_col: u32,
1565 ) -> Result<RangeSummary, EditorError> {
1566 let mut summary = RangeSummary::default();
1567
1568 self.begin_batch();
1569
1570 let vertices_in_range: Vec<_> = self
1572 .graph
1573 .vertices_in_sheet(sheet_id)
1574 .filter(|&id| {
1575 let coord = self.graph.get_coord(id);
1576 let row = coord.row();
1577 let col = coord.col();
1578 row >= start_row && row <= end_row && col >= start_col && col <= end_col
1579 })
1580 .collect();
1581
1582 for id in vertices_in_range {
1583 self.remove_vertex(id)?;
1584 summary.cells_affected += 1;
1585 }
1586
1587 self.commit_batch();
1588
1589 Ok(summary)
1590 }
1591
1592 pub fn copy_range(
1594 &mut self,
1595 sheet_id: SheetId,
1596 from_start_row: u32,
1597 from_start_col: u32,
1598 from_end_row: u32,
1599 from_end_col: u32,
1600 to_sheet_id: SheetId,
1601 to_row: u32,
1602 to_col: u32,
1603 ) -> Result<RangeSummary, EditorError> {
1604 let row_offset = to_row as i32 - from_start_row as i32;
1605 let col_offset = to_col as i32 - from_start_col as i32;
1606
1607 let mut summary = RangeSummary::default();
1608 let mut cell_data = Vec::new();
1609
1610 let vertices_in_range: Vec<_> = self
1612 .graph
1613 .vertices_in_sheet(sheet_id)
1614 .filter(|&id| {
1615 let coord = self.graph.get_coord(id);
1616 let row = coord.row();
1617 let col = coord.col();
1618 row >= from_start_row
1619 && row <= from_end_row
1620 && col >= from_start_col
1621 && col <= from_end_col
1622 })
1623 .collect();
1624
1625 for id in vertices_in_range {
1626 let coord = self.graph.get_coord(id);
1627 let row = coord.row();
1628 let col = coord.col();
1629
1630 if let Some(formula) = self.get_formula_ast(id) {
1632 cell_data.push((
1633 row - from_start_row,
1634 col - from_start_col,
1635 CellData::Formula(formula),
1636 ));
1637 } else if let Some(value) = self.graph.get_value(id) {
1638 cell_data.push((
1639 row - from_start_row,
1640 col - from_start_col,
1641 CellData::Value(value),
1642 ));
1643 }
1644 }
1645
1646 self.begin_batch();
1647
1648 for (row_idx, col_idx, data) in cell_data {
1650 let dest_row = (to_row as i32 + row_idx as i32) as u32;
1651 let dest_col = (to_col as i32 + col_idx as i32) as u32;
1652
1653 match data {
1654 CellData::Value(value) => {
1655 let cell_ref =
1656 self.graph
1657 .make_cell_ref_internal(to_sheet_id, dest_row, dest_col);
1658
1659 if let Some(&existing_id) = self.graph.get_vertex_id_for_address(&cell_ref) {
1660 self.graph.update_vertex_value(existing_id, value);
1661 self.graph.mark_vertex_dirty(existing_id);
1662 summary.vertices_updated.push(existing_id);
1663 } else {
1664 let meta =
1665 VertexMeta::new(dest_row, dest_col, to_sheet_id, VertexKind::Cell);
1666 let id = self.add_vertex(meta);
1667 self.graph.update_vertex_value(id, value);
1668 summary.vertices_created.push(id);
1669 }
1670 }
1671 CellData::Formula(formula) => {
1672 let adjuster = RelativeReferenceAdjuster::new(row_offset, col_offset);
1674 let adjusted = adjuster.adjust_formula(&formula);
1675
1676 let cell_ref =
1677 self.graph
1678 .make_cell_ref_internal(to_sheet_id, dest_row, dest_col);
1679
1680 if let Some(&existing_id) = self.graph.get_vertex_id_for_address(&cell_ref) {
1681 self.graph.update_vertex_formula(existing_id, adjusted)?;
1682 summary.vertices_updated.push(existing_id);
1683 } else {
1684 let meta = VertexMeta::new(
1685 dest_row,
1686 dest_col,
1687 to_sheet_id,
1688 VertexKind::FormulaScalar,
1689 );
1690 let id = self.add_vertex(meta);
1691 self.graph.update_vertex_formula(id, adjusted)?;
1692 summary.vertices_created.push(id);
1693 }
1694 }
1695 }
1696
1697 summary.cells_affected += 1;
1698 }
1699
1700 self.commit_batch();
1701
1702 Ok(summary)
1703 }
1704
1705 pub fn move_range(
1707 &mut self,
1708 sheet_id: SheetId,
1709 from_start_row: u32,
1710 from_start_col: u32,
1711 from_end_row: u32,
1712 from_end_col: u32,
1713 to_sheet_id: SheetId,
1714 to_row: u32,
1715 to_col: u32,
1716 ) -> Result<RangeSummary, EditorError> {
1717 let mut summary = self.copy_range(
1719 sheet_id,
1720 from_start_row,
1721 from_start_col,
1722 from_end_row,
1723 from_end_col,
1724 to_sheet_id,
1725 to_row,
1726 to_col,
1727 )?;
1728
1729 let clear_summary = self.clear_range(
1731 sheet_id,
1732 from_start_row,
1733 from_start_col,
1734 from_end_row,
1735 from_end_col,
1736 )?;
1737
1738 summary.cells_moved = clear_summary.cells_affected;
1739
1740 let row_offset = to_row as i32 - from_start_row as i32;
1742 let col_offset = to_col as i32 - from_start_col as i32;
1743
1744 let all_formula_vertices: Vec<_> = self.graph.vertices_with_formulas().collect();
1746
1747 let from_sheet_name = self.graph.sheet_name(sheet_id).to_string();
1748 let to_sheet_name = self.graph.sheet_name(to_sheet_id).to_string();
1749 let adjuster = MoveReferenceAdjuster::new(
1750 sheet_id,
1751 from_sheet_name,
1752 from_start_row,
1753 from_start_col,
1754 from_end_row,
1755 from_end_col,
1756 to_sheet_id,
1757 to_sheet_name,
1758 row_offset,
1759 col_offset,
1760 );
1761
1762 for formula_id in all_formula_vertices {
1763 if let Some(formula) = self.get_formula_ast(formula_id) {
1764 let formula_sheet_id = self.graph.get_vertex_sheet_id(formula_id);
1765 if let Some(adjusted) = adjuster.adjust_if_references(&formula, formula_sheet_id) {
1766 self.graph.update_vertex_formula(formula_id, adjusted)?;
1767 }
1768 }
1769 }
1770
1771 Ok(summary)
1772 }
1773
1774 pub fn define_name(
1776 &mut self,
1777 name: &str,
1778 definition: NamedDefinition,
1779 scope: NameScope,
1780 ) -> Result<(), EditorError> {
1781 self.graph.define_name(name, definition.clone(), scope)?;
1782
1783 self.log_change(ChangeEvent::DefineName {
1784 name: name.to_string(),
1785 scope,
1786 definition,
1787 });
1788
1789 Ok(())
1790 }
1791
1792 pub fn define_name_for_cell(
1794 &mut self,
1795 name: &str,
1796 sheet_name: &str,
1797 row: u32,
1798 col: u32,
1799 scope: NameScope,
1800 ) -> Result<(), EditorError> {
1801 let sheet_id = self
1802 .graph
1803 .sheet_id(sheet_name)
1804 .ok_or_else(|| EditorError::InvalidName {
1805 name: sheet_name.to_string(),
1806 reason: "Sheet not found".to_string(),
1807 })?;
1808 let cell_ref = CellRef::new(sheet_id, Coord::from_excel(row, col, true, true));
1809 self.define_name(name, NamedDefinition::Cell(cell_ref), scope)
1810 }
1811
1812 pub fn define_name_for_range(
1814 &mut self,
1815 name: &str,
1816 sheet_name: &str,
1817 start_row: u32,
1818 start_col: u32,
1819 end_row: u32,
1820 end_col: u32,
1821 scope: NameScope,
1822 ) -> Result<(), EditorError> {
1823 let sheet_id = self
1824 .graph
1825 .sheet_id(sheet_name)
1826 .ok_or_else(|| EditorError::InvalidName {
1827 name: sheet_name.to_string(),
1828 reason: "Sheet not found".to_string(),
1829 })?;
1830 let start = CellRef::new(
1831 sheet_id,
1832 Coord::from_excel(start_row, start_col, true, true),
1833 );
1834 let end = CellRef::new(sheet_id, Coord::from_excel(end_row, end_col, true, true));
1835 let range_ref = crate::reference::RangeRef::new(start, end);
1836 self.define_name(name, NamedDefinition::Range(range_ref), scope)
1837 }
1838
1839 pub fn update_name(
1841 &mut self,
1842 name: &str,
1843 new_definition: NamedDefinition,
1844 scope: NameScope,
1845 ) -> Result<(), EditorError> {
1846 let old_definition = self
1848 .graph
1849 .resolve_name(
1850 name,
1851 match scope {
1852 NameScope::Sheet(id) => id,
1853 NameScope::Workbook => 0,
1854 },
1855 )
1856 .cloned();
1857
1858 self.graph
1859 .update_name(name, new_definition.clone(), scope)?;
1860
1861 if let Some(old_def) = old_definition {
1862 self.log_change(ChangeEvent::UpdateName {
1863 name: name.to_string(),
1864 scope,
1865 old_definition: old_def,
1866 new_definition,
1867 });
1868 }
1869
1870 Ok(())
1871 }
1872
1873 pub fn delete_name(&mut self, name: &str, scope: NameScope) -> Result<(), EditorError> {
1875 let old_def = if self.has_logger() {
1877 self.graph
1878 .resolve_name(
1879 name,
1880 match scope {
1881 NameScope::Sheet(id) => id,
1882 NameScope::Workbook => 0,
1883 },
1884 )
1885 .cloned()
1886 } else {
1887 None
1888 };
1889
1890 self.graph.delete_name(name, scope)?;
1891 self.log_change(ChangeEvent::DeleteName {
1892 name: name.to_string(),
1893 scope,
1894 old_definition: old_def,
1895 });
1896
1897 Ok(())
1898 }
1899}
1900
1901enum CellData {
1903 Value(LiteralValue),
1904 Formula(ASTNode),
1905}
1906
1907impl<'g> Drop for VertexEditor<'g> {
1908 fn drop(&mut self) {
1909 if self.batch_mode {
1911 self.commit_batch();
1912 }
1913 }
1914}
1915
1916#[cfg(test)]
1917mod tests {
1918 use super::*;
1919 use crate::engine::graph::editor::change_log::{ChangeEvent, ChangeLog};
1920 use crate::reference::Coord;
1921
1922 fn create_test_graph() -> DependencyGraph {
1923 DependencyGraph::new()
1924 }
1925
1926 #[test]
1927 fn test_vertex_editor_creation() {
1928 let mut graph = create_test_graph();
1929 let editor = VertexEditor::new(&mut graph);
1930 assert!(!editor.has_logger());
1931 assert!(!editor.batch_mode);
1932 }
1933
1934 #[test]
1935 fn test_vertex_editor_with_logger() {
1936 let mut graph = create_test_graph();
1937 let mut log = ChangeLog::new();
1938 let editor = VertexEditor::with_logger(&mut graph, &mut log);
1939 assert!(editor.has_logger());
1940 assert!(!editor.batch_mode);
1941 }
1942
1943 #[test]
1944 fn test_add_vertex() {
1945 let mut graph = create_test_graph();
1946 let mut editor = VertexEditor::new(&mut graph);
1947
1948 let meta = VertexMeta::new(5, 10, 0, VertexKind::Cell).dirty();
1949 let vertex_id = editor.add_vertex(meta);
1950
1951 assert!(vertex_id.0 > 0);
1953 }
1954
1955 #[test]
1956 fn test_batch_operations() {
1957 let mut graph = create_test_graph();
1958 let mut editor = VertexEditor::new(&mut graph);
1959
1960 assert!(!editor.batch_mode);
1961 editor.begin_batch();
1962 assert!(editor.batch_mode);
1963
1964 let meta1 = VertexMeta::new(1, 1, 0, VertexKind::Cell);
1966 let meta2 = VertexMeta::new(2, 2, 0, VertexKind::Cell);
1967
1968 let id1 = editor.add_vertex(meta1);
1969 let id2 = editor.add_vertex(meta2);
1970
1971 assert!(editor.add_edge(id1, id2));
1973
1974 editor.commit_batch();
1975 assert!(!editor.batch_mode);
1976 }
1977
1978 #[test]
1979 fn test_remove_vertex() {
1980 let mut graph = create_test_graph();
1981 let mut editor = VertexEditor::new(&mut graph);
1982
1983 let meta = VertexMeta::new(3, 4, 0, VertexKind::Cell).dirty();
1984 let vertex_id = editor.add_vertex(meta);
1985
1986 assert!(editor.remove_vertex(vertex_id).is_ok());
1988 }
1989
1990 #[test]
1991 fn test_remove_vertex_clears_spill_registry_for_anchor() {
1992 let mut graph = create_test_graph();
1993 let sheet_id = graph.sheet_id_mut("Sheet1");
1994
1995 let anchor_cell = CellRef::new(sheet_id, Coord::new(0, 0, true, true));
1997 let anchor_vid = {
1998 let mut editor = VertexEditor::new(&mut graph);
1999 editor.set_cell_value(anchor_cell, LiteralValue::Number(0.0))
2000 };
2001
2002 let target_cells = vec![
2003 CellRef::new(sheet_id, Coord::new(0, 0, true, true)),
2004 CellRef::new(sheet_id, Coord::new(0, 1, true, true)),
2005 CellRef::new(sheet_id, Coord::new(1, 0, true, true)),
2006 CellRef::new(sheet_id, Coord::new(1, 1, true, true)),
2007 ];
2008 let values = vec![
2009 vec![LiteralValue::Number(1.0), LiteralValue::Number(2.0)],
2010 vec![LiteralValue::Number(3.0), LiteralValue::Number(4.0)],
2011 ];
2012
2013 graph
2014 .commit_spill_region_atomic_with_fault(anchor_vid, target_cells.clone(), values, None)
2015 .unwrap();
2016
2017 assert!(graph.spill_registry_has_anchor(anchor_vid));
2018 for cell in &target_cells {
2019 assert_eq!(
2020 graph.spill_registry_anchor_for_cell(*cell),
2021 Some(anchor_vid)
2022 );
2023 }
2024
2025 {
2026 let mut editor = VertexEditor::new(&mut graph);
2027 editor.remove_vertex(anchor_vid).unwrap();
2028 }
2029
2030 assert!(!graph.spill_registry_has_anchor(anchor_vid));
2031 for cell in &target_cells {
2032 assert_eq!(graph.spill_registry_anchor_for_cell(*cell), None);
2033 }
2034 assert_eq!(graph.spill_registry_counts(), (0, 0));
2035 }
2036
2037 #[test]
2038 fn test_edge_operations() {
2039 let mut graph = create_test_graph();
2040 let mut editor = VertexEditor::new(&mut graph);
2041
2042 let meta1 = VertexMeta::new(1, 1, 0, VertexKind::Cell);
2043 let meta2 = VertexMeta::new(2, 2, 0, VertexKind::FormulaScalar);
2044
2045 let id1 = editor.add_vertex(meta1);
2046 let id2 = editor.add_vertex(meta2);
2047
2048 assert!(editor.add_edge(id1, id2));
2050
2051 assert!(!editor.add_edge(id1, id1));
2053
2054 assert!(editor.remove_edge(id1, id2));
2056 }
2057
2058 #[test]
2059 fn test_set_cell_value() {
2060 let mut graph = create_test_graph();
2061 let mut log = ChangeLog::new();
2062
2063 let cell_ref = CellRef {
2064 sheet_id: 0,
2065 coord: Coord::new(2, 3, true, true),
2066 };
2067 let value = LiteralValue::Number(42.0);
2068
2069 let vertex_id = {
2070 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2071 editor.set_cell_value(cell_ref, value.clone())
2072 };
2073
2074 assert!(vertex_id.0 > 0);
2076
2077 assert_eq!(log.len(), 1);
2079 match &log.events()[0] {
2080 ChangeEvent::SetValue { addr, new, .. } => {
2081 assert_eq!(addr.sheet_id, cell_ref.sheet_id);
2082 assert_eq!(addr.coord.row(), cell_ref.coord.row());
2083 assert_eq!(addr.coord.col(), cell_ref.coord.col());
2084 assert_eq!(new, &value);
2085 }
2086 _ => panic!("Expected SetValue event"),
2087 }
2088 }
2089
2090 #[test]
2091 fn test_set_cell_formula() {
2092 let mut graph = create_test_graph();
2093 let mut log = ChangeLog::new();
2094
2095 let cell_ref = CellRef {
2096 sheet_id: 0,
2097 coord: Coord::new(1, 1, true, true),
2098 };
2099
2100 use formualizer_parse::parser::ASTNodeType;
2101 let formula = formualizer_parse::parser::ASTNode {
2102 node_type: ASTNodeType::Literal(LiteralValue::Number(100.0)),
2103 source_token: None,
2104 contains_volatile: false,
2105 };
2106
2107 let vertex_id = {
2108 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2109 editor.set_cell_formula(cell_ref, formula.clone())
2110 };
2111
2112 assert!(vertex_id.0 > 0);
2114
2115 assert_eq!(log.len(), 1);
2117 match &log.events()[0] {
2118 ChangeEvent::SetFormula { addr, .. } => {
2119 assert_eq!(addr.sheet_id, cell_ref.sheet_id);
2120 assert_eq!(addr.coord.row(), cell_ref.coord.row());
2121 assert_eq!(addr.coord.col(), cell_ref.coord.col());
2122 }
2123 _ => panic!("Expected SetFormula event"),
2124 }
2125 }
2126
2127 #[test]
2128 fn test_shift_rows() {
2129 let mut graph = create_test_graph();
2130 let mut log = ChangeLog::new();
2131
2132 {
2133 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2134
2135 let cell1 = CellRef {
2137 sheet_id: 0,
2138 coord: Coord::new(5, 1, true, true),
2139 };
2140 let cell2 = CellRef {
2141 sheet_id: 0,
2142 coord: Coord::new(10, 1, true, true),
2143 };
2144 let cell3 = CellRef {
2145 sheet_id: 0,
2146 coord: Coord::new(15, 1, true, true),
2147 };
2148
2149 editor.set_cell_value(cell1, LiteralValue::Number(1.0));
2150 editor.set_cell_value(cell2, LiteralValue::Number(2.0));
2151 editor.set_cell_value(cell3, LiteralValue::Number(3.0));
2152 }
2153
2154 log.clear();
2156
2157 {
2158 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2159 editor.shift_rows(0, 10, 2);
2161 }
2162
2163 assert_eq!(log.len(), 1);
2165 match &log.events()[0] {
2166 ChangeEvent::SetValue { addr, new, .. } => {
2167 assert_eq!(addr.sheet_id, 0);
2168 assert_eq!(addr.coord.row(), 10);
2169 if let LiteralValue::Text(msg) = new {
2170 assert!(msg.contains("Row shift"));
2171 assert!(msg.contains("start=10"));
2172 assert!(msg.contains("delta=2"));
2173 }
2174 }
2175 _ => panic!("Expected SetValue event for row shift"),
2176 }
2177 }
2178
2179 #[test]
2180 fn test_shift_columns() {
2181 let mut graph = create_test_graph();
2182 let mut log = ChangeLog::new();
2183
2184 {
2185 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2186
2187 let cell1 = CellRef {
2189 sheet_id: 0,
2190 coord: Coord::new(1, 5, true, true),
2191 };
2192 let cell2 = CellRef {
2193 sheet_id: 0,
2194 coord: Coord::new(1, 10, true, true),
2195 };
2196
2197 editor.set_cell_value(cell1, LiteralValue::Number(1.0));
2198 editor.set_cell_value(cell2, LiteralValue::Number(2.0));
2199 }
2200
2201 log.clear();
2203
2204 {
2205 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2206 editor.shift_columns(0, 8, 3);
2208 }
2209
2210 assert_eq!(log.len(), 1);
2212 match &log.events()[0] {
2213 ChangeEvent::SetValue { addr, new, .. } => {
2214 assert_eq!(addr.sheet_id, 0);
2215 assert_eq!(addr.coord.col(), 8);
2216 if let LiteralValue::Text(msg) = new {
2217 assert!(msg.contains("Column shift"));
2218 assert!(msg.contains("start=8"));
2219 assert!(msg.contains("delta=3"));
2220 }
2221 }
2222 _ => panic!("Expected SetValue event for column shift"),
2223 }
2224 }
2225
2226 #[test]
2227 fn test_move_vertex() {
2228 let mut graph = create_test_graph();
2229 let mut editor = VertexEditor::new(&mut graph);
2230
2231 let meta = VertexMeta::new(5, 10, 0, VertexKind::Cell);
2232 let vertex_id = editor.add_vertex(meta);
2233
2234 assert!(editor.move_vertex(vertex_id, AbsCoord::new(8, 12)).is_ok());
2236
2237 assert!(editor.move_vertex(vertex_id, AbsCoord::new(8, 12)).is_ok());
2239 }
2240
2241 #[test]
2242 fn test_vertex_meta_builder() {
2243 let meta = VertexMeta::new(1, 2, 3, VertexKind::FormulaScalar)
2244 .dirty()
2245 .volatile()
2246 .with_flags(0x08);
2247
2248 assert_eq!(meta.coord.row(), 1);
2249 assert_eq!(meta.coord.col(), 2);
2250 assert_eq!(meta.sheet_id, 3);
2251 assert_eq!(meta.kind, VertexKind::FormulaScalar);
2252 assert_eq!(meta.flags, 0x08); }
2254
2255 #[test]
2256 fn test_change_log_management() {
2257 let mut graph = create_test_graph();
2258 let mut log = ChangeLog::new();
2259
2260 {
2261 let mut editor = VertexEditor::with_logger(&mut graph, &mut log);
2262 let cell_ref = CellRef {
2263 sheet_id: 0,
2264 coord: Coord::new(0, 0, true, true),
2265 };
2266 editor.set_cell_value(cell_ref, LiteralValue::Number(1.0));
2267 editor.set_cell_value(cell_ref, LiteralValue::Number(2.0));
2268 }
2269
2270 assert_eq!(log.len(), 2);
2271
2272 log.clear();
2273 assert_eq!(log.len(), 0);
2274 }
2275
2276 #[test]
2277 fn test_editor_drop_commits_batch() {
2278 let mut graph = create_test_graph();
2279 {
2280 let mut editor = VertexEditor::new(&mut graph);
2281 editor.begin_batch();
2282
2283 let meta = VertexMeta::new(1, 1, 0, VertexKind::Cell);
2284 editor.add_vertex(meta);
2285
2286 }
2288
2289 }
2291}