1use super::*;
2use formualizer_common::parse_a1_1based;
3
4#[inline]
5fn normalize_name_key(name: &str) -> String {
6 name.to_lowercase()
7}
8
9fn is_valid_excel_name(name: &str) -> bool {
11 if name.is_empty() || name.len() > 255 {
19 return false;
20 }
21
22 if parse_a1_1based(name).is_ok() {
23 return false;
24 }
25
26 let mut chars = name.chars();
27
28 if let Some(first) = chars.next()
30 && !first.is_alphabetic()
31 && first != '_'
32 && first != '\\'
33 {
34 return false;
35 }
36
37 for c in chars {
39 if !c.is_alphanumeric() && c != '.' && c != '_' {
40 return false;
41 }
42 }
43
44 true
45}
46
47fn adjust_named_definition(
52 definition: &mut NamedDefinition,
53 adjuster: &crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster,
54 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
55 context: &crate::engine::graph::editor::reference_adjuster::ReferenceContext<'_>,
56) -> Result<(), ExcelError> {
57 use crate::engine::graph::editor::reference_adjuster::AbsShiftPolicy;
58 let mut invalidated = false;
59 match definition {
60 NamedDefinition::Cell(cell_ref) => {
61 if let Some(adjusted) =
62 adjuster.adjust_cell_ref_with_policy(cell_ref, operation, AbsShiftPolicy::Track)
63 {
64 *cell_ref = adjusted;
65 } else {
66 invalidated = true;
67 }
68 }
69 NamedDefinition::Range(range_ref) => {
70 let adjusted_start = adjuster.adjust_cell_ref_with_policy(
71 &range_ref.start,
72 operation,
73 AbsShiftPolicy::Track,
74 );
75 let adjusted_end = adjuster.adjust_cell_ref_with_policy(
76 &range_ref.end,
77 operation,
78 AbsShiftPolicy::Track,
79 );
80
81 if let (Some(start), Some(end)) = (adjusted_start, adjusted_end) {
82 range_ref.start = start;
83 range_ref.end = end;
84 } else {
85 invalidated = true;
86 }
87 }
88 NamedDefinition::Literal(_) => {
89 }
91 NamedDefinition::Formula {
92 ast,
93 dependencies,
94 range_deps,
95 } => {
96 let adjusted_ast = adjuster.adjust_ast_with_policy_in_context(
97 ast,
98 operation,
99 AbsShiftPolicy::Track,
100 context,
101 );
102 *ast = adjusted_ast;
103
104 dependencies.clear();
105 range_deps.clear();
106 }
107 }
108 if invalidated {
109 *definition = NamedDefinition::Formula {
110 ast: formualizer_parse::parser::ASTNode::new(
111 formualizer_parse::parser::ASTNodeType::Literal(LiteralValue::Error(
112 ExcelError::new(ExcelErrorKind::Ref),
113 )),
114 None,
115 ),
116 dependencies: Vec::new(),
117 range_deps: Vec::new(),
118 };
119 }
120 Ok(())
121}
122
123impl DependencyGraph {
124 #[inline]
125 pub(crate) fn name_lookup_key(&self, name: &str) -> String {
126 if self.config.case_sensitive_names {
127 name.to_string()
128 } else {
129 normalize_name_key(name)
130 }
131 }
132
133 fn canonical_name_in_scope(&self, scope: NameScope, name: &str) -> Option<String> {
134 let key = self.name_lookup_key(name);
135 match scope {
136 NameScope::Workbook => self.named_ranges_lookup.get(&key).cloned(),
137 NameScope::Sheet(sheet_id) => self
138 .sheet_named_ranges_lookup
139 .get(&(sheet_id, key))
140 .cloned(),
141 }
142 }
143
144 pub(super) fn next_symbol_addr(&mut self) -> VertexAddr {
150 let seq = self.symbol_vertex_seq;
151 self.symbol_vertex_seq = self.symbol_vertex_seq.wrapping_add(1);
152 VertexAddr::symbol(SymbolAddr::new(seq))
153 }
154
155 pub(super) fn allocate_symbol_vertex(
162 &mut self,
163 kind: VertexKind,
164 scope_sheet_id: SheetId,
165 ) -> VertexId {
166 let addr = self.next_symbol_addr();
167 let vertex_id = self.store.allocate(addr, scope_sheet_id, 0x01);
168 self.store.set_kind(vertex_id, kind);
169 self.edges.add_vertex(addr, vertex_id.0);
170 vertex_id
171 }
172
173 pub(super) fn allocate_name_vertex(&mut self, scope: NameScope) -> VertexId {
174 let scope_sheet_id = match scope {
177 NameScope::Sheet(id) => id,
178 NameScope::Workbook => self.default_sheet_id,
179 };
180 let vertex_id = self.allocate_symbol_vertex(VertexKind::NamedScalar, scope_sheet_id);
181 self.mark_vertex_dirty(vertex_id);
182 vertex_id
183 }
184
185 pub(crate) fn validate_define_name(
188 &self,
189 name: &str,
190 scope: NameScope,
191 ) -> Result<(), ExcelError> {
192 if !is_valid_excel_name(name) {
193 return Err(
194 ExcelError::new(ExcelErrorKind::Name).with_message(format!("Invalid name: {name}"))
195 );
196 }
197
198 let lookup_key = self.name_lookup_key(name);
199 match scope {
200 NameScope::Workbook => {
201 if let Some(existing) = self.named_ranges_lookup.get(&lookup_key) {
202 return Err(ExcelError::new(ExcelErrorKind::Name).with_message(format!(
203 "Name collision under normalization: '{name}' conflicts with '{existing}'"
204 )));
205 }
206 }
207 NameScope::Sheet(sheet_id) => {
208 if let Some(existing) = self.sheet_named_ranges_lookup.get(&(sheet_id, lookup_key))
209 {
210 return Err(ExcelError::new(ExcelErrorKind::Name).with_message(format!(
211 "Name collision under normalization in sheet: '{name}' conflicts with '{existing}'"
212 )));
213 }
214 }
215 }
216 Ok(())
217 }
218
219 pub(crate) fn validate_existing_name(
220 &self,
221 name: &str,
222 scope: NameScope,
223 ) -> Result<(), ExcelError> {
224 self.canonical_name_in_scope(scope, name)
225 .map(|_| ())
226 .ok_or_else(|| {
227 ExcelError::new(ExcelErrorKind::Name)
228 .with_message(format!("Name not found: {name}"))
229 })
230 }
231
232 pub fn define_name(
234 &mut self,
235 name: &str,
236 definition: NamedDefinition,
237 scope: NameScope,
238 ) -> Result<(), ExcelError> {
239 self.validate_define_name(name, scope)?;
240
241 let mut final_definition = definition;
242 if let NamedDefinition::Formula { ref ast, .. } = final_definition {
244 let (deps, range_deps, _, _) = self.extract_dependencies(
245 ast,
246 match scope {
247 NameScope::Sheet(id) => id,
248 NameScope::Workbook => self.default_sheet_id,
249 },
250 )?;
251 final_definition = NamedDefinition::Formula {
252 ast: ast.clone(),
253 dependencies: deps,
254 range_deps,
255 };
256 }
257
258 let vertex_id = self.allocate_name_vertex(scope);
260
261 let named_range = NamedRange {
262 definition: final_definition,
263 scope,
264 dependents: FxHashSet::default(),
265 vertex: vertex_id,
266 };
267
268 if matches!(named_range.definition, NamedDefinition::Range(_)) {
269 self.store.set_kind(vertex_id, VertexKind::NamedArray);
270 } else {
271 self.store.set_kind(vertex_id, VertexKind::NamedScalar);
272 }
273
274 let referenced_names =
276 self.rebuild_name_dependencies(vertex_id, &named_range.definition, scope)?;
277 if !referenced_names.is_empty() {
278 self.attach_vertex_to_names(vertex_id, &referenced_names);
279 }
280
281 let key = name.to_string();
282
283 match scope {
284 NameScope::Workbook => {
285 self.named_ranges.insert(key.clone(), named_range);
286 self.named_ranges_lookup
287 .insert(self.name_lookup_key(&key), key.clone());
288 }
289 NameScope::Sheet(id) => {
290 self.sheet_named_ranges
291 .insert((id, key.clone()), named_range);
292 self.sheet_named_ranges_lookup
293 .insert((id, self.name_lookup_key(&key)), key.clone());
294 }
295 }
296
297 self.name_vertex_lookup.insert(vertex_id, (scope, key));
298 self.resolve_pending_name_references(scope, name);
299 self.bump_symbol_revision();
300
301 Ok(())
302 }
303
304 pub fn named_ranges_iter(&self) -> impl Iterator<Item = (&String, &NamedRange)> {
306 self.named_ranges.iter()
307 }
308
309 pub fn sheet_named_ranges_iter(
311 &self,
312 ) -> impl Iterator<Item = (&(SheetId, String), &NamedRange)> {
313 self.sheet_named_ranges.iter()
314 }
315
316 pub fn resolve_name_entry_in_scope(&self, name: &str, scope: NameScope) -> Option<&NamedRange> {
328 let workbook_entry = || {
329 if self.config.case_sensitive_names {
330 self.named_ranges.get(name)
331 } else {
332 self.named_ranges_lookup
333 .get(&self.name_lookup_key(name))
334 .and_then(|canon| self.named_ranges.get(canon))
335 }
336 };
337
338 match scope {
339 NameScope::Workbook => workbook_entry(),
340 NameScope::Sheet(current_sheet) => {
341 if self.config.case_sensitive_names {
342 self.sheet_named_ranges
343 .get(&(current_sheet, name.to_string()))
344 .or_else(workbook_entry)
345 } else {
346 let key = self.name_lookup_key(name);
347 self.sheet_named_ranges_lookup
348 .get(&(current_sheet, key))
349 .and_then(|canon| {
350 self.sheet_named_ranges.get(&(current_sheet, canon.clone()))
351 })
352 .or_else(workbook_entry)
353 }
354 }
355 }
356 }
357
358 pub fn resolve_name_entry(&self, name: &str, current_sheet: SheetId) -> Option<&NamedRange> {
362 self.resolve_name_entry_in_scope(name, NameScope::Sheet(current_sheet))
363 }
364
365 pub fn resolve_name(&self, name: &str, current_sheet: SheetId) -> Option<&NamedDefinition> {
367 self.resolve_name_entry(name, current_sheet)
368 .map(|nr| &nr.definition)
369 }
370
371 pub(crate) fn name_key_for_vertex(&self, vertex: VertexId) -> Option<String> {
375 self.name_vertex_lookup
376 .get(&vertex)
377 .map(|(_, name)| self.name_lookup_key(name))
378 }
379
380 pub fn named_range_by_vertex(&self, vertex: VertexId) -> Option<&NamedRange> {
381 self.name_vertex_lookup
382 .get(&vertex)
383 .and_then(|(scope, name)| match scope {
384 NameScope::Workbook => self.named_ranges.get(name),
385 NameScope::Sheet(sheet_id) => {
386 self.sheet_named_ranges.get(&(*sheet_id, name.clone()))
387 }
388 })
389 }
390
391 pub fn update_name(
393 &mut self,
394 name: &str,
395 new_definition: NamedDefinition,
396 scope: NameScope,
397 ) -> Result<(), ExcelError> {
398 let Some(canon_name) = self.canonical_name_in_scope(scope, name) else {
399 return Err(ExcelError::new(ExcelErrorKind::Name)
400 .with_message(format!("Name not found: {name}")));
401 };
402
403 let dependents_to_dirty = match scope {
405 NameScope::Workbook => self
406 .named_ranges
407 .get(&canon_name)
408 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
409 NameScope::Sheet(id) => self
410 .sheet_named_ranges
411 .get(&(id, canon_name.clone()))
412 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
413 };
414
415 if let Some(dependents) = dependents_to_dirty {
416 self.mark_dirty_many(&dependents);
422
423 let named_range = match scope {
425 NameScope::Workbook => self.named_ranges.get_mut(&canon_name),
426 NameScope::Sheet(id) => self.sheet_named_ranges.get_mut(&(id, canon_name.clone())),
427 };
428
429 let mut update_data: Option<(VertexId, NameScope, NamedDefinition, bool)> = None;
430 if let Some(named_range) = named_range {
431 named_range.definition = new_definition;
432 let is_range = matches!(named_range.definition, NamedDefinition::Range(_));
433 update_data = Some((
434 named_range.vertex,
435 named_range.scope,
436 named_range.definition.clone(),
437 is_range,
438 ));
439 }
440
441 if let Some((vertex, scope_value, definition_snapshot, is_range)) = update_data {
442 self.detach_vertex_from_names(vertex);
443
444 if is_range {
445 self.store.set_kind(vertex, VertexKind::NamedArray);
446 } else {
447 self.store.set_kind(vertex, VertexKind::NamedScalar);
448 }
449
450 let referenced_names =
451 self.rebuild_name_dependencies(vertex, &definition_snapshot, scope_value)?;
452 if !referenced_names.is_empty() {
453 self.attach_vertex_to_names(vertex, &referenced_names);
454 }
455 self.mark_dirty_many(&[vertex]);
458 }
459
460 self.bump_symbol_revision();
461 Ok(())
462 } else {
463 Err(ExcelError::new(ExcelErrorKind::Name)
464 .with_message(format!("Name not found: {name}")))
465 }
466 }
467
468 pub fn delete_name(&mut self, name: &str, scope: NameScope) -> Result<(), ExcelError> {
470 let Some(canon_name) = self.canonical_name_in_scope(scope, name) else {
471 return Err(ExcelError::new(ExcelErrorKind::Name)
472 .with_message(format!("Name not found: {name}")));
473 };
474
475 let named_range = match scope {
476 NameScope::Workbook => {
477 let removed = self.named_ranges.remove(&canon_name);
478 let key = self.name_lookup_key(&canon_name);
479 self.named_ranges_lookup.remove(&key);
480 removed
481 }
482 NameScope::Sheet(id) => {
483 let removed = self.sheet_named_ranges.remove(&(id, canon_name.clone()));
484 let key = self.name_lookup_key(&canon_name);
485 self.sheet_named_ranges_lookup.remove(&(id, key));
486 removed
487 }
488 };
489
490 if let Some(named_range) = named_range {
491 let mut affected: FxHashSet<VertexId> = FxHashSet::default();
492 for &vertex_id in &named_range.dependents {
493 affected.insert(vertex_id);
494 }
495 for (vertex_id, names) in self.vertex_to_names.iter() {
496 if names.contains(&named_range.vertex) {
497 affected.insert(*vertex_id);
498 }
499 }
500 let formulas_to_rebuild = affected
501 .iter()
502 .filter(|&&vertex_id| self.get_cell_ref_for_vertex(vertex_id).is_some())
503 .filter_map(|&vertex_id| self.get_formula(vertex_id).map(|ast| (vertex_id, ast)))
504 .collect::<Vec<_>>();
505 let names_to_rebuild = affected
511 .iter()
512 .filter(|&&vertex_id| vertex_id != named_range.vertex)
513 .filter_map(|&vertex_id| {
514 self.named_range_by_vertex(vertex_id)
515 .map(|nr| (vertex_id, nr.definition.clone(), nr.scope))
516 })
517 .collect::<Vec<_>>();
518 let dirty_sources = affected
519 .iter()
520 .copied()
521 .filter(|&vertex_id| vertex_id != named_range.vertex)
522 .collect::<Vec<_>>();
523 for vertex_id in affected {
524 if let Some(names) = self.vertex_to_names.get_mut(&vertex_id) {
525 names.retain(|vid| *vid != named_range.vertex);
526 if names.is_empty() {
527 self.vertex_to_names.remove(&vertex_id);
528 }
529 }
530 }
531 self.mark_named_vertex_deleted(&named_range);
532 for (vertex_id, ast) in formulas_to_rebuild {
537 self.rebuild_formula_dependencies(vertex_id, &ast);
538 }
539 for (vertex_id, definition, name_scope) in names_to_rebuild {
540 let referenced_names =
541 self.rebuild_name_dependencies(vertex_id, &definition, name_scope)?;
542 if !referenced_names.is_empty() {
543 self.attach_vertex_to_names(vertex_id, &referenced_names);
544 }
545 }
546 self.mark_dirty_many(&dirty_sources);
550 self.bump_symbol_revision();
551 Ok(())
552 } else {
553 Err(ExcelError::new(ExcelErrorKind::Name)
554 .with_message(format!("Name not found: {name}")))
555 }
556 }
557
558 pub(super) fn detach_vertex_from_names(&mut self, vertex: VertexId) {
559 if let Some(prior) = self.vertex_to_names.remove(&vertex) {
560 for name_vertex in prior {
561 if let Some((scope, name)) = self.name_vertex_lookup.get(&name_vertex).cloned() {
562 match scope {
563 NameScope::Workbook => {
564 if let Some(entry) = self.named_ranges.get_mut(&name) {
565 entry.dependents.remove(&vertex);
566 }
567 }
568 NameScope::Sheet(sheet_id) => {
569 if let Some(entry) =
570 self.sheet_named_ranges.get_mut(&(sheet_id, name.clone()))
571 {
572 entry.dependents.remove(&vertex);
573 }
574 }
575 }
576 }
577 }
578 }
579 }
580
581 pub(crate) fn attach_vertex_to_names(&mut self, vertex: VertexId, names: &[VertexId]) {
582 if names.is_empty() {
583 return;
584 }
585 let mut unique = FxHashSet::default();
586 let mut recorded = Vec::new();
587 for &name_vertex in names {
588 if !unique.insert(name_vertex) {
589 continue;
590 }
591 if let Some((scope, name)) = self.name_vertex_lookup.get(&name_vertex).cloned() {
592 match scope {
593 NameScope::Workbook => {
594 if let Some(entry) = self.named_ranges.get_mut(&name) {
595 entry.dependents.insert(vertex);
596 }
597 }
598 NameScope::Sheet(sheet_id) => {
599 if let Some(entry) =
600 self.sheet_named_ranges.get_mut(&(sheet_id, name.clone()))
601 {
602 entry.dependents.insert(vertex);
603 }
604 }
605 }
606 recorded.push(name_vertex);
607 }
608 }
609 if !recorded.is_empty() {
610 self.vertex_to_names.insert(vertex, recorded);
611 }
612 }
613
614 pub(super) fn unregister_name_cell_dependencies(&mut self, name_vertex: VertexId) {
615 if let Some(prev) = self.name_to_cell_dependencies.remove(&name_vertex) {
616 for dep in prev {
617 if let Some(set) = self.cell_to_name_dependents.get_mut(&dep) {
618 set.remove(&name_vertex);
619 if set.is_empty() {
620 self.cell_to_name_dependents.remove(&dep);
621 }
622 }
623 }
624 }
625 }
626
627 pub(super) fn register_name_cell_dependencies(
628 &mut self,
629 name_vertex: VertexId,
630 dependencies: &[VertexId],
631 ) {
632 self.unregister_name_cell_dependencies(name_vertex);
633 if dependencies.is_empty() {
634 return;
635 }
636 for dep in dependencies {
637 self.cell_to_name_dependents
638 .entry(*dep)
639 .or_default()
640 .insert(name_vertex);
641 }
642 self.name_to_cell_dependencies
643 .insert(name_vertex, dependencies.to_vec());
644 }
645
646 pub(crate) fn record_pending_name_reference(
647 &mut self,
648 sheet_id: SheetId,
649 name: &str,
650 formula_vertex: VertexId,
651 ) {
652 let key = self.name_lookup_key(name);
653 self.pending_name_links
654 .entry(key.clone())
655 .or_default()
656 .insert((sheet_id, formula_vertex));
657 self.vertex_to_pending_names
658 .entry(formula_vertex)
659 .or_default()
660 .insert(key);
661 }
662
663 pub(crate) fn clear_pending_name_references(&mut self, formula_vertex: VertexId) {
664 let Some(keys) = self.vertex_to_pending_names.remove(&formula_vertex) else {
665 return;
666 };
667
668 for key in keys {
669 let mut remove_key = false;
670 if let Some(entries) = self.pending_name_links.get_mut(&key) {
671 entries.retain(|(_, vertex_id)| *vertex_id != formula_vertex);
672 remove_key = entries.is_empty();
673 }
674 if remove_key {
675 self.pending_name_links.remove(&key);
676 }
677 }
678 }
679
680 pub(super) fn resolve_pending_name_references(&mut self, scope: NameScope, name: &str) {
681 let key = self.name_lookup_key(name);
682 if let Some(entries) = self.pending_name_links.remove(&key) {
683 for (sheet_id, formula_vertex) in entries {
684 let attach = match scope {
685 NameScope::Workbook => true,
686 NameScope::Sheet(expected) => expected == sheet_id,
687 };
688 if attach {
689 if let Some(ast) = self.get_formula(formula_vertex) {
690 self.rebuild_formula_dependencies(formula_vertex, &ast);
691 } else {
692 self.clear_pending_name_references(formula_vertex);
693 }
694 } else {
695 self.record_pending_name_reference(sheet_id, name, formula_vertex);
696 }
697 }
698 }
699 }
700
701 pub(super) fn name_depends_on_vertex(
702 &self,
703 name_vertex: VertexId,
704 target: VertexId,
705 visited: &mut FxHashSet<VertexId>,
706 ) -> bool {
707 if !visited.insert(name_vertex) {
708 return false;
709 }
710
711 for dependency in self.edges.out_edges(name_vertex).iter().copied() {
712 if dependency == target {
713 return true;
714 }
715
716 if matches!(
717 self.store.kind(dependency),
718 VertexKind::NamedScalar | VertexKind::NamedArray
719 ) && self.name_depends_on_vertex(dependency, target, visited)
720 {
721 return true;
722 }
723 }
724
725 false
726 }
727
728 pub(super) fn rebuild_name_dependencies(
729 &mut self,
730 vertex: VertexId,
731 definition: &NamedDefinition,
732 scope: NameScope,
733 ) -> Result<Vec<VertexId>, ExcelError> {
734 let formula_dependencies = if let NamedDefinition::Formula { ast, .. } = definition {
735 let current_sheet_id = match scope {
736 NameScope::Sheet(id) => id,
737 NameScope::Workbook => self.default_sheet_id,
738 };
739 let (dependencies, range_dependencies, _, _, _pending_names) =
740 self.extract_dependencies_with_pending_names(ast, current_sheet_id)?;
741 Some((dependencies, range_dependencies))
742 } else {
743 None
744 };
745
746 self.remove_dependent_edges(vertex);
747 self.unregister_name_cell_dependencies(vertex);
748
749 let mut dependencies: Vec<VertexId> = Vec::new();
750 let mut range_dependencies: Vec<SharedRangeRef<'static>> = Vec::new();
751 let mut placeholders = Vec::new();
752
753 match definition {
754 NamedDefinition::Cell(cell_ref) => {
755 let vertex_id = self.get_or_create_vertex(cell_ref, &mut placeholders);
756 dependencies.push(vertex_id);
757 }
758 NamedDefinition::Range(range_ref) => {
759 let height = range_ref
760 .end
761 .coord
762 .row()
763 .saturating_sub(range_ref.start.coord.row())
764 + 1;
765 let width = range_ref
766 .end
767 .coord
768 .col()
769 .saturating_sub(range_ref.start.coord.col())
770 + 1;
771 let size = (width * height) as usize;
772
773 if size <= self.config.range_expansion_limit {
774 for row in range_ref.start.coord.row()..=range_ref.end.coord.row() {
775 for col in range_ref.start.coord.col()..=range_ref.end.coord.col() {
776 let coord = Coord::new(row, col, true, true);
777 let addr = CellRef::new(range_ref.start.sheet_id, coord);
778 let vertex_id = self.get_or_create_vertex(&addr, &mut placeholders);
779 dependencies.push(vertex_id);
780 }
781 }
782 } else {
783 let sheet_loc = SharedSheetLocator::Id(range_ref.start.sheet_id);
784 let sr = formualizer_common::AxisBound::new(
785 range_ref.start.coord.row(),
786 range_ref.start.coord.row_abs(),
787 );
788 let sc = formualizer_common::AxisBound::new(
789 range_ref.start.coord.col(),
790 range_ref.start.coord.col_abs(),
791 );
792 let er = formualizer_common::AxisBound::new(
793 range_ref.end.coord.row(),
794 range_ref.end.coord.row_abs(),
795 );
796 let ec = formualizer_common::AxisBound::new(
797 range_ref.end.coord.col(),
798 range_ref.end.coord.col_abs(),
799 );
800 if let Ok(r) = SharedRangeRef::from_parts(
801 sheet_loc,
802 Some(sr),
803 Some(sc),
804 Some(er),
805 Some(ec),
806 ) {
807 range_dependencies.push(r.into_owned());
808 }
809 }
810 }
811 NamedDefinition::Literal(_) => {
812 }
814 NamedDefinition::Formula { .. } => {
815 let Some((formula_deps, range_deps)) = formula_dependencies else {
816 return Err(ExcelError::new(ExcelErrorKind::Error)
817 .with_message("Internal error: formula dependencies were not extracted"));
818 };
819 dependencies.extend(formula_deps);
820 range_dependencies.extend(range_deps);
821 }
822 }
823
824 if !dependencies.is_empty() {
825 self.add_dependent_edges(vertex, &dependencies);
826 }
827 self.register_name_cell_dependencies(vertex, &dependencies);
828
829 if !range_dependencies.is_empty() {
830 let sheet_id = match scope {
831 NameScope::Sheet(id) => id,
832 NameScope::Workbook => self.default_sheet_id,
833 };
834 self.add_range_dependent_edges(vertex, &range_dependencies, sheet_id);
835 }
836
837 Ok(dependencies
838 .iter()
839 .filter(|vid| {
840 matches!(
841 self.store.kind(**vid),
842 VertexKind::NamedScalar | VertexKind::NamedArray
843 )
844 })
845 .copied()
846 .collect())
847 }
848
849 pub fn adjust_named_ranges(
850 &mut self,
851 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
852 ) -> Result<(), ExcelError> {
853 let adjuster = crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster::new();
854
855 let changed = !self.named_ranges.is_empty() || !self.sheet_named_ranges.is_empty();
856 let workbook_context =
858 crate::engine::graph::editor::reference_adjuster::ReferenceContext::new(
859 self.default_sheet_id,
860 &self.sheet_reg,
861 );
862 let mut adjusted_named_ranges = self.named_ranges.clone();
865 let mut adjusted_sheet_named_ranges = self.sheet_named_ranges.clone();
866 for named_range in adjusted_named_ranges.values_mut() {
867 adjust_named_definition(
868 &mut named_range.definition,
869 &adjuster,
870 operation,
871 &workbook_context,
872 )?;
873 }
874
875 for ((scope_sheet_id, _), named_range) in adjusted_sheet_named_ranges.iter_mut() {
877 let context = crate::engine::graph::editor::reference_adjuster::ReferenceContext::new(
878 *scope_sheet_id,
879 &self.sheet_reg,
880 );
881 adjust_named_definition(&mut named_range.definition, &adjuster, operation, &context)?;
882 }
883 let changed_names: Vec<_> = adjusted_named_ranges
884 .iter()
885 .filter_map(|(key, adjusted)| {
886 self.named_ranges
887 .get(key)
888 .is_some_and(|current| current.definition != adjusted.definition)
889 .then_some((adjusted.vertex, adjusted.scope, adjusted.definition.clone()))
890 })
891 .chain(
892 adjusted_sheet_named_ranges
893 .iter()
894 .filter_map(|(key, adjusted)| {
895 self.sheet_named_ranges
896 .get(key)
897 .is_some_and(|current| current.definition != adjusted.definition)
898 .then_some((
899 adjusted.vertex,
900 adjusted.scope,
901 adjusted.definition.clone(),
902 ))
903 }),
904 )
905 .collect();
906 self.named_ranges = adjusted_named_ranges;
907 self.sheet_named_ranges = adjusted_sheet_named_ranges;
908 for &(vertex, scope, ref definition) in &changed_names {
909 self.detach_vertex_from_names(vertex);
910 self.store.set_kind(
911 vertex,
912 if matches!(definition, NamedDefinition::Range(_)) {
913 VertexKind::NamedArray
914 } else {
915 VertexKind::NamedScalar
916 },
917 );
918 let referenced_names = self.rebuild_name_dependencies(vertex, definition, scope)?;
919 if !referenced_names.is_empty() {
920 self.attach_vertex_to_names(vertex, &referenced_names);
921 }
922 }
923 self.mark_dirty_many(
924 &changed_names
925 .iter()
926 .map(|(vertex, _, _)| *vertex)
927 .collect::<Vec<_>>(),
928 );
929 if changed {
930 self.bump_symbol_revision();
931 }
932
933 Ok(())
934 }
935
936 pub fn mark_as_name_error(&mut self, vertex_id: VertexId) {
938 self.mark_vertex_dirty(vertex_id);
940 }
941
942 pub(super) fn mark_named_vertex_deleted(&mut self, named_range: &NamedRange) {
943 self.detach_vertex_from_names(named_range.vertex);
944 self.remove_dependent_edges(named_range.vertex);
945 self.unregister_name_cell_dependencies(named_range.vertex);
946 self.store.mark_deleted(named_range.vertex, true);
947 self.vertex_values.remove(&named_range.vertex);
948 self.vertex_formulas.remove(&named_range.vertex);
949 self.clear_formula_vertex_dirty(named_range.vertex);
950 self.volatile_vertices.remove(&named_range.vertex);
951 self.vertex_to_names.remove(&named_range.vertex);
952 self.name_vertex_lookup.remove(&named_range.vertex);
953 }
954}