1use super::*;
2use formualizer_common::parse_a1_1based;
3
4fn is_valid_excel_name(name: &str) -> bool {
6 if name.is_empty() || name.len() > 255 {
14 return false;
15 }
16
17 if parse_a1_1based(name).is_ok() {
18 return false;
19 }
20
21 let mut chars = name.chars();
22
23 if let Some(first) = chars.next()
25 && !first.is_alphabetic()
26 && first != '_'
27 && first != '\\'
28 {
29 return false;
30 }
31
32 for c in chars {
34 if !c.is_alphanumeric() && c != '.' && c != '_' {
35 return false;
36 }
37 }
38
39 true
40}
41
42fn adjust_named_definition(
44 definition: &mut NamedDefinition,
45 adjuster: &crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster,
46 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
47) -> Result<(), ExcelError> {
48 match definition {
49 NamedDefinition::Cell(cell_ref) => {
50 if let Some(adjusted) = adjuster.adjust_cell_ref(cell_ref, operation) {
51 *cell_ref = adjusted;
52 } else {
53 return Err(ExcelError::new(ExcelErrorKind::Ref));
54 }
55 }
56 NamedDefinition::Range(range_ref) => {
57 let adjusted_start = adjuster.adjust_cell_ref(&range_ref.start, operation);
58 let adjusted_end = adjuster.adjust_cell_ref(&range_ref.end, operation);
59
60 if let (Some(start), Some(end)) = (adjusted_start, adjusted_end) {
61 range_ref.start = start;
62 range_ref.end = end;
63 } else {
64 return Err(ExcelError::new(ExcelErrorKind::Ref));
65 }
66 }
67 NamedDefinition::Formula {
68 ast,
69 dependencies,
70 range_deps,
71 } => {
72 let adjusted_ast = adjuster.adjust_ast(ast, operation);
73 *ast = adjusted_ast;
74
75 dependencies.clear();
76 range_deps.clear();
77 }
78 }
79 Ok(())
80}
81
82impl DependencyGraph {
83 fn next_name_coord(&mut self) -> AbsCoord {
84 let seq = self.name_vertex_seq;
85 self.name_vertex_seq = self.name_vertex_seq.wrapping_add(1);
86 let row = (seq / 16_384).min(0x000F_FFFF);
87 let col = seq % 16_384;
88 AbsCoord::new(row, col)
89 }
90
91 pub(super) fn allocate_name_vertex(&mut self, scope: NameScope) -> VertexId {
92 let coord = self.next_name_coord();
93 let sheet_id = match scope {
94 NameScope::Sheet(id) => id,
95 NameScope::Workbook => self.default_sheet_id,
96 };
97 let vertex_id = self.store.allocate(coord, sheet_id, 0x01);
98 self.store.set_kind(vertex_id, VertexKind::NamedScalar);
99 self.store.set_dirty(vertex_id, true);
100 self.edges.add_vertex(coord, vertex_id.0);
101 self.dirty_vertices.insert(vertex_id);
102 vertex_id
103 }
104
105 pub fn define_name(
109 &mut self,
110 name: &str,
111 definition: NamedDefinition,
112 scope: NameScope,
113 ) -> Result<(), ExcelError> {
114 if !is_valid_excel_name(name) {
116 return Err(
117 ExcelError::new(ExcelErrorKind::Name).with_message(format!("Invalid name: {name}"))
118 );
119 }
120
121 match scope {
123 NameScope::Workbook => {
124 if self.named_ranges.contains_key(name) {
125 return Err(ExcelError::new(ExcelErrorKind::Name)
126 .with_message(format!("Name already exists: {name}")));
127 }
128 }
129 NameScope::Sheet(sheet_id) => {
130 if self
131 .sheet_named_ranges
132 .contains_key(&(sheet_id, name.to_string()))
133 {
134 return Err(ExcelError::new(ExcelErrorKind::Name)
135 .with_message(format!("Name already exists in sheet: {name}")));
136 }
137 }
138 }
139
140 let mut final_definition = definition;
141 if let NamedDefinition::Formula { ref ast, .. } = final_definition {
143 let (deps, range_deps, _, _) = self.extract_dependencies(
144 ast,
145 match scope {
146 NameScope::Sheet(id) => id,
147 NameScope::Workbook => self.default_sheet_id,
148 },
149 )?;
150 final_definition = NamedDefinition::Formula {
151 ast: ast.clone(),
152 dependencies: deps,
153 range_deps,
154 };
155 }
156
157 let vertex_id = self.allocate_name_vertex(scope);
159
160 let named_range = NamedRange {
161 definition: final_definition,
162 scope,
163 dependents: FxHashSet::default(),
164 vertex: vertex_id,
165 };
166
167 if matches!(named_range.definition, NamedDefinition::Range(_)) {
168 self.store.set_kind(vertex_id, VertexKind::NamedArray);
169 } else {
170 self.store.set_kind(vertex_id, VertexKind::NamedScalar);
171 }
172
173 let referenced_names =
174 self.rebuild_name_dependencies(vertex_id, &named_range.definition, scope);
175 if !referenced_names.is_empty() {
176 self.attach_vertex_to_names(vertex_id, &referenced_names);
177 }
178
179 let key = name.to_string();
180
181 match scope {
182 NameScope::Workbook => {
183 self.named_ranges.insert(key.clone(), named_range);
184 }
185 NameScope::Sheet(id) => {
186 self.sheet_named_ranges
187 .insert((id, key.clone()), named_range);
188 }
189 }
190
191 self.name_vertex_lookup.insert(vertex_id, (scope, key));
192 self.resolve_pending_name_references(scope, name, vertex_id);
193
194 Ok(())
195 }
196
197 pub fn named_ranges_iter(&self) -> impl Iterator<Item = (&String, &NamedRange)> {
199 self.named_ranges.iter()
200 }
201
202 pub fn sheet_named_ranges_iter(
204 &self,
205 ) -> impl Iterator<Item = (&(SheetId, String), &NamedRange)> {
206 self.sheet_named_ranges.iter()
207 }
208
209 pub fn resolve_name_entry(&self, name: &str, current_sheet: SheetId) -> Option<&NamedRange> {
210 self.sheet_named_ranges
211 .get(&(current_sheet, name.to_string()))
212 .or_else(|| self.named_ranges.get(name))
213 }
214
215 pub fn resolve_name(&self, name: &str, current_sheet: SheetId) -> Option<&NamedDefinition> {
217 self.resolve_name_entry(name, current_sheet)
218 .map(|nr| &nr.definition)
219 }
220
221 pub fn named_range_by_vertex(&self, vertex: VertexId) -> Option<&NamedRange> {
222 self.name_vertex_lookup
223 .get(&vertex)
224 .and_then(|(scope, name)| match scope {
225 NameScope::Workbook => self.named_ranges.get(name),
226 NameScope::Sheet(sheet_id) => {
227 self.sheet_named_ranges.get(&(*sheet_id, name.clone()))
228 }
229 })
230 }
231
232 pub fn update_name(
234 &mut self,
235 name: &str,
236 new_definition: NamedDefinition,
237 scope: NameScope,
238 ) -> Result<(), ExcelError> {
239 let dependents_to_dirty = match scope {
241 NameScope::Workbook => self
242 .named_ranges
243 .get(name)
244 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
245 NameScope::Sheet(id) => self
246 .sheet_named_ranges
247 .get(&(id, name.to_string()))
248 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
249 };
250
251 if let Some(dependents) = dependents_to_dirty {
252 for vertex_id in dependents {
254 self.mark_vertex_dirty(vertex_id);
255 }
256
257 let named_range = match scope {
259 NameScope::Workbook => self.named_ranges.get_mut(name),
260 NameScope::Sheet(id) => self.sheet_named_ranges.get_mut(&(id, name.to_string())),
261 };
262
263 let mut update_data: Option<(VertexId, NameScope, NamedDefinition, bool)> = None;
264 if let Some(named_range) = named_range {
265 named_range.definition = new_definition;
266 named_range.dependents.clear();
267 let is_range = matches!(named_range.definition, NamedDefinition::Range(_));
268 update_data = Some((
269 named_range.vertex,
270 named_range.scope,
271 named_range.definition.clone(),
272 is_range,
273 ));
274 }
275
276 if let Some((vertex, scope_value, definition_snapshot, is_range)) = update_data {
277 self.detach_vertex_from_names(vertex);
278
279 if is_range {
280 self.store.set_kind(vertex, VertexKind::NamedArray);
281 } else {
282 self.store.set_kind(vertex, VertexKind::NamedScalar);
283 }
284 self.store.set_dirty(vertex, true);
285 self.dirty_vertices.insert(vertex);
286
287 let referenced_names =
288 self.rebuild_name_dependencies(vertex, &definition_snapshot, scope_value);
289 if !referenced_names.is_empty() {
290 self.attach_vertex_to_names(vertex, &referenced_names);
291 }
292 }
293
294 Ok(())
295 } else {
296 Err(ExcelError::new(ExcelErrorKind::Name)
297 .with_message(format!("Name not found: {name}")))
298 }
299 }
300
301 pub fn delete_name(&mut self, name: &str, scope: NameScope) -> Result<(), ExcelError> {
303 let named_range = match scope {
304 NameScope::Workbook => self.named_ranges.remove(name),
305 NameScope::Sheet(id) => self.sheet_named_ranges.remove(&(id, name.to_string())),
306 };
307
308 if let Some(named_range) = named_range {
309 let mut affected: FxHashSet<VertexId> = FxHashSet::default();
310 for &vertex_id in &named_range.dependents {
311 affected.insert(vertex_id);
312 }
313 for (vertex_id, names) in self.vertex_to_names.iter() {
314 if names.iter().any(|vid| *vid == named_range.vertex) {
315 affected.insert(*vertex_id);
316 }
317 }
318 for vertex_id in affected {
319 self.mark_vertex_dirty(vertex_id);
320 if let Some(names) = self.vertex_to_names.get_mut(&vertex_id) {
321 names.retain(|vid| *vid != named_range.vertex);
322 if names.is_empty() {
323 self.vertex_to_names.remove(&vertex_id);
324 }
325 }
326 }
327 self.mark_named_vertex_deleted(&named_range);
328 Ok(())
329 } else {
330 Err(ExcelError::new(ExcelErrorKind::Name)
331 .with_message(format!("Name not found: {name}")))
332 }
333 }
334
335 pub(super) fn detach_vertex_from_names(&mut self, vertex: VertexId) {
336 if let Some(prior) = self.vertex_to_names.remove(&vertex) {
337 for name_vertex in prior {
338 if let Some((scope, name)) = self.name_vertex_lookup.get(&name_vertex).cloned() {
339 match scope {
340 NameScope::Workbook => {
341 if let Some(entry) = self.named_ranges.get_mut(&name) {
342 entry.dependents.remove(&vertex);
343 }
344 }
345 NameScope::Sheet(sheet_id) => {
346 if let Some(entry) =
347 self.sheet_named_ranges.get_mut(&(sheet_id, name.clone()))
348 {
349 entry.dependents.remove(&vertex);
350 }
351 }
352 }
353 }
354 }
355 }
356 }
357
358 pub(crate) fn attach_vertex_to_names(&mut self, vertex: VertexId, names: &[VertexId]) {
359 if names.is_empty() {
360 return;
361 }
362 let mut unique = FxHashSet::default();
363 let mut recorded = Vec::new();
364 for &name_vertex in names {
365 if !unique.insert(name_vertex) {
366 continue;
367 }
368 if let Some((scope, name)) = self.name_vertex_lookup.get(&name_vertex).cloned() {
369 match scope {
370 NameScope::Workbook => {
371 if let Some(entry) = self.named_ranges.get_mut(&name) {
372 entry.dependents.insert(vertex);
373 }
374 }
375 NameScope::Sheet(sheet_id) => {
376 if let Some(entry) =
377 self.sheet_named_ranges.get_mut(&(sheet_id, name.clone()))
378 {
379 entry.dependents.insert(vertex);
380 }
381 }
382 }
383 recorded.push(name_vertex);
384 }
385 }
386 if !recorded.is_empty() {
387 self.vertex_to_names.insert(vertex, recorded);
388 }
389 }
390
391 pub(super) fn unregister_name_cell_dependencies(&mut self, name_vertex: VertexId) {
392 if let Some(prev) = self.name_to_cell_dependencies.remove(&name_vertex) {
393 for dep in prev {
394 if let Some(set) = self.cell_to_name_dependents.get_mut(&dep) {
395 set.remove(&name_vertex);
396 if set.is_empty() {
397 self.cell_to_name_dependents.remove(&dep);
398 }
399 }
400 }
401 }
402 }
403
404 pub(super) fn register_name_cell_dependencies(
405 &mut self,
406 name_vertex: VertexId,
407 dependencies: &[VertexId],
408 ) {
409 self.unregister_name_cell_dependencies(name_vertex);
410 if dependencies.is_empty() {
411 return;
412 }
413 for dep in dependencies {
414 self.cell_to_name_dependents
415 .entry(*dep)
416 .or_default()
417 .insert(name_vertex);
418 }
419 self.name_to_cell_dependencies
420 .insert(name_vertex, dependencies.to_vec());
421 }
422
423 pub(crate) fn record_pending_name_reference(
424 &mut self,
425 sheet_id: SheetId,
426 name: &str,
427 formula_vertex: VertexId,
428 ) {
429 self.pending_name_links
430 .entry(name.to_string())
431 .or_default()
432 .push((sheet_id, formula_vertex));
433 }
434
435 fn resolve_pending_name_references(
436 &mut self,
437 scope: NameScope,
438 name: &str,
439 named_vertex: VertexId,
440 ) {
441 if let Some(mut entries) = self.pending_name_links.remove(name) {
442 let mut remaining: Vec<(SheetId, VertexId)> = Vec::new();
443 for (sheet_id, formula_vertex) in entries.drain(..) {
444 let attach = match scope {
445 NameScope::Workbook => true,
446 NameScope::Sheet(expected) => expected == sheet_id,
447 };
448 if attach {
449 self.add_dependent_edges(formula_vertex, &[named_vertex]);
450 self.attach_vertex_to_names(formula_vertex, &[named_vertex]);
451 } else {
452 remaining.push((sheet_id, formula_vertex));
453 }
454 }
455 if !remaining.is_empty() {
456 self.pending_name_links.insert(name.to_string(), remaining);
457 }
458 }
459 }
460
461 pub(super) fn name_depends_on_vertex(
462 &self,
463 name_vertex: VertexId,
464 target: VertexId,
465 visited: &mut FxHashSet<VertexId>,
466 ) -> bool {
467 if !visited.insert(name_vertex) {
468 return false;
469 }
470
471 for dependency in self.edges.out_edges(name_vertex).iter().copied() {
472 if dependency == target {
473 return true;
474 }
475
476 if matches!(
477 self.store.kind(dependency),
478 VertexKind::NamedScalar | VertexKind::NamedArray
479 ) && self.name_depends_on_vertex(dependency, target, visited)
480 {
481 return true;
482 }
483 }
484
485 false
486 }
487
488 pub(super) fn rebuild_name_dependencies(
489 &mut self,
490 vertex: VertexId,
491 definition: &NamedDefinition,
492 scope: NameScope,
493 ) -> Vec<VertexId> {
494 self.remove_dependent_edges(vertex);
495 self.unregister_name_cell_dependencies(vertex);
496
497 let mut dependencies: Vec<VertexId> = Vec::new();
498 let mut range_dependencies: Vec<SharedRangeRef<'static>> = Vec::new();
499 let mut placeholders = Vec::new();
500
501 match definition {
502 NamedDefinition::Cell(cell_ref) => {
503 let vertex_id = self.get_or_create_vertex(cell_ref, &mut placeholders);
504 dependencies.push(vertex_id);
505 }
506 NamedDefinition::Range(range_ref) => {
507 let height = range_ref
508 .end
509 .coord
510 .row()
511 .saturating_sub(range_ref.start.coord.row())
512 + 1;
513 let width = range_ref
514 .end
515 .coord
516 .col()
517 .saturating_sub(range_ref.start.coord.col())
518 + 1;
519 let size = (width * height) as usize;
520
521 if size <= self.config.range_expansion_limit {
522 for row in range_ref.start.coord.row()..=range_ref.end.coord.row() {
523 for col in range_ref.start.coord.col()..=range_ref.end.coord.col() {
524 let coord = Coord::new(row, col, true, true);
525 let addr = CellRef::new(range_ref.start.sheet_id, coord);
526 let vertex_id = self.get_or_create_vertex(&addr, &mut placeholders);
527 dependencies.push(vertex_id);
528 }
529 }
530 } else {
531 let sheet_loc = SharedSheetLocator::Id(range_ref.start.sheet_id);
532 let sr = formualizer_common::AxisBound::new(
533 range_ref.start.coord.row(),
534 range_ref.start.coord.row_abs(),
535 );
536 let sc = formualizer_common::AxisBound::new(
537 range_ref.start.coord.col(),
538 range_ref.start.coord.col_abs(),
539 );
540 let er = formualizer_common::AxisBound::new(
541 range_ref.end.coord.row(),
542 range_ref.end.coord.row_abs(),
543 );
544 let ec = formualizer_common::AxisBound::new(
545 range_ref.end.coord.col(),
546 range_ref.end.coord.col_abs(),
547 );
548 if let Ok(r) = SharedRangeRef::from_parts(
549 sheet_loc,
550 Some(sr),
551 Some(sc),
552 Some(er),
553 Some(ec),
554 ) {
555 range_dependencies.push(r.into_owned());
556 }
557 }
558 }
559 NamedDefinition::Formula {
560 dependencies: formula_deps,
561 range_deps,
562 ..
563 } => {
564 dependencies.extend(formula_deps.iter().copied());
565 range_dependencies.extend(range_deps.iter().cloned());
566 }
567 }
568
569 if !dependencies.is_empty() {
570 self.add_dependent_edges(vertex, &dependencies);
571 }
572 self.register_name_cell_dependencies(vertex, &dependencies);
573
574 if !range_dependencies.is_empty() {
575 let sheet_id = match scope {
576 NameScope::Sheet(id) => id,
577 NameScope::Workbook => self.default_sheet_id,
578 };
579 self.add_range_dependent_edges(vertex, &range_dependencies, sheet_id);
580 }
581
582 dependencies
583 .iter()
584 .filter(|vid| {
585 matches!(
586 self.store.kind(**vid),
587 VertexKind::NamedScalar | VertexKind::NamedArray
588 )
589 })
590 .copied()
591 .collect()
592 }
593
594 pub fn adjust_named_ranges(
595 &mut self,
596 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
597 ) -> Result<(), ExcelError> {
598 let adjuster = crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster::new();
599
600 for named_range in self.named_ranges.values_mut() {
602 adjust_named_definition(&mut named_range.definition, &adjuster, operation)?;
603 }
604
605 for named_range in self.sheet_named_ranges.values_mut() {
607 adjust_named_definition(&mut named_range.definition, &adjuster, operation)?;
608 }
609
610 Ok(())
611 }
612
613 pub fn mark_as_name_error(&mut self, vertex_id: VertexId) {
615 self.mark_vertex_dirty(vertex_id);
617 }
618
619 pub(super) fn mark_named_vertex_deleted(&mut self, named_range: &NamedRange) {
620 self.detach_vertex_from_names(named_range.vertex);
621 self.remove_dependent_edges(named_range.vertex);
622 self.unregister_name_cell_dependencies(named_range.vertex);
623 self.store.mark_deleted(named_range.vertex, true);
624 self.vertex_values.remove(&named_range.vertex);
625 self.vertex_formulas.remove(&named_range.vertex);
626 self.dirty_vertices.remove(&named_range.vertex);
627 self.volatile_vertices.remove(&named_range.vertex);
628 self.vertex_to_names.remove(&named_range.vertex);
629 self.name_vertex_lookup.remove(&named_range.vertex);
630 }
631}