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