formualizer_eval/engine/graph/
sheets.rs1use super::ast_utils::{update_internal_sheet_references, update_sheet_references_in_ast};
2use super::*;
3
4impl DependencyGraph {
5 pub fn add_sheet(&mut self, name: &str) -> Result<SheetId, ExcelError> {
10 if let Some(id) = self.sheet_reg.get_id(name) {
11 return Ok(id);
12 }
13
14 let sheet_id = self.sheet_reg.id_for(name);
15 self.sheet_indexes.entry(sheet_id).or_default();
16 Ok(sheet_id)
17 }
18
19 pub fn remove_sheet(&mut self, sheet_id: SheetId) -> Result<(), ExcelError> {
21 if self.sheet_reg.name(sheet_id).is_empty() {
22 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Sheet does not exist"));
23 }
24
25 let sheet_count = self.sheet_reg.all_sheets().len();
26 if sheet_count <= 1 {
27 return Err(
28 ExcelError::new(ExcelErrorKind::Value).with_message("Cannot remove the last sheet")
29 );
30 }
31
32 self.begin_batch();
33
34 let vertices_to_delete: Vec<VertexId> = self.vertices_in_sheet(sheet_id).collect();
35
36 let mut formulas_to_update = Vec::new();
37 for &formula_id in self.vertex_formulas.keys() {
38 let deps = self.edges.out_edges(formula_id);
39 for dep_id in deps {
40 if self.store.sheet_id(dep_id) == sheet_id {
41 formulas_to_update.push(formula_id);
42 break;
43 }
44 }
45 }
46
47 for formula_id in formulas_to_update {
48 self.mark_as_ref_error(formula_id);
49 }
50
51 let ref_err = LiteralValue::Error(ExcelError::new(ExcelErrorKind::Ref));
57 let mut name_vertices_to_update: Vec<VertexId> = Vec::new();
58 let mut dirty_vertices: Vec<VertexId> = Vec::new();
59
60 for nr in self.named_ranges.values_mut() {
61 match &nr.definition {
62 NamedDefinition::Cell(c) if c.sheet_id == sheet_id => {
63 nr.definition = NamedDefinition::Literal(ref_err.clone());
64 name_vertices_to_update.push(nr.vertex);
65 dirty_vertices.push(nr.vertex);
66 dirty_vertices.extend(nr.dependents.iter().copied());
67 }
68 NamedDefinition::Range(r)
69 if r.start.sheet_id == sheet_id || r.end.sheet_id == sheet_id =>
70 {
71 nr.definition = NamedDefinition::Literal(ref_err.clone());
72 name_vertices_to_update.push(nr.vertex);
73 dirty_vertices.push(nr.vertex);
74 dirty_vertices.extend(nr.dependents.iter().copied());
75 }
76 _ => {}
77 }
78 }
79 for nr in self.sheet_named_ranges.values_mut() {
80 match &nr.definition {
81 NamedDefinition::Cell(c) if c.sheet_id == sheet_id => {
82 nr.definition = NamedDefinition::Literal(ref_err.clone());
83 name_vertices_to_update.push(nr.vertex);
84 dirty_vertices.push(nr.vertex);
85 dirty_vertices.extend(nr.dependents.iter().copied());
86 }
87 NamedDefinition::Range(r)
88 if r.start.sheet_id == sheet_id || r.end.sheet_id == sheet_id =>
89 {
90 nr.definition = NamedDefinition::Literal(ref_err.clone());
91 name_vertices_to_update.push(nr.vertex);
92 dirty_vertices.push(nr.vertex);
93 dirty_vertices.extend(nr.dependents.iter().copied());
94 }
95 _ => {}
96 }
97 }
98
99 for vid in name_vertices_to_update {
101 self.update_vertex_value(vid, ref_err.clone());
102 }
103 for vid in dirty_vertices {
104 self.mark_vertex_dirty(vid);
105 }
106
107 for vertex_id in vertices_to_delete {
108 if let Some(cell_ref) = self.get_cell_ref_for_vertex(vertex_id) {
109 self.cell_to_vertex.remove(&cell_ref);
110 }
111
112 self.remove_all_edges(vertex_id);
113
114 let coord = self.store.coord(vertex_id);
115 if let Some(index) = self.sheet_indexes.get_mut(&sheet_id) {
116 index.remove_vertex(coord, vertex_id);
117 }
118
119 self.vertex_formulas.remove(&vertex_id);
120 self.vertex_values.remove(&vertex_id);
121
122 self.mark_deleted(vertex_id, true);
123 }
124
125 let sheet_names_to_remove: Vec<(SheetId, String)> = self
126 .sheet_named_ranges
127 .keys()
128 .filter(|(sid, _)| *sid == sheet_id)
129 .cloned()
130 .collect();
131
132 for key in sheet_names_to_remove {
133 if let Some(named_range) = self.sheet_named_ranges.remove(&key) {
134 if !self.config.case_sensitive_names {
135 let normalized = key.1.to_ascii_lowercase();
136 self.sheet_named_ranges_lookup
137 .remove(&(sheet_id, normalized));
138 } else {
139 self.sheet_named_ranges_lookup.remove(&key);
140 }
141 self.mark_named_vertex_deleted(&named_range);
142 }
143 }
144
145 self.sheet_indexes.remove(&sheet_id);
146
147 if self.default_sheet_id == sheet_id
148 && let Some(&new_default) = self.sheet_indexes.keys().next()
149 {
150 self.default_sheet_id = new_default;
151 }
152
153 self.sheet_reg.remove(sheet_id)?;
154 self.end_batch();
155
156 Ok(())
157 }
158
159 pub fn rename_sheet(&mut self, sheet_id: SheetId, new_name: &str) -> Result<(), ExcelError> {
161 if new_name.is_empty() || new_name.len() > 255 {
162 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Invalid sheet name"));
163 }
164
165 let old_name = self.sheet_reg.name(sheet_id);
166 if old_name.is_empty() {
167 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Sheet does not exist"));
168 }
169
170 if let Some(existing_id) = self.sheet_reg.get_id(new_name) {
171 if existing_id != sheet_id {
172 return Err(ExcelError::new(ExcelErrorKind::Value)
173 .with_message(format!("Sheet '{new_name}' already exists")));
174 }
175 return Ok(());
176 }
177
178 let old_name = old_name.to_string();
179 self.sheet_reg.rename(sheet_id, new_name)?;
180
181 let formulas_to_update: Vec<VertexId> = self.vertex_formulas.keys().copied().collect();
182 for formula_id in formulas_to_update {
183 let ast_id = match self.get_formula_id(formula_id) {
184 Some(ast_id) => ast_id,
185 None => continue,
186 };
187 let ast = match self.data_store.retrieve_ast(ast_id, &self.sheet_reg) {
188 Some(ast) => ast,
189 None => continue,
190 };
191
192 let updated_ast = update_sheet_references_in_ast(&ast, &old_name, new_name);
193 if ast != updated_ast {
194 let updated_ast_id = self.data_store.store_ast(&updated_ast, &self.sheet_reg);
195 self.vertex_formulas.insert(formula_id, updated_ast_id);
196 self.mark_vertex_dirty(formula_id);
197 }
198 }
199
200 Ok(())
201 }
202
203 pub fn duplicate_sheet(
205 &mut self,
206 source_sheet_id: SheetId,
207 new_name: &str,
208 ) -> Result<SheetId, ExcelError> {
209 if new_name.is_empty() || new_name.len() > 255 {
210 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Invalid sheet name"));
211 }
212
213 let source_name = self.sheet_reg.name(source_sheet_id).to_string();
214 if source_name.is_empty() {
215 return Err(
216 ExcelError::new(ExcelErrorKind::Value).with_message("Source sheet does not exist")
217 );
218 }
219
220 if self.sheet_reg.get_id(new_name).is_some() {
221 return Err(ExcelError::new(ExcelErrorKind::Value)
222 .with_message(format!("Sheet '{new_name}' already exists")));
223 }
224
225 let new_sheet_id = self.add_sheet(new_name)?;
226
227 self.begin_batch();
228
229 let source_vertices: Vec<(VertexId, AbsCoord)> = self
230 .vertices_in_sheet(source_sheet_id)
231 .map(|id| (id, self.store.coord(id)))
232 .collect();
233
234 let mut vertex_mapping = FxHashMap::default();
235
236 for (old_id, coord) in &source_vertices {
237 let row = coord.row();
238 let col = coord.col();
239 let kind = self.store.kind(*old_id);
240
241 let new_id = self.store.allocate(*coord, new_sheet_id, 0x01);
242 self.edges.add_vertex(*coord, new_id.0);
243 self.sheet_index_mut(new_sheet_id)
244 .add_vertex(*coord, new_id);
245
246 self.store.set_kind(new_id, kind);
247
248 if let Some(&value_ref) = self.vertex_values.get(old_id) {
249 self.vertex_values.insert(new_id, value_ref);
250 }
251
252 vertex_mapping.insert(*old_id, new_id);
253
254 let cell_ref = CellRef::new(new_sheet_id, Coord::new(row, col, true, true));
255 self.cell_to_vertex.insert(cell_ref, new_id);
256 }
257
258 for (old_id, _) in &source_vertices {
259 if let Some(&new_id) = vertex_mapping.get(old_id)
260 && let Some(&ast_id) = self.vertex_formulas.get(old_id)
261 && let Some(ast) = self.data_store.retrieve_ast(ast_id, &self.sheet_reg)
262 {
263 let updated_ast = update_internal_sheet_references(
264 &ast,
265 &source_name,
266 new_name,
267 source_sheet_id,
268 new_sheet_id,
269 );
270
271 let new_ast_id = self.data_store.store_ast(&updated_ast, &self.sheet_reg);
272 self.vertex_formulas.insert(new_id, new_ast_id);
273
274 if let Ok((deps, range_deps, _, name_vertices)) =
275 self.extract_dependencies(&updated_ast, new_sheet_id)
276 {
277 let mapped_deps: Vec<VertexId> = deps
278 .iter()
279 .map(|&dep_id| vertex_mapping.get(&dep_id).copied().unwrap_or(dep_id))
280 .collect();
281
282 self.add_dependent_edges(new_id, &mapped_deps);
283 self.add_range_dependent_edges(new_id, &range_deps, new_sheet_id);
284
285 if !name_vertices.is_empty() {
286 self.attach_vertex_to_names(new_id, &name_vertices);
287 }
288 }
289 }
290 }
291
292 let sheet_names: Vec<(String, NamedRange)> = self
293 .sheet_named_ranges
294 .iter()
295 .filter(|((sid, _), _)| *sid == source_sheet_id)
296 .map(|((_, name), range)| (name.clone(), range.clone()))
297 .collect();
298
299 for (name, mut named_range) in sheet_names {
300 named_range.scope = NameScope::Sheet(new_sheet_id);
301
302 match &mut named_range.definition {
303 NamedDefinition::Cell(cell_ref) if cell_ref.sheet_id == source_sheet_id => {
304 cell_ref.sheet_id = new_sheet_id;
305 }
306 NamedDefinition::Range(range_ref) => {
307 if range_ref.start.sheet_id == source_sheet_id {
308 range_ref.start.sheet_id = new_sheet_id;
309 range_ref.end.sheet_id = new_sheet_id;
310 }
311 }
312 _ => {}
313 }
314
315 named_range.dependents.clear();
316 let name_vertex = self.allocate_name_vertex(named_range.scope);
317 if matches!(named_range.definition, NamedDefinition::Range(_)) {
318 self.store.set_kind(name_vertex, VertexKind::NamedArray);
319 } else {
320 self.store.set_kind(name_vertex, VertexKind::NamedScalar);
321 }
322 named_range.vertex = name_vertex;
323
324 let referenced_names = self.rebuild_name_dependencies(
325 name_vertex,
326 &named_range.definition,
327 named_range.scope,
328 );
329 if !referenced_names.is_empty() {
330 self.attach_vertex_to_names(name_vertex, &referenced_names);
331 }
332
333 self.sheet_named_ranges
334 .insert((new_sheet_id, name.clone()), named_range);
335 self.name_vertex_lookup
336 .insert(name_vertex, (NameScope::Sheet(new_sheet_id), name));
337 }
338
339 self.end_batch();
340
341 Ok(new_sheet_id)
342 }
343}