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(
55 definition: &mut NamedDefinition,
56 adjuster: &crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster,
57 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
58 context: &crate::engine::graph::editor::reference_adjuster::ReferenceContext<'_>,
59) -> Result<(), ExcelError> {
60 use crate::engine::graph::editor::reference_adjuster::AbsShiftPolicy;
61 match definition {
62 NamedDefinition::Cell(cell_ref) => {
63 if let Some(adjusted) =
64 adjuster.adjust_cell_ref_with_policy(cell_ref, operation, AbsShiftPolicy::Pin)
65 {
66 *cell_ref = adjusted;
67 } else {
68 return Err(ExcelError::new(ExcelErrorKind::Ref));
69 }
70 }
71 NamedDefinition::Range(range_ref) => {
72 let adjusted_start = adjuster.adjust_cell_ref_with_policy(
73 &range_ref.start,
74 operation,
75 AbsShiftPolicy::Pin,
76 );
77 let adjusted_end = adjuster.adjust_cell_ref_with_policy(
78 &range_ref.end,
79 operation,
80 AbsShiftPolicy::Pin,
81 );
82
83 if let (Some(start), Some(end)) = (adjusted_start, adjusted_end) {
84 range_ref.start = start;
85 range_ref.end = end;
86 } else {
87 return Err(ExcelError::new(ExcelErrorKind::Ref));
88 }
89 }
90 NamedDefinition::Literal(_) => {
91 }
93 NamedDefinition::Formula {
94 ast,
95 dependencies,
96 range_deps,
97 } => {
98 let adjusted_ast = adjuster.adjust_ast_with_policy_in_context(
99 ast,
100 operation,
101 AbsShiftPolicy::Pin,
102 context,
103 );
104 *ast = adjusted_ast;
105
106 dependencies.clear();
107 range_deps.clear();
108 }
109 }
110 Ok(())
111}
112
113impl DependencyGraph {
114 #[inline]
115 pub(crate) fn name_lookup_key(&self, name: &str) -> String {
116 if self.config.case_sensitive_names {
117 name.to_string()
118 } else {
119 normalize_name_key(name)
120 }
121 }
122
123 fn canonical_name_in_scope(&self, scope: NameScope, name: &str) -> Option<String> {
124 let key = self.name_lookup_key(name);
125 match scope {
126 NameScope::Workbook => self.named_ranges_lookup.get(&key).cloned(),
127 NameScope::Sheet(sheet_id) => self
128 .sheet_named_ranges_lookup
129 .get(&(sheet_id, key))
130 .cloned(),
131 }
132 }
133
134 fn next_name_coord(&mut self) -> AbsCoord {
135 let seq = self.name_vertex_seq;
136 self.name_vertex_seq = self.name_vertex_seq.wrapping_add(1);
137 let row = (seq / 16_384).min(0x000F_FFFF);
138 let col = seq % 16_384;
139 AbsCoord::new(row, col)
140 }
141
142 pub(super) fn allocate_name_vertex(&mut self, scope: NameScope) -> VertexId {
143 let coord = self.next_name_coord();
144 let sheet_id = match scope {
145 NameScope::Sheet(id) => id,
146 NameScope::Workbook => self.default_sheet_id,
147 };
148 let vertex_id = self.store.allocate(coord, sheet_id, 0x01);
149 self.store.set_kind(vertex_id, VertexKind::NamedScalar);
150 self.mark_vertex_dirty(vertex_id);
151 self.edges.add_vertex(coord, vertex_id.0);
152 vertex_id
153 }
154
155 pub(crate) fn validate_define_name(
158 &self,
159 name: &str,
160 scope: NameScope,
161 ) -> Result<(), ExcelError> {
162 if !is_valid_excel_name(name) {
163 return Err(
164 ExcelError::new(ExcelErrorKind::Name).with_message(format!("Invalid name: {name}"))
165 );
166 }
167
168 let lookup_key = self.name_lookup_key(name);
169 match scope {
170 NameScope::Workbook => {
171 if let Some(existing) = self.named_ranges_lookup.get(&lookup_key) {
172 return Err(ExcelError::new(ExcelErrorKind::Name).with_message(format!(
173 "Name collision under normalization: '{name}' conflicts with '{existing}'"
174 )));
175 }
176 }
177 NameScope::Sheet(sheet_id) => {
178 if let Some(existing) = self.sheet_named_ranges_lookup.get(&(sheet_id, lookup_key))
179 {
180 return Err(ExcelError::new(ExcelErrorKind::Name).with_message(format!(
181 "Name collision under normalization in sheet: '{name}' conflicts with '{existing}'"
182 )));
183 }
184 }
185 }
186 Ok(())
187 }
188
189 pub(crate) fn validate_existing_name(
190 &self,
191 name: &str,
192 scope: NameScope,
193 ) -> Result<(), ExcelError> {
194 self.canonical_name_in_scope(scope, name)
195 .map(|_| ())
196 .ok_or_else(|| {
197 ExcelError::new(ExcelErrorKind::Name)
198 .with_message(format!("Name not found: {name}"))
199 })
200 }
201
202 pub fn define_name(
204 &mut self,
205 name: &str,
206 definition: NamedDefinition,
207 scope: NameScope,
208 ) -> Result<(), ExcelError> {
209 self.validate_define_name(name, scope)?;
210
211 let mut final_definition = definition;
212 if let NamedDefinition::Formula { ref ast, .. } = final_definition {
214 let (deps, range_deps, _, _) = self.extract_dependencies(
215 ast,
216 match scope {
217 NameScope::Sheet(id) => id,
218 NameScope::Workbook => self.default_sheet_id,
219 },
220 )?;
221 final_definition = NamedDefinition::Formula {
222 ast: ast.clone(),
223 dependencies: deps,
224 range_deps,
225 };
226 }
227
228 let vertex_id = self.allocate_name_vertex(scope);
230
231 let named_range = NamedRange {
232 definition: final_definition,
233 scope,
234 dependents: FxHashSet::default(),
235 vertex: vertex_id,
236 };
237
238 if matches!(named_range.definition, NamedDefinition::Range(_)) {
239 self.store.set_kind(vertex_id, VertexKind::NamedArray);
240 } else {
241 self.store.set_kind(vertex_id, VertexKind::NamedScalar);
242 }
243
244 let referenced_names =
245 self.rebuild_name_dependencies(vertex_id, &named_range.definition, scope);
246 if !referenced_names.is_empty() {
247 self.attach_vertex_to_names(vertex_id, &referenced_names);
248 }
249
250 let key = name.to_string();
251
252 match scope {
253 NameScope::Workbook => {
254 self.named_ranges.insert(key.clone(), named_range);
255 self.named_ranges_lookup
256 .insert(self.name_lookup_key(&key), key.clone());
257 }
258 NameScope::Sheet(id) => {
259 self.sheet_named_ranges
260 .insert((id, key.clone()), named_range);
261 self.sheet_named_ranges_lookup
262 .insert((id, self.name_lookup_key(&key)), key.clone());
263 }
264 }
265
266 self.name_vertex_lookup.insert(vertex_id, (scope, key));
267 self.resolve_pending_name_references(scope, name);
268 self.bump_symbol_revision();
269
270 Ok(())
271 }
272
273 pub fn named_ranges_iter(&self) -> impl Iterator<Item = (&String, &NamedRange)> {
275 self.named_ranges.iter()
276 }
277
278 pub fn sheet_named_ranges_iter(
280 &self,
281 ) -> impl Iterator<Item = (&(SheetId, String), &NamedRange)> {
282 self.sheet_named_ranges.iter()
283 }
284
285 pub fn resolve_name_entry_in_scope(&self, name: &str, scope: NameScope) -> Option<&NamedRange> {
297 let workbook_entry = || {
298 if self.config.case_sensitive_names {
299 self.named_ranges.get(name)
300 } else {
301 self.named_ranges_lookup
302 .get(&self.name_lookup_key(name))
303 .and_then(|canon| self.named_ranges.get(canon))
304 }
305 };
306
307 match scope {
308 NameScope::Workbook => workbook_entry(),
309 NameScope::Sheet(current_sheet) => {
310 if self.config.case_sensitive_names {
311 self.sheet_named_ranges
312 .get(&(current_sheet, name.to_string()))
313 .or_else(workbook_entry)
314 } else {
315 let key = self.name_lookup_key(name);
316 self.sheet_named_ranges_lookup
317 .get(&(current_sheet, key))
318 .and_then(|canon| {
319 self.sheet_named_ranges.get(&(current_sheet, canon.clone()))
320 })
321 .or_else(workbook_entry)
322 }
323 }
324 }
325 }
326
327 pub fn resolve_name_entry(&self, name: &str, current_sheet: SheetId) -> Option<&NamedRange> {
331 self.resolve_name_entry_in_scope(name, NameScope::Sheet(current_sheet))
332 }
333
334 pub fn resolve_name(&self, name: &str, current_sheet: SheetId) -> Option<&NamedDefinition> {
336 self.resolve_name_entry(name, current_sheet)
337 .map(|nr| &nr.definition)
338 }
339
340 pub(crate) fn name_key_for_vertex(&self, vertex: VertexId) -> Option<String> {
344 self.name_vertex_lookup
345 .get(&vertex)
346 .map(|(_, name)| self.name_lookup_key(name))
347 }
348
349 pub fn named_range_by_vertex(&self, vertex: VertexId) -> Option<&NamedRange> {
350 self.name_vertex_lookup
351 .get(&vertex)
352 .and_then(|(scope, name)| match scope {
353 NameScope::Workbook => self.named_ranges.get(name),
354 NameScope::Sheet(sheet_id) => {
355 self.sheet_named_ranges.get(&(*sheet_id, name.clone()))
356 }
357 })
358 }
359
360 pub fn update_name(
362 &mut self,
363 name: &str,
364 new_definition: NamedDefinition,
365 scope: NameScope,
366 ) -> Result<(), ExcelError> {
367 let Some(canon_name) = self.canonical_name_in_scope(scope, name) else {
368 return Err(ExcelError::new(ExcelErrorKind::Name)
369 .with_message(format!("Name not found: {name}")));
370 };
371
372 let dependents_to_dirty = match scope {
374 NameScope::Workbook => self
375 .named_ranges
376 .get(&canon_name)
377 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
378 NameScope::Sheet(id) => self
379 .sheet_named_ranges
380 .get(&(id, canon_name.clone()))
381 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
382 };
383
384 if let Some(dependents) = dependents_to_dirty {
385 for vertex_id in dependents {
387 self.mark_vertex_dirty(vertex_id);
388 }
389
390 let named_range = match scope {
392 NameScope::Workbook => self.named_ranges.get_mut(&canon_name),
393 NameScope::Sheet(id) => self.sheet_named_ranges.get_mut(&(id, canon_name.clone())),
394 };
395
396 let mut update_data: Option<(VertexId, NameScope, NamedDefinition, bool)> = None;
397 if let Some(named_range) = named_range {
398 named_range.definition = new_definition;
399 let is_range = matches!(named_range.definition, NamedDefinition::Range(_));
400 update_data = Some((
401 named_range.vertex,
402 named_range.scope,
403 named_range.definition.clone(),
404 is_range,
405 ));
406 }
407
408 if let Some((vertex, scope_value, definition_snapshot, is_range)) = update_data {
409 self.detach_vertex_from_names(vertex);
410
411 if is_range {
412 self.store.set_kind(vertex, VertexKind::NamedArray);
413 } else {
414 self.store.set_kind(vertex, VertexKind::NamedScalar);
415 }
416 self.mark_vertex_dirty(vertex);
417
418 let referenced_names =
419 self.rebuild_name_dependencies(vertex, &definition_snapshot, scope_value);
420 if !referenced_names.is_empty() {
421 self.attach_vertex_to_names(vertex, &referenced_names);
422 }
423 }
424
425 self.bump_symbol_revision();
426 Ok(())
427 } else {
428 Err(ExcelError::new(ExcelErrorKind::Name)
429 .with_message(format!("Name not found: {name}")))
430 }
431 }
432
433 pub fn delete_name(&mut self, name: &str, scope: NameScope) -> Result<(), ExcelError> {
435 let Some(canon_name) = self.canonical_name_in_scope(scope, name) else {
436 return Err(ExcelError::new(ExcelErrorKind::Name)
437 .with_message(format!("Name not found: {name}")));
438 };
439
440 let named_range = match scope {
441 NameScope::Workbook => {
442 let removed = self.named_ranges.remove(&canon_name);
443 let key = self.name_lookup_key(&canon_name);
444 self.named_ranges_lookup.remove(&key);
445 removed
446 }
447 NameScope::Sheet(id) => {
448 let removed = self.sheet_named_ranges.remove(&(id, canon_name.clone()));
449 let key = self.name_lookup_key(&canon_name);
450 self.sheet_named_ranges_lookup.remove(&(id, key));
451 removed
452 }
453 };
454
455 if let Some(named_range) = named_range {
456 let mut affected: FxHashSet<VertexId> = FxHashSet::default();
457 for &vertex_id in &named_range.dependents {
458 affected.insert(vertex_id);
459 }
460 for (vertex_id, names) in self.vertex_to_names.iter() {
461 if names.contains(&named_range.vertex) {
462 affected.insert(*vertex_id);
463 }
464 }
465 for vertex_id in affected {
466 self.mark_vertex_dirty(vertex_id);
467 if let Some(names) = self.vertex_to_names.get_mut(&vertex_id) {
468 names.retain(|vid| *vid != named_range.vertex);
469 if names.is_empty() {
470 self.vertex_to_names.remove(&vertex_id);
471 }
472 }
473 }
474 self.mark_named_vertex_deleted(&named_range);
475 self.bump_symbol_revision();
476 Ok(())
477 } else {
478 Err(ExcelError::new(ExcelErrorKind::Name)
479 .with_message(format!("Name not found: {name}")))
480 }
481 }
482
483 pub(super) fn detach_vertex_from_names(&mut self, vertex: VertexId) {
484 if let Some(prior) = self.vertex_to_names.remove(&vertex) {
485 for name_vertex in prior {
486 if let Some((scope, name)) = self.name_vertex_lookup.get(&name_vertex).cloned() {
487 match scope {
488 NameScope::Workbook => {
489 if let Some(entry) = self.named_ranges.get_mut(&name) {
490 entry.dependents.remove(&vertex);
491 }
492 }
493 NameScope::Sheet(sheet_id) => {
494 if let Some(entry) =
495 self.sheet_named_ranges.get_mut(&(sheet_id, name.clone()))
496 {
497 entry.dependents.remove(&vertex);
498 }
499 }
500 }
501 }
502 }
503 }
504 }
505
506 pub(crate) fn attach_vertex_to_names(&mut self, vertex: VertexId, names: &[VertexId]) {
507 if names.is_empty() {
508 return;
509 }
510 let mut unique = FxHashSet::default();
511 let mut recorded = Vec::new();
512 for &name_vertex in names {
513 if !unique.insert(name_vertex) {
514 continue;
515 }
516 if let Some((scope, name)) = self.name_vertex_lookup.get(&name_vertex).cloned() {
517 match scope {
518 NameScope::Workbook => {
519 if let Some(entry) = self.named_ranges.get_mut(&name) {
520 entry.dependents.insert(vertex);
521 }
522 }
523 NameScope::Sheet(sheet_id) => {
524 if let Some(entry) =
525 self.sheet_named_ranges.get_mut(&(sheet_id, name.clone()))
526 {
527 entry.dependents.insert(vertex);
528 }
529 }
530 }
531 recorded.push(name_vertex);
532 }
533 }
534 if !recorded.is_empty() {
535 self.vertex_to_names.insert(vertex, recorded);
536 }
537 }
538
539 pub(super) fn unregister_name_cell_dependencies(&mut self, name_vertex: VertexId) {
540 if let Some(prev) = self.name_to_cell_dependencies.remove(&name_vertex) {
541 for dep in prev {
542 if let Some(set) = self.cell_to_name_dependents.get_mut(&dep) {
543 set.remove(&name_vertex);
544 if set.is_empty() {
545 self.cell_to_name_dependents.remove(&dep);
546 }
547 }
548 }
549 }
550 }
551
552 pub(super) fn register_name_cell_dependencies(
553 &mut self,
554 name_vertex: VertexId,
555 dependencies: &[VertexId],
556 ) {
557 self.unregister_name_cell_dependencies(name_vertex);
558 if dependencies.is_empty() {
559 return;
560 }
561 for dep in dependencies {
562 self.cell_to_name_dependents
563 .entry(*dep)
564 .or_default()
565 .insert(name_vertex);
566 }
567 self.name_to_cell_dependencies
568 .insert(name_vertex, dependencies.to_vec());
569 }
570
571 pub(crate) fn record_pending_name_reference(
572 &mut self,
573 sheet_id: SheetId,
574 name: &str,
575 formula_vertex: VertexId,
576 ) {
577 let key = self.name_lookup_key(name);
578 self.pending_name_links
579 .entry(key.clone())
580 .or_default()
581 .insert((sheet_id, formula_vertex));
582 self.vertex_to_pending_names
583 .entry(formula_vertex)
584 .or_default()
585 .insert(key);
586 }
587
588 pub(crate) fn clear_pending_name_references(&mut self, formula_vertex: VertexId) {
589 let Some(keys) = self.vertex_to_pending_names.remove(&formula_vertex) else {
590 return;
591 };
592
593 for key in keys {
594 let mut remove_key = false;
595 if let Some(entries) = self.pending_name_links.get_mut(&key) {
596 entries.retain(|(_, vertex_id)| *vertex_id != formula_vertex);
597 remove_key = entries.is_empty();
598 }
599 if remove_key {
600 self.pending_name_links.remove(&key);
601 }
602 }
603 }
604
605 pub(super) fn resolve_pending_name_references(&mut self, scope: NameScope, name: &str) {
606 let key = self.name_lookup_key(name);
607 if let Some(entries) = self.pending_name_links.remove(&key) {
608 for (sheet_id, formula_vertex) in entries {
609 let attach = match scope {
610 NameScope::Workbook => true,
611 NameScope::Sheet(expected) => expected == sheet_id,
612 };
613 if attach {
614 if let Some(ast) = self.get_formula(formula_vertex) {
615 self.rebuild_formula_dependencies(formula_vertex, &ast);
616 } else {
617 self.clear_pending_name_references(formula_vertex);
618 }
619 } else {
620 self.record_pending_name_reference(sheet_id, name, formula_vertex);
621 }
622 }
623 }
624 }
625
626 pub(super) fn name_depends_on_vertex(
627 &self,
628 name_vertex: VertexId,
629 target: VertexId,
630 visited: &mut FxHashSet<VertexId>,
631 ) -> bool {
632 if !visited.insert(name_vertex) {
633 return false;
634 }
635
636 for dependency in self.edges.out_edges(name_vertex).iter().copied() {
637 if dependency == target {
638 return true;
639 }
640
641 if matches!(
642 self.store.kind(dependency),
643 VertexKind::NamedScalar | VertexKind::NamedArray
644 ) && self.name_depends_on_vertex(dependency, target, visited)
645 {
646 return true;
647 }
648 }
649
650 false
651 }
652
653 pub(super) fn rebuild_name_dependencies(
654 &mut self,
655 vertex: VertexId,
656 definition: &NamedDefinition,
657 scope: NameScope,
658 ) -> Vec<VertexId> {
659 self.remove_dependent_edges(vertex);
660 self.unregister_name_cell_dependencies(vertex);
661
662 let mut dependencies: Vec<VertexId> = Vec::new();
663 let mut range_dependencies: Vec<SharedRangeRef<'static>> = Vec::new();
664 let mut placeholders = Vec::new();
665
666 match definition {
667 NamedDefinition::Cell(cell_ref) => {
668 let vertex_id = self.get_or_create_vertex(cell_ref, &mut placeholders);
669 dependencies.push(vertex_id);
670 }
671 NamedDefinition::Range(range_ref) => {
672 let height = range_ref
673 .end
674 .coord
675 .row()
676 .saturating_sub(range_ref.start.coord.row())
677 + 1;
678 let width = range_ref
679 .end
680 .coord
681 .col()
682 .saturating_sub(range_ref.start.coord.col())
683 + 1;
684 let size = (width * height) as usize;
685
686 if size <= self.config.range_expansion_limit {
687 for row in range_ref.start.coord.row()..=range_ref.end.coord.row() {
688 for col in range_ref.start.coord.col()..=range_ref.end.coord.col() {
689 let coord = Coord::new(row, col, true, true);
690 let addr = CellRef::new(range_ref.start.sheet_id, coord);
691 let vertex_id = self.get_or_create_vertex(&addr, &mut placeholders);
692 dependencies.push(vertex_id);
693 }
694 }
695 } else {
696 let sheet_loc = SharedSheetLocator::Id(range_ref.start.sheet_id);
697 let sr = formualizer_common::AxisBound::new(
698 range_ref.start.coord.row(),
699 range_ref.start.coord.row_abs(),
700 );
701 let sc = formualizer_common::AxisBound::new(
702 range_ref.start.coord.col(),
703 range_ref.start.coord.col_abs(),
704 );
705 let er = formualizer_common::AxisBound::new(
706 range_ref.end.coord.row(),
707 range_ref.end.coord.row_abs(),
708 );
709 let ec = formualizer_common::AxisBound::new(
710 range_ref.end.coord.col(),
711 range_ref.end.coord.col_abs(),
712 );
713 if let Ok(r) = SharedRangeRef::from_parts(
714 sheet_loc,
715 Some(sr),
716 Some(sc),
717 Some(er),
718 Some(ec),
719 ) {
720 range_dependencies.push(r.into_owned());
721 }
722 }
723 }
724 NamedDefinition::Literal(_) => {
725 }
727 NamedDefinition::Formula {
728 dependencies: formula_deps,
729 range_deps,
730 ..
731 } => {
732 dependencies.extend(formula_deps.iter().copied());
733 range_dependencies.extend(range_deps.iter().cloned());
734 }
735 }
736
737 if !dependencies.is_empty() {
738 self.add_dependent_edges(vertex, &dependencies);
739 }
740 self.register_name_cell_dependencies(vertex, &dependencies);
741
742 if !range_dependencies.is_empty() {
743 let sheet_id = match scope {
744 NameScope::Sheet(id) => id,
745 NameScope::Workbook => self.default_sheet_id,
746 };
747 self.add_range_dependent_edges(vertex, &range_dependencies, sheet_id);
748 }
749
750 dependencies
751 .iter()
752 .filter(|vid| {
753 matches!(
754 self.store.kind(**vid),
755 VertexKind::NamedScalar | VertexKind::NamedArray
756 )
757 })
758 .copied()
759 .collect()
760 }
761
762 pub fn adjust_named_ranges(
763 &mut self,
764 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
765 ) -> Result<(), ExcelError> {
766 let adjuster = crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster::new();
767
768 let changed = !self.named_ranges.is_empty() || !self.sheet_named_ranges.is_empty();
769 let workbook_context =
771 crate::engine::graph::editor::reference_adjuster::ReferenceContext::new(
772 self.default_sheet_id,
773 &self.sheet_reg,
774 );
775 for named_range in self.named_ranges.values_mut() {
776 adjust_named_definition(
777 &mut named_range.definition,
778 &adjuster,
779 operation,
780 &workbook_context,
781 )?;
782 }
783
784 for ((scope_sheet_id, _), named_range) in self.sheet_named_ranges.iter_mut() {
786 let context = crate::engine::graph::editor::reference_adjuster::ReferenceContext::new(
787 *scope_sheet_id,
788 &self.sheet_reg,
789 );
790 adjust_named_definition(&mut named_range.definition, &adjuster, operation, &context)?;
791 }
792 if changed {
793 self.bump_symbol_revision();
794 }
795
796 Ok(())
797 }
798
799 pub fn mark_as_name_error(&mut self, vertex_id: VertexId) {
801 self.mark_vertex_dirty(vertex_id);
803 }
804
805 pub(super) fn mark_named_vertex_deleted(&mut self, named_range: &NamedRange) {
806 self.detach_vertex_from_names(named_range.vertex);
807 self.remove_dependent_edges(named_range.vertex);
808 self.unregister_name_cell_dependencies(named_range.vertex);
809 self.store.mark_deleted(named_range.vertex, true);
810 self.vertex_values.remove(&named_range.vertex);
811 self.vertex_formulas.remove(&named_range.vertex);
812 self.clear_formula_vertex_dirty(named_range.vertex);
813 self.volatile_vertices.remove(&named_range.vertex);
814 self.vertex_to_names.remove(&named_range.vertex);
815 self.name_vertex_lookup.remove(&named_range.vertex);
816 }
817}