1#![deny(missing_docs)]
2
3use std::borrow::Cow;
4use std::collections::HashMap;
5use std::sync::Arc;
6use std::vec::Vec;
7
8use crate::arithmetic::power;
9use crate::expressions::parser::static_analysis::run_static_analysis_on_node;
10use crate::{
11 calc_result::{CalcResult, Range},
12 cell::CellValue,
13 constants::{self, LAST_COLUMN, LAST_ROW},
14 expressions::{
15 lexer::LexerMode,
16 parser::{
17 move_formula::{move_formula, MoveContext},
18 new_parser_english,
19 static_analysis::StaticResult,
20 stringify::{
21 rename_defined_name_in_node, to_english_string, to_localized_string, to_rc_format,
22 },
23 ArrayNode, CompletionContext, NamedVariable, Node, Parser,
24 },
25 token::{get_error_by_name, Error, OpProduct, OpSum, OpUnary},
26 types::*,
27 utils::{self, is_valid_column_number, is_valid_identifier, is_valid_row},
28 },
29 formatter::{
30 format::{format_number, parse_formatted_number},
31 lexer::is_likely_date_number_format,
32 },
33 implicit_intersection::implicit_intersection,
34 language::{get_default_language, get_language, Language},
35 locale::{get_default_locale, get_locale, Locale},
36 types::*,
37 utils as common,
38};
39
40use crate::evaluation::{CellKey, Evaluation, FormulaCell, Seen};
41use crate::{cf_types::CfCellResult, tz::Tz};
42
43#[cfg(any(test, feature = "mock_time"))]
44pub use crate::mock_time::get_milliseconds_since_epoch;
45
46#[cfg(not(any(test, feature = "mock_time")))]
52#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
53#[allow(clippy::expect_used)]
54pub fn get_milliseconds_since_epoch() -> i64 {
55 use std::time::{SystemTime, UNIX_EPOCH};
56 SystemTime::now()
57 .duration_since(UNIX_EPOCH)
58 .expect("problem with system time")
59 .as_millis() as i64
60}
61
62#[cfg(not(any(test, feature = "mock_time")))]
68#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
69pub fn get_milliseconds_since_epoch() -> i64 {
70 use js_sys::Date;
71 Date::now() as i64
72}
73
74pub(crate) enum CellStructure {
82 SingleCell,
83 ArrayFormula {
84 range: (i32, i32),
85 },
86 DynamicFormula {
87 range: (i32, i32),
88 },
89 SpillArray {
90 anchor: (i32, i32),
91 range: (i32, i32),
92 },
93 SpillDynamic {
94 anchor: (i32, i32),
95 range: (i32, i32),
96 },
97}
98
99#[derive(Clone)]
101pub(crate) enum ParsedDefinedName {
102 CellReference(CellReferenceIndex),
104 RangeReference(Range),
106 LambdaDefinition(Vec<NamedVariable>, Node),
108 InvalidDefinedNameFormula,
110}
111
112pub struct FmtSettings {
114 pub currency: String,
116 pub currency_format: String,
118 pub short_date: String,
120 pub short_date_example: String,
122 pub long_date: String,
124 pub long_date_example: String,
126 pub number_fmt: String,
128 pub number_example: String,
130}
131
132fn top_left_of_array(array: &[Vec<ArrayNode>], cell: CellReferenceIndex) -> CalcResult {
135 match array.first().and_then(|row| row.first()) {
136 Some(ArrayNode::Number(n)) => CalcResult::Number(*n),
137 Some(ArrayNode::Boolean(b)) => CalcResult::Boolean(*b),
138 Some(ArrayNode::String(s)) => CalcResult::String(s.clone()),
139 Some(ArrayNode::Error(error)) => CalcResult::new_error(error.clone(), cell, String::new()),
140 Some(ArrayNode::Empty) => CalcResult::EmptyCell,
141 None => CalcResult::new_error(Error::CALC, cell, "Empty array".to_string()),
142 }
143}
144
145fn array_node_to_formula_value(node: ArrayNode) -> FormulaValue {
146 match node {
147 ArrayNode::Boolean(b) => FormulaValue::Boolean(b),
148 ArrayNode::Number(n) if !n.is_finite() => {
151 FormulaValue::new_error(Error::NUM, String::new(), String::new())
152 }
153 ArrayNode::Number(n) => FormulaValue::Number(n),
154 ArrayNode::String(s) => FormulaValue::Text(s),
155 ArrayNode::Error(ei) => FormulaValue::new_error(ei, String::new(), String::new()),
156 ArrayNode::Empty => FormulaValue::Number(0.0),
157 }
158}
159
160fn array_node_to_spill_value(node: ArrayNode) -> SpillValue {
161 match node {
162 ArrayNode::Boolean(b) => SpillValue::Boolean(b),
163 ArrayNode::Number(n) if !n.is_finite() => SpillValue::Error(Error::NUM),
165 ArrayNode::Number(n) => SpillValue::Number(n),
166 ArrayNode::String(s) => SpillValue::Text(s),
167 ArrayNode::Error(ei) => SpillValue::Error(ei),
168 ArrayNode::Empty => SpillValue::Number(0.0),
169 }
170}
171
172fn formula_value_to_spill_value(v: &FormulaValue) -> SpillValue {
173 match v {
174 FormulaValue::Unevaluated => SpillValue::Error(Error::ERROR),
175 FormulaValue::Boolean(b) => SpillValue::Boolean(*b),
176 FormulaValue::Number(n) => SpillValue::Number(*n),
177 FormulaValue::Text(s) => SpillValue::Text(s.clone()),
178 FormulaValue::Error { ei, .. } => SpillValue::Error(ei.clone()),
179 }
180}
181
182pub struct Model<'a> {
195 pub workbook: Workbook,
197 pub parsed_formulas: Vec<Vec<(Arc<Node>, StaticResult)>>,
201 pub(crate) parsed_defined_names: HashMap<(Option<u32>, String), ParsedDefinedName>,
203 pub(crate) shared_strings: HashMap<String, usize>,
205 pub(crate) parser: Parser<'a>,
207 pub(crate) locale: &'a Locale,
209 pub(crate) language: &'a Language,
211 pub(crate) tz: Tz,
213 pub(crate) view_id: u32,
215 pub(crate) variable_stack: HashMap<usize, CalcResult>,
217 pub(crate) last_variable_id: usize,
219 pub(crate) lambdas: HashMap<usize, (Vec<NamedVariable>, Node)>,
221 pub(crate) last_lambda_id: usize,
223 pub(crate) evaluation: Evaluation,
225 pub(crate) cf_cache: HashMap<(u32, i32, i32), Vec<CfCellResult>>,
228 pub(crate) links: HashMap<(u32, i32, i32), Link>,
230 pub(crate) shared_formula_lookup: Vec<SharedFormulaLookup>,
236}
237
238#[derive(Default)]
240pub(crate) struct SharedFormulaLookup {
241 pub(crate) index: HashMap<String, i32>,
242 pub(crate) built_from: usize,
247}
248
249pub(crate) fn build_shared_formula_lookup(shared_formulas: &[String]) -> SharedFormulaLookup {
253 let mut index = HashMap::with_capacity(shared_formulas.len());
254 for (i, formula) in shared_formulas.iter().enumerate() {
255 index.entry(formula.clone()).or_insert(i as i32);
256 }
257 SharedFormulaLookup {
258 index,
259 built_from: shared_formulas.len(),
260 }
261}
262
263pub struct CellIndex {
266 pub index: u32,
268 pub row: i32,
270 pub column: i32,
272}
273
274impl<'a> Model<'a> {
275 pub(crate) fn get_next_variable_id(&mut self) -> usize {
276 let id = self.last_variable_id;
277 self.last_variable_id += 1;
278 id
279 }
280 pub(crate) fn clear_variable_stack(&mut self) {
281 self.variable_stack.clear();
282 self.last_variable_id = 0;
283 }
284 pub(crate) fn get_next_lambda_id(&mut self) -> usize {
285 let id = self.last_lambda_id;
286 self.last_lambda_id += 1;
287 id
288 }
289 pub(crate) fn clear_lambdas(&mut self) {
290 self.lambdas.clear();
291 self.last_lambda_id = 0;
292 }
293 pub(crate) fn evaluate_node_with_reference(
294 &mut self,
295 node: &Node,
296 cell: CellReferenceIndex,
297 ) -> CalcResult {
298 match node {
299 Node::ReferenceKind {
300 sheet_name: _,
301 sheet_index,
302 absolute_row,
303 absolute_column,
304 row,
305 column,
306 } => {
307 let mut row1 = *row;
308 let mut column1 = *column;
309 if !absolute_row {
310 row1 += cell.row;
311 }
312 if !absolute_column {
313 column1 += cell.column;
314 }
315 CalcResult::Range {
316 left: CellReferenceIndex {
317 sheet: *sheet_index,
318 row: row1,
319 column: column1,
320 },
321 right: CellReferenceIndex {
322 sheet: *sheet_index,
323 row: row1,
324 column: column1,
325 },
326 }
327 }
328 Node::RangeKind {
329 sheet_name: _,
330 sheet_index,
331 absolute_row1,
332 absolute_column1,
333 row1,
334 column1,
335 absolute_row2,
336 absolute_column2,
337 row2,
338 column2,
339 } => {
340 let mut row_left = *row1;
341 let mut column_left = *column1;
342 if !absolute_row1 {
343 row_left += cell.row;
344 }
345 if !absolute_column1 {
346 column_left += cell.column;
347 }
348 let mut row_right = *row2;
349 let mut column_right = *column2;
350 if !absolute_row2 {
351 row_right += cell.row;
352 }
353 if !absolute_column2 {
354 column_right += cell.column;
355 }
356 CalcResult::Range {
358 left: CellReferenceIndex {
359 sheet: *sheet_index,
360 row: row_left,
361 column: column_left,
362 },
363 right: CellReferenceIndex {
364 sheet: *sheet_index,
365 row: row_right,
366 column: column_right,
367 },
368 }
369 }
370 Node::ImplicitIntersection {
371 automatic: _,
372 child,
373 } => match self.evaluate_node_with_reference(child, cell) {
374 CalcResult::Range { left, right } => {
375 match implicit_intersection(&cell, &Range { left, right }) {
376 Some(r) => CalcResult::Range { left: r, right: r },
377 None => CalcResult::new_error(
378 Error::VALUE,
379 cell,
380 format!("Error with Implicit Intersection in cell {cell:?}"),
381 ),
382 }
383 }
384 CalcResult::Array(array) => top_left_of_array(&array, cell),
386 other => other,
388 },
389 Node::NamedVariableKind { .. } => self.variable_value(node, cell),
391 Node::DefinedNameKind((name, scope, _)) => {
394 if let Ok(Some(parsed_defined_name)) = self.get_parsed_defined_name(name, *scope) {
395 match parsed_defined_name {
396 ParsedDefinedName::CellReference(reference) => {
397 return CalcResult::Range {
398 left: reference,
399 right: reference,
400 };
401 }
402 ParsedDefinedName::RangeReference(range) => {
403 return CalcResult::Range {
404 left: range.left,
405 right: range.right,
406 };
407 }
408 ParsedDefinedName::LambdaDefinition(..)
409 | ParsedDefinedName::InvalidDefinedNameFormula => {}
410 }
411 }
412 self.evaluate_node_in_context(node, cell)
413 }
414 _ => self.evaluate_node_in_context(node, cell),
415 }
416 }
417
418 fn variable_value(&mut self, node: &Node, cell: CellReferenceIndex) -> CalcResult {
420 match node {
421 Node::NamedVariableKind { name, id: Some(id) } => {
422 match self.variable_stack.get(&(*id as usize)) {
423 Some(v) => v.clone(),
424 None => CalcResult::new_error(
425 Error::NAME,
426 cell,
427 format!("Variable \"{name}\" not found in scope."),
428 ),
429 }
430 }
431 Node::NamedVariableKind { name, id: None } => CalcResult::new_error(
432 Error::NAME,
433 cell,
434 format!("Variable name \"{name}\" not found."),
435 ),
436 _ => CalcResult::new_error(Error::ERROR, cell, "Not a variable".to_string()),
437 }
438 }
439
440 fn get_range(&mut self, left: &Node, right: &Node, cell: CellReferenceIndex) -> CalcResult {
441 let left_result = self.evaluate_node_with_reference(left, cell);
442 let right_result = self.evaluate_node_with_reference(right, cell);
443 match (left_result, right_result) {
444 (
445 CalcResult::Range {
446 left: left1,
447 right: right1,
448 },
449 CalcResult::Range {
450 left: left2,
451 right: right2,
452 },
453 ) => {
454 if left1.row == right1.row
455 && left1.column == right1.column
456 && left2.row == right2.row
457 && left2.column == right2.column
458 {
459 return CalcResult::Range {
460 left: left1,
461 right: right2,
462 };
463 }
464 CalcResult::Error {
465 error: Error::VALUE,
466 origin: cell,
467 message: "Invalid range".to_string(),
468 }
469 }
470 _ => CalcResult::Error {
471 error: Error::VALUE,
472 origin: cell,
473 message: "Invalid range".to_string(),
474 },
475 }
476 }
477
478 pub(crate) fn implicit_intersection_to_value(
482 &mut self,
483 result: CalcResult,
484 cell: CellReferenceIndex,
485 ) -> CalcResult {
486 match result {
487 CalcResult::Range { left, right } => {
488 match implicit_intersection(&cell, &Range { left, right }) {
489 Some(cell_reference) => self.evaluate_cell(cell_reference),
490 None => CalcResult::new_error(
491 Error::VALUE,
492 cell,
493 format!("Error with Implicit Intersection in cell {cell:?}"),
494 ),
495 }
496 }
497 other => other,
498 }
499 }
500
501 pub(crate) fn formula_without_prefix<'b>(&self, value: &'b str) -> Option<&'b str> {
502 if let Some(stripped) = value.strip_prefix('=') {
503 if stripped.is_empty() {
504 None
505 } else {
506 Some(stripped)
507 }
508 } else if let Some(stripped) = value.strip_prefix(['+', '-']) {
509 if stripped.is_empty() || self.cast_number(stripped).is_some() {
510 None
511 } else {
512 Some(value)
513 }
514 } else {
515 None
516 }
517 }
518
519 pub(crate) fn parse_internal_formula(&mut self, body: &str, context: &CellReferenceRC) -> Node {
528 let locale = self.locale;
529 let language = self.language;
530 self.parser.set_locale(get_default_locale());
531 self.parser.set_language(get_default_language());
532 let node = self.parser.parse(body, context);
533 self.parser.set_locale(locale);
534 self.parser.set_language(language);
535 node
536 }
537
538 pub(crate) fn user_formula_to_internal(
547 &mut self,
548 formula: &str,
549 context: &CellReferenceRC,
550 ) -> Result<String, String> {
551 let trimmed = formula.trim();
552 let had_equals = trimmed.starts_with('=');
553 let body = trimmed.strip_prefix('=').unwrap_or(trimmed);
554 let mut node = self.parser.parse(body, context);
555 if let Node::ParseErrorKind { .. } = node {
556 node = self.parse_internal_formula(body, context);
559 }
560 if let Node::ParseErrorKind { .. } = node {
561 return Err(format!("Invalid formula: '{formula}'"));
562 }
563 let english = to_english_string(&node, context);
564 Ok(if had_equals {
565 format!("={english}")
566 } else {
567 english
568 })
569 }
570
571 pub fn formula_completion(
578 &mut self,
579 sheet: u32,
580 row: i32,
581 column: i32,
582 formula: &str,
583 cursor: usize,
584 ) -> Result<CompletionContext, String> {
585 let sheet_name = self.workbook.worksheet(sheet)?.get_name();
586 let cell_reference = CellReferenceRC {
587 sheet: sheet_name,
588 row,
589 column,
590 };
591 let (body, cursor) = match formula.strip_prefix('=') {
594 Some(rest) => (rest, cursor.saturating_sub(1)),
595 None => (formula, cursor),
596 };
597 Ok(self.parser.parse_at_cursor(body, cursor, &cell_reference))
598 }
599
600 pub(crate) fn internal_formula_to_display(
604 &self,
605 formula: &str,
606 context: &CellReferenceRC,
607 ) -> String {
608 let trimmed = formula.trim();
609 let had_equals = trimmed.starts_with('=');
610 let body = trimmed.strip_prefix('=').unwrap_or(trimmed);
611 if body.is_empty() {
612 return formula.to_string();
613 }
614 let worksheet_names = self
616 .workbook
617 .worksheets
618 .iter()
619 .map(|s| s.get_name())
620 .collect();
621 let defined_names = self.workbook.get_defined_names_with_scope();
622 let mut parser =
623 new_parser_english(worksheet_names, defined_names, self.workbook.tables.clone());
624 let node = parser.parse(body, context);
625 if let Node::ParseErrorKind { .. } = node {
626 return formula.to_string();
627 }
628 let local = to_localized_string(&node, context, self.locale, self.language);
629 if had_equals {
630 format!("={local}")
631 } else {
632 local
633 }
634 }
635
636 pub(crate) fn evaluate_formula(&mut self, formula: &str, sheet: u32) -> Option<f64> {
640 let body = formula.trim().strip_prefix('=').unwrap_or(formula.trim());
641 if body.is_empty() {
642 return None;
643 }
644 let sheet_name = self.workbook.worksheets.get(sheet as usize)?.get_name();
645 let context_rc = CellReferenceRC {
646 sheet: sheet_name,
647 row: 1,
648 column: 1,
649 };
650 let node = self.parse_internal_formula(body, &context_rc);
651 let context_index = CellReferenceIndex {
652 sheet,
653 row: 1,
654 column: 1,
655 };
656 match self.evaluate_node_in_context(&node, context_index) {
657 CalcResult::Number(n) => Some(n),
658 _ => None,
659 }
660 }
661
662 pub(crate) fn evaluate_node_in_context(
663 &mut self,
664 node: &Node,
665 cell: CellReferenceIndex,
666 ) -> CalcResult {
667 use Node::*;
668 match node {
669 OpSumKind { kind, left, right } => match kind {
670 OpSum::Add => self.handle_arithmetic(left, right, cell, &|f1, f2| Ok(f1 + f2)),
671 OpSum::Minus => self.handle_arithmetic(left, right, cell, &|f1, f2| Ok(f1 - f2)),
672 },
673 NumberKind(value) => CalcResult::Number(*value),
674 StringKind(value) => CalcResult::String(value.replace(r#""""#, r#"""#)),
675 BooleanKind(value) => CalcResult::Boolean(*value),
676 ReferenceKind {
677 sheet_name: _,
678 sheet_index,
679 absolute_row,
680 absolute_column,
681 row,
682 column,
683 } => {
684 let mut row1 = *row;
685 let mut column1 = *column;
686 if !absolute_row {
687 row1 += cell.row;
688 }
689 if !absolute_column {
690 column1 += cell.column;
691 }
692 self.evaluate_cell(CellReferenceIndex {
693 sheet: *sheet_index,
694 row: row1,
695 column: column1,
696 })
697 }
698 WrongReferenceKind { .. } => {
699 CalcResult::new_error(Error::REF, cell, "Wrong reference".to_string())
700 }
701 OpRangeKind { left, right } => self.get_range(left, right, cell),
702 WrongRangeKind { .. } => {
703 CalcResult::new_error(Error::REF, cell, "Wrong range".to_string())
704 }
705 RangeKind {
706 sheet_index,
707 row1,
708 column1,
709 row2,
710 column2,
711 absolute_column1,
712 absolute_row2,
713 absolute_row1,
714 absolute_column2,
715 sheet_name: _,
716 } => {
717 let r1 = if *absolute_row1 {
718 *row1
719 } else {
720 *row1 + cell.row
721 };
722 let r2 = if *absolute_row2 {
723 *row2
724 } else {
725 *row2 + cell.row
726 };
727 let c1 = if *absolute_column1 {
728 *column1
729 } else {
730 *column1 + cell.column
731 };
732 let c2 = if *absolute_column2 {
733 *column2
734 } else {
735 *column2 + cell.column
736 };
737 CalcResult::Range {
738 left: CellReferenceIndex {
739 sheet: *sheet_index,
740 row: r1.min(r2),
741 column: c1.min(c2),
742 },
743 right: CellReferenceIndex {
744 sheet: *sheet_index,
745 row: r1.max(r2),
746 column: c1.max(c2),
747 },
748 }
749 }
750 OpConcatenateKind { left, right } => self.handle_concatenate(left, right, cell),
751 OpProductKind { kind, left, right } => match kind {
752 OpProduct::Times => {
753 self.handle_arithmetic(left, right, cell, &|f1, f2| Ok(f1 * f2))
754 }
755 OpProduct::Divide => self.handle_arithmetic(left, right, cell, &|f1, f2| {
756 if f2 == 0.0 {
757 Err(Error::DIV)
758 } else {
759 Ok(f1 / f2)
760 }
761 }),
762 },
763 OpPowerKind { left, right } => self.handle_arithmetic(left, right, cell, &power),
764 FunctionKind { kind, args } => self.evaluate_function(kind, args, cell),
765 NamedFunctionKind { name, args, id } => {
766 let lambda_result = if let Some(var_id) = id {
767 match self.variable_stack.get(&(*var_id as usize)) {
769 Some(v) => v.clone(),
770 None => {
771 return CalcResult::new_error(
772 Error::NAME,
773 cell,
774 format!("Variable \"{name}\" not found in scope."),
775 )
776 }
777 }
778 } else {
779 let name_lower = name.to_lowercase();
783 let found = self
784 .parsed_defined_names
785 .get(&(Some(cell.sheet), name_lower.clone()))
786 .or_else(|| self.parsed_defined_names.get(&(None, name_lower)))
787 .cloned();
788 match found {
789 Some(ParsedDefinedName::LambdaDefinition(param_names, body)) => {
790 let lambda_id = self.get_next_lambda_id();
791 self.lambdas.insert(lambda_id, (param_names, body));
792 CalcResult::Lambda(lambda_id)
793 }
794 _ => {
795 return CalcResult::new_error(
796 Error::NAME,
797 cell,
798 format!("Invalid function: {name}"),
799 )
800 }
801 }
802 };
803 self.call_lambda(lambda_result, args, cell)
804 }
805 ArrayKind(s) => CalcResult::Array(s.to_owned()),
806 DefinedNameKind((name, scope, _)) => {
807 if let Ok(Some(parsed_defined_name)) = self.get_parsed_defined_name(name, *scope) {
808 match parsed_defined_name {
809 ParsedDefinedName::CellReference(reference) => {
810 self.evaluate_cell(reference)
811 }
812 ParsedDefinedName::RangeReference(range) => CalcResult::Range {
813 left: range.left,
814 right: range.right,
815 },
816 ParsedDefinedName::LambdaDefinition(param_names, body) => {
817 let lambda_id = self.get_next_lambda_id();
818 self.lambdas.insert(lambda_id, (param_names, body));
819 CalcResult::Lambda(lambda_id)
820 }
821 ParsedDefinedName::InvalidDefinedNameFormula => CalcResult::new_error(
822 Error::NAME,
823 cell,
824 format!("Defined name \"{name}\" is not a reference."),
825 ),
826 }
827 } else {
828 CalcResult::new_error(
829 Error::NAME,
830 cell,
831 format!("Defined name \"{name}\" not found."),
832 )
833 }
834 }
835 TableNameKind(s) => CalcResult::new_error(
836 Error::NAME,
837 cell,
838 format!("table name \"{s}\" not supported."),
839 ),
840 NamedVariableKind { .. } => match self.variable_value(node, cell) {
844 CalcResult::Range { left, right } if left == right => self.evaluate_cell(left),
845 value => value,
846 },
847 CompareKind { kind, left, right } => self.handle_comparison(left, right, cell, kind),
848 UnaryKind { kind, right } => match kind {
851 OpUnary::Minus => self.apply_number_unary(right, cell, |f| Ok(-f)),
852 OpUnary::Percentage => self.apply_number_unary(right, cell, |f| Ok(f / 100.0)),
853 },
854 ErrorKind(kind) => CalcResult::new_error(kind.clone(), cell, "".to_string()),
855 ParseErrorKind {
856 formula, message, ..
857 } => CalcResult::new_error(
858 Error::ERROR,
859 cell,
860 format!("Error parsing {formula}: {message}"),
861 ),
862 EmptyArgKind => CalcResult::EmptyArg,
863 SpillRangeOperator { child } => match self.evaluate_node_with_reference(child, cell) {
864 CalcResult::Range { left, right } => {
865 if left != right {
866 return CalcResult::new_error(
867 Error::ERROR,
868 cell,
869 format!("Error with Spill Range Operator in cell {cell:?}"),
870 );
871 }
872 if let CalcResult::Error {
876 error: Error::CIRC, ..
877 } = self.evaluate_cell(left)
878 {
879 return CalcResult::new_error(
880 Error::CIRC,
881 cell,
882 "Circular reference detected".to_string(),
883 );
884 }
885 let sheet = left.sheet;
886 let row = left.row;
887 let column = left.column;
888 let worksheet = match self.workbook.worksheet(sheet) {
889 Ok(s) => s,
890 Err(e) => {
891 return CalcResult::new_error(
892 Error::REF,
893 cell,
894 format!("Sheet index {sheet} not found: {e}"),
895 );
896 }
897 };
898 match worksheet.get_cell_spill(row, column) {
899 Ok((width, height)) => CalcResult::Range {
900 left: CellReferenceIndex { sheet, row, column },
901 right: CellReferenceIndex {
902 sheet,
903 row: row + height - 1,
904 column: column + width - 1,
905 },
906 },
907 Err(e) => CalcResult::new_error(
908 Error::REF,
909 cell,
910 format!("Cell {sheet}!{row},{column} not found: {e}"),
911 ),
912 }
913 }
914 _ => CalcResult::new_error(
915 Error::ERROR,
916 cell,
917 format!("Error with Spill Range Operator in cell {cell:?}"),
918 ),
919 },
920 ImplicitIntersection {
921 automatic: _,
922 child,
923 } => match self.evaluate_node_with_reference(child, cell) {
924 CalcResult::Array(array) => top_left_of_array(&array, cell),
925 result => self.implicit_intersection_to_value(result, cell),
926 },
927 LambdaDefKind { parameters, body } => {
928 let id = self.get_next_lambda_id();
929 self.lambdas.insert(id, (parameters.clone(), *body.clone()));
930 CalcResult::Lambda(id)
931 }
932 LambdaCallKind { lambda, args } => {
933 let lambda_result = self.evaluate_node_in_context(lambda, cell);
934 self.call_lambda(lambda_result, args, cell)
935 }
936 }
937 }
938
939 fn cell_reference_to_string(
940 &self,
941 cell_reference: &CellReferenceIndex,
942 ) -> Result<String, String> {
943 let sheet = self.workbook.worksheet(cell_reference.sheet)?;
944 let column = utils::number_to_column(cell_reference.column)
945 .ok_or_else(|| "Invalid column".to_string())?;
946 if !is_valid_row(cell_reference.row) {
947 return Err("Invalid row".to_string());
948 }
949 Ok(format!("{}!{}{}", sheet.name, column, cell_reference.row))
950 }
951
952 fn get_value_from_array(
953 &self,
954 array: &[Vec<ArrayNode>],
955 row: i32,
956 column: i32,
957 ) -> Option<ArrayNode> {
958 let width = array[0].len() as i32;
959 let height = array.len() as i32;
960 if row < 1 || row > height || column < 1 || column > width {
961 return None;
962 }
963 let value = &array[(row - 1) as usize][(column - 1) as usize];
964 Some(value.clone())
965 }
966
967 pub(crate) fn set_cells_with_result(
974 &mut self,
975 cell_reference: CellReferenceIndex,
976 cell: FormulaCell,
977 result: &CalcResult,
978 ) -> Result<(), String> {
979 let CellReferenceIndex { sheet, column, row } = cell_reference;
980 let original_range = cell.array;
981 let s = cell.s;
982 let formula = cell.f;
983 if let CalcResult::Array(array) = result {
987 if array.is_empty() || array[0].is_empty() {
988 return self.set_cells_with_result(
989 cell_reference,
990 cell,
991 &CalcResult::new_error(
992 Error::CALC,
993 cell_reference,
994 "Formula produced a zero-size array".to_string(),
995 ),
996 );
997 }
998 let array_width = array[0].len() as i32;
999 let array_height = array.len() as i32;
1000
1001 match original_range {
1002 Some((true, old_area)) => {
1003 return match self.spill_dynamic_array(
1004 cell_reference,
1005 old_area,
1006 formula,
1007 s,
1008 array,
1009 )? {
1010 Some(error) => self.set_cells_with_result(cell_reference, cell, &error),
1011 None => Ok(()),
1012 };
1013 }
1014 Some((false, (original_width, original_height))) => {
1015 for r in row..row + original_height {
1018 for c in column..column + original_width {
1019 let rel_row = r - row + 1;
1020 let rel_col = c - column + 1;
1021 let value = self.get_value_from_array(array, rel_row, rel_col);
1022 let new_cell = if r == row && c == column {
1023 let fv = match value {
1024 Some(node) => array_node_to_formula_value(node),
1025 None => FormulaValue::new_error(
1026 Error::NIMPL,
1027 "".to_string(),
1028 "Unexpected array result".to_string(),
1029 ),
1030 };
1031 Cell::ArrayFormula {
1032 f: formula,
1033 s,
1034 r: (original_width, original_height),
1035 kind: ArrayKind::Cse,
1036 v: fv,
1037 }
1038 } else {
1039 let sv = match value {
1040 Some(node) => array_node_to_spill_value(node),
1041 None => SpillValue::Error(Error::VALUE),
1042 };
1043 let existing_style =
1044 self.workbook.worksheets[sheet as usize].get_style(r, c);
1045 Cell::SpillCell {
1046 s: existing_style,
1047 a: (row, column),
1048 v: sv,
1049 }
1050 };
1051 self.workbook.worksheets[sheet as usize].update_cell(r, c, new_cell)?;
1054 }
1055 }
1056 return Ok(());
1058 }
1059 None => {
1060 let coerced = if array_width == 1 && array_height == 1 {
1069 match self.get_value_from_array(array, 1, 1) {
1070 Some(node) => array_node_to_formula_value(node),
1071 None => FormulaValue::new_error(
1072 Error::VALUE,
1073 "".to_string(),
1074 "Unexpected array result".to_string(),
1075 ),
1076 }
1077 } else {
1078 debug_assert!(
1085 false,
1086 "Larger-than-1x1 array reached scalar-context cell \
1087 (sheet={sheet}, row={row}, column={column}, \
1088 {array_width}x{array_height}); implicit intersection \
1089 was expected to collapse it.",
1090 );
1091 FormulaValue::new_error(
1092 Error::VALUE,
1093 "".to_string(),
1094 "Array result in scalar context".to_string(),
1095 )
1096 };
1097 *self.workbook.worksheets[sheet as usize]
1098 .cell_mut(row, column)
1099 .ok_or("expected a cell")? = Cell::CellFormula {
1100 f: formula,
1101 s,
1102 v: coerced,
1103 };
1104 return Ok(());
1105 }
1106 }
1107 }
1108
1109 let formula_value = match result {
1110 CalcResult::Number(value) => {
1111 if value.is_nan() || value.is_infinite() {
1113 return self.set_cells_with_result(
1115 cell_reference,
1116 cell,
1117 &CalcResult::Error {
1118 error: Error::NUM,
1119 origin: cell_reference,
1120 message: "".to_string(),
1121 },
1122 );
1123 }
1124 FormulaValue::Number(*value)
1125 }
1126 CalcResult::String(value) => FormulaValue::Text(value.clone()),
1127 CalcResult::Boolean(value) => FormulaValue::Boolean(*value),
1128 CalcResult::Error {
1129 error,
1130 origin,
1131 message,
1132 } => {
1133 let o = match self.cell_reference_to_string(origin) {
1134 Ok(s) => s,
1135 Err(_) => "".to_string(),
1136 };
1137 FormulaValue::new_error(error.clone(), o, message.to_string())
1138 }
1139 CalcResult::Range { .. } => {
1140 debug_assert!(false, "Unexpected range result in non-array formula");
1142 return Err("Cannot set a range as cell value".to_string());
1143 }
1144 CalcResult::EmptyCell | CalcResult::EmptyArg => {
1145 return self.set_cells_with_result(cell_reference, cell, &CalcResult::Number(0.0));
1147 }
1148 CalcResult::Array(_) | CalcResult::Lambda(_) => {
1150 debug_assert!(false, "Unexpected array result in non-array formula");
1151 return Err("Unexpected array result in non-array formula".to_string());
1152 }
1153 };
1154
1155 if let Some((true, old_area)) = original_range {
1156 if !self.retire_own_spill_cells(cell_reference, old_area, (1, 1))? {
1158 return Ok(());
1159 }
1160 }
1161
1162 if let Some((false, (width, height))) = original_range {
1164 let spill_value = formula_value_to_spill_value(&formula_value);
1165 let ws = &mut self.workbook.worksheets[sheet as usize];
1166 for r in row..row + height {
1167 for c in column..column + width {
1168 if r == row && c == column {
1169 continue;
1170 }
1171 let existing_style = ws.get_style(r, c);
1172 ws.update_cell(
1173 r,
1174 c,
1175 Cell::SpillCell {
1176 a: (row, column),
1177 s: existing_style,
1178 v: spill_value.clone(),
1179 },
1180 )?;
1181 }
1182 }
1183 }
1184
1185 let worksheet = &mut self.workbook.worksheets[sheet as usize];
1189 match (worksheet.cell_mut(row, column), original_range) {
1190 (Some(Cell::CellFormula { f, s: style, v }), None) => {
1191 *f = formula;
1192 *style = s;
1193 *v = formula_value;
1194 }
1195 (
1196 Some(Cell::ArrayFormula {
1197 f,
1198 s: style,
1199 r,
1200 kind,
1201 v,
1202 }),
1203 Some((is_dynamic, area)),
1204 ) => {
1205 *f = formula;
1206 *style = s;
1207 (*kind, *r) = if is_dynamic {
1209 (ArrayKind::Dynamic, (1, 1))
1210 } else {
1211 (ArrayKind::Cse, area)
1212 };
1213 *v = formula_value;
1214 }
1215 (_, original_range) => {
1218 let new_cell = match original_range {
1219 Some((is_dynamic, area)) => {
1220 let (kind, r) = if is_dynamic {
1221 (ArrayKind::Dynamic, (1, 1))
1222 } else {
1223 (ArrayKind::Cse, area)
1224 };
1225 Cell::ArrayFormula {
1226 f: formula,
1227 s,
1228 r,
1229 kind,
1230 v: formula_value,
1231 }
1232 }
1233 None => Cell::CellFormula {
1234 f: formula,
1235 s,
1236 v: formula_value,
1237 },
1238 };
1239 worksheet.update_cell(row, column, new_cell)?;
1240 }
1241 }
1242 Ok(())
1243 }
1244
1245 fn spill_dynamic_array(
1255 &mut self,
1256 anchor: CellReferenceIndex,
1257 old_area: (i32, i32),
1258 formula: i32,
1259 style: i32,
1260 array: &[Vec<ArrayNode>],
1261 ) -> Result<Option<CalcResult>, String> {
1262 let CellReferenceIndex { sheet, row, column } = anchor;
1263 let height = array.len() as i32;
1264 let width = array[0].len() as i32;
1265 let spill_error = |message: &str| {
1266 Some(CalcResult::new_error(
1267 Error::SPILL,
1268 anchor,
1269 message.to_string(),
1270 ))
1271 };
1272 if row + height - 1 > LAST_ROW || column + width - 1 > LAST_COLUMN {
1273 return Ok(spill_error("Spill would exceed worksheet bounds"));
1274 }
1275
1276 let mut blocked = false;
1282 let mut occupied_by_other_spills = Vec::new();
1283 {
1284 let worksheet = self.workbook.worksheet(sheet)?;
1285 for r in row..row + height {
1286 for c in column..column + width {
1287 if (r, c) == (row, column) {
1288 continue;
1289 }
1290 if worksheet.merged_cell_containing(r, c).is_some() {
1291 blocked = true;
1292 continue;
1293 }
1294 match worksheet.cell(r, c).as_deref() {
1295 None | Some(Cell::EmptyCell { .. }) => {}
1296 Some(Cell::SpillCell { a, .. }) if *a == (row, column) => {}
1297 Some(Cell::SpillCell { .. }) => {
1298 blocked = true;
1299 occupied_by_other_spills.push(CellReferenceIndex {
1300 sheet,
1301 row: r,
1302 column: c,
1303 });
1304 }
1305 Some(_) => blocked = true,
1306 }
1307 }
1308 }
1309 }
1310 for position in occupied_by_other_spills {
1311 self.record_seen(position, Seen::Occupied);
1312 }
1313 if blocked {
1314 return Ok(spill_error("Cannot spill array result"));
1315 }
1316
1317 let writes: Vec<CellKey> = (row..row + height)
1318 .flat_map(|r| (column..column + width).map(move |c| (sheet, r, c)))
1319 .filter(|&(_, r, c)| (r, c) != (row, column))
1320 .collect();
1321 let clears = self.own_spill_cells_outside(anchor, old_area, (width, height))?;
1322 if self.spill_contradicts_a_read(anchor, &writes, &clears) {
1323 return Ok(None);
1324 }
1325
1326 let worksheet = self.workbook.worksheet_mut(sheet)?;
1327 for r in row..row + height {
1328 for c in column..column + width {
1329 let value = array[(r - row) as usize][(c - column) as usize].clone();
1330 let cell = if (r, c) == (row, column) {
1331 Cell::ArrayFormula {
1332 f: formula,
1333 s: style,
1334 r: (width, height),
1335 kind: ArrayKind::Dynamic,
1336 v: array_node_to_formula_value(value),
1337 }
1338 } else {
1339 Cell::SpillCell {
1340 a: (row, column),
1341 s: worksheet.get_style(r, c),
1342 v: array_node_to_spill_value(value),
1343 }
1344 };
1345 worksheet.update_cell(r, c, cell)?;
1347 }
1348 }
1349 for (_, r, c) in clears {
1350 worksheet.cell_clear_contents(r, c)?;
1351 }
1352 Ok(None)
1353 }
1354
1355 fn retire_own_spill_cells(
1360 &mut self,
1361 anchor: CellReferenceIndex,
1362 old_area: (i32, i32),
1363 keep_area: (i32, i32),
1364 ) -> Result<bool, String> {
1365 let clears = self.own_spill_cells_outside(anchor, old_area, keep_area)?;
1366 if self.spill_contradicts_a_read(anchor, &[], &clears) {
1367 return Ok(false);
1368 }
1369 let worksheet = self.workbook.worksheet_mut(anchor.sheet)?;
1370 for (_, r, c) in clears {
1371 worksheet.cell_clear_contents(r, c)?;
1372 }
1373 Ok(true)
1374 }
1375
1376 fn own_spill_cells_outside(
1380 &self,
1381 anchor: CellReferenceIndex,
1382 old_area: (i32, i32),
1383 keep_area: (i32, i32),
1384 ) -> Result<Vec<CellKey>, String> {
1385 let CellReferenceIndex { sheet, row, column } = anchor;
1386 let worksheet = self.workbook.worksheet(sheet)?;
1387 let mut cells = Vec::new();
1388 for r in row..row + old_area.1 {
1389 for c in column..column + old_area.0 {
1390 let kept = r < row + keep_area.1 && c < column + keep_area.0;
1391 if kept {
1392 continue;
1393 }
1394 if matches!(
1395 worksheet.cell(r, c).as_deref(),
1396 Some(Cell::SpillCell { a, .. }) if *a == (row, column)
1397 ) {
1398 cells.push((sheet, r, c));
1399 }
1400 }
1401 }
1402 Ok(cells)
1403 }
1404
1405 pub fn set_sheet_color(&mut self, sheet: u32, color: &Color) -> Result<(), String> {
1420 let worksheet = self.workbook.worksheet_mut(sheet)?;
1421 worksheet.color = color.clone();
1422 Ok(())
1423 }
1424
1425 pub fn set_sheet_state(&mut self, sheet: u32, state: SheetState) -> Result<(), String> {
1427 let worksheet = self.workbook.worksheet_mut(sheet)?;
1428 worksheet.state = state;
1429 Ok(())
1430 }
1431
1432 pub fn set_theme(&mut self, theme: crate::types::Theme) {
1434 self.workbook.theme = theme;
1435 self.evaluate_conditional_formatting();
1436 }
1437
1438 pub fn get_theme(&self) -> Theme {
1440 self.workbook.theme.clone()
1441 }
1442
1443 pub fn set_show_grid_lines(&mut self, sheet: u32, show_grid_lines: bool) -> Result<(), String> {
1445 let worksheet = self.workbook.worksheet_mut(sheet)?;
1446 worksheet.show_grid_lines = show_grid_lines;
1447 Ok(())
1448 }
1449
1450 pub(crate) fn get_cell_value(
1452 &self,
1453 cell: &Cell,
1454 cell_reference: CellReferenceIndex,
1455 ) -> CalcResult {
1456 use Cell::*;
1457 match cell {
1458 EmptyCell { .. } => CalcResult::EmptyCell,
1459 BooleanCell { v, .. } => CalcResult::Boolean(*v),
1460 NumberCell { v, .. } => CalcResult::Number(*v),
1461 ErrorCell { ei, .. } => {
1462 let message = ei.to_localized_error_string(self.language);
1463 CalcResult::new_error(ei.clone(), cell_reference, message)
1464 }
1465 SharedString { si, .. } => {
1466 if let Some(s) = self.workbook.shared_strings.get(*si as usize) {
1467 CalcResult::String(s.clone())
1468 } else {
1469 let message = "Invalid shared string".to_string();
1470 CalcResult::new_error(Error::ERROR, cell_reference, message)
1471 }
1472 }
1473 CellFormula {
1474 v: FormulaValue::Unevaluated,
1475 ..
1476 }
1477 | ArrayFormula {
1478 v: FormulaValue::Unevaluated,
1479 ..
1480 } => CalcResult::Error {
1481 error: Error::ERROR,
1482 origin: cell_reference,
1483 message: "Unevaluated formula".to_string(),
1484 },
1485 CellFormula {
1486 v: FormulaValue::Boolean(v),
1487 ..
1488 }
1489 | ArrayFormula {
1490 v: FormulaValue::Boolean(v),
1491 ..
1492 } => CalcResult::Boolean(*v),
1493 CellFormula {
1494 v: FormulaValue::Number(v),
1495 ..
1496 }
1497 | ArrayFormula {
1498 v: FormulaValue::Number(v),
1499 ..
1500 } => CalcResult::Number(*v),
1501 CellFormula {
1502 v: FormulaValue::Text(v),
1503 ..
1504 }
1505 | ArrayFormula {
1506 v: FormulaValue::Text(v),
1507 ..
1508 } => CalcResult::String(v.clone()),
1509 CellFormula {
1510 v: FormulaValue::Error { ei, d },
1511 ..
1512 }
1513 | ArrayFormula {
1514 v: FormulaValue::Error { ei, d },
1515 ..
1516 } => {
1517 if let Some(cell_reference) = self.parse_reference(&d.o) {
1518 CalcResult::new_error(ei.clone(), cell_reference, d.m.clone())
1519 } else {
1520 CalcResult::Error {
1521 error: ei.clone(),
1522 origin: cell_reference,
1523 message: ei.to_localized_error_string(self.language),
1524 }
1525 }
1526 }
1527 SpillCell {
1528 v: SpillValue::Number(v),
1529 ..
1530 } => CalcResult::Number(*v),
1531 SpillCell {
1532 v: SpillValue::Boolean(v),
1533 ..
1534 } => CalcResult::Boolean(*v),
1535 SpillCell {
1536 v: SpillValue::Text(v),
1537 ..
1538 } => CalcResult::String(v.clone()),
1539 SpillCell {
1540 v: SpillValue::Error(ei),
1541 ..
1542 } => {
1543 let message = ei.to_localized_error_string(self.language);
1544 CalcResult::new_error(ei.clone(), cell_reference, message)
1545 }
1546 }
1547 }
1548
1549 pub fn is_empty_cell(&self, sheet: u32, row: i32, column: i32) -> Result<bool, String> {
1564 self.workbook.worksheet(sheet)?.is_empty_cell(row, column)
1565 }
1566
1567 pub(crate) fn evaluate_range(
1569 &mut self,
1570 left: CellReferenceIndex,
1571 right: CellReferenceIndex,
1572 ) -> Vec<Vec<ArrayNode>> {
1573 let width = (right.column - left.column + 1).max(0) as usize;
1574 let height = (right.row - left.row + 1).max(0) as usize;
1575 let mut result = Vec::with_capacity(height);
1576 for row in left.row..=right.row {
1577 let mut row_result = Vec::with_capacity(width);
1578 self.read_row(left.sheet, row, left.column, right.column, &mut |value| {
1579 row_result.push(value)
1580 });
1581 result.push(row_result);
1582 }
1583 result
1584 }
1585
1586 pub(crate) fn evaluate_range_of_numbers(
1596 &mut self,
1597 left: CellReferenceIndex,
1598 right: CellReferenceIndex,
1599 ) -> Option<Vec<f64>> {
1600 let width = (right.column - left.column + 1).max(0) as usize;
1601 let height = (right.row - left.row + 1).max(0) as usize;
1602 let mut numbers = Vec::with_capacity(width * height);
1603 let mut only_numbers = true;
1604 for row in left.row..=right.row {
1605 if self.evaluation.restart.is_none() && !self.evaluation.unwinding {
1608 let sheet_data = &self.workbook.worksheets[left.sheet as usize].sheet_data;
1609 if let Some(row_numbers) =
1610 sheet_data.numbers_in_row_between(row, left.column, right.column)
1611 {
1612 numbers.extend_from_slice(row_numbers);
1613 continue;
1614 }
1615 }
1616 self.read_row(
1617 left.sheet,
1618 row,
1619 left.column,
1620 right.column,
1621 &mut |value| match value {
1622 ArrayNode::Number(number) => numbers.push(number),
1623 _ => only_numbers = false,
1624 },
1625 );
1626 if !only_numbers {
1627 return None;
1628 }
1629 }
1630 Some(numbers)
1631 }
1632
1633 fn read_row(
1636 &mut self,
1637 sheet: u32,
1638 row: i32,
1639 first_column: i32,
1640 last_column: i32,
1641 push: &mut impl FnMut(ArrayNode),
1642 ) {
1643 let mut column = first_column;
1644 while column <= last_column {
1645 let (stop, resume) = self.read_constants(sheet, row, column, last_column, push);
1648 for c in stop..resume {
1649 let cell_reference = CellReferenceIndex {
1650 sheet,
1651 row,
1652 column: c,
1653 };
1654 let value = match self.evaluate_cell(cell_reference) {
1655 CalcResult::Number(n) => ArrayNode::Number(n),
1656 CalcResult::Boolean(b) => ArrayNode::Boolean(b),
1657 CalcResult::String(s) => ArrayNode::String(s),
1658 CalcResult::Error { error, .. } => ArrayNode::Error(error),
1659 CalcResult::EmptyCell | CalcResult::EmptyArg => ArrayNode::Empty,
1660 CalcResult::Range { .. } | CalcResult::Array(_) | CalcResult::Lambda(_) => {
1661 debug_assert!(false, "Unexpected array result in non-array formula");
1663 ArrayNode::Error(Error::NIMPL)
1664 }
1665 };
1666 push(value);
1667 }
1668 column = resume;
1669 }
1670 }
1671
1672 fn read_constants(
1685 &mut self,
1686 sheet: u32,
1687 row: i32,
1688 column: i32,
1689 last_column: i32,
1690 push: &mut impl FnMut(ArrayNode),
1691 ) -> (i32, i32) {
1692 let evaluation = &mut self.evaluation;
1693 if evaluation.restart.is_some() || evaluation.unwinding {
1694 return (column, last_column + 1);
1697 }
1698 let shared_strings = &self.workbook.shared_strings;
1699 let mut cells = self.workbook.worksheets[sheet as usize]
1700 .sheet_data
1701 .cells_in_row_between(row, column, last_column);
1702 let mut next = column;
1703 let mut read_empty = |from: i32, to: i32, push: &mut dyn FnMut(ArrayNode)| {
1705 for column in from..to {
1706 evaluation.record_seen(CellReferenceIndex { sheet, row, column }, Seen::Empty);
1707 push(ArrayNode::Empty);
1708 }
1709 };
1710 while let Some((c, cell)) = cells.next() {
1711 let value = match &*cell {
1712 Cell::EmptyCell { .. } => {
1713 read_empty(next, c + 1, push);
1714 next = c + 1;
1715 continue;
1716 }
1717 Cell::NumberCell { v, .. } => ArrayNode::Number(*v),
1718 Cell::BooleanCell { v, .. } => ArrayNode::Boolean(*v),
1719 Cell::ErrorCell { ei, .. } => ArrayNode::Error(ei.clone()),
1720 Cell::SharedString { si, .. } => match shared_strings.get(*si as usize) {
1721 Some(s) => ArrayNode::String(s.clone()),
1722 None => ArrayNode::Error(Error::ERROR),
1723 },
1724 Cell::CellFormula { .. } | Cell::ArrayFormula { .. } | Cell::SpillCell { .. } => {
1725 read_empty(next, c, push);
1726 let mut resume = c + 1;
1728 for (following, cell) in cells.by_ref() {
1729 let is_constant = !matches!(
1730 *cell,
1731 Cell::CellFormula { .. }
1732 | Cell::ArrayFormula { .. }
1733 | Cell::SpillCell { .. }
1734 );
1735 if following != resume || is_constant {
1736 break;
1737 }
1738 resume += 1;
1739 }
1740 return (c, resume);
1741 }
1742 };
1743 read_empty(next, c, push);
1744 push(value);
1745 next = c + 1;
1746 }
1747 read_empty(next, last_column + 1, push);
1748 (last_column + 1, last_column + 1)
1749 }
1750
1751 #[inline(always)]
1752 pub(crate) fn fetch_cell(&self, cell_reference: CellReferenceIndex) -> Option<Cow<'_, Cell>> {
1753 self.workbook.worksheets[cell_reference.sheet as usize]
1754 .sheet_data
1755 .cell(cell_reference.row, cell_reference.column)
1756 }
1757
1758 pub(crate) fn get_sheet_index_by_name(&self, name: &str) -> Option<u32> {
1759 let worksheets = &self.workbook.worksheets;
1760 for (index, worksheet) in worksheets.iter().enumerate() {
1761 if worksheet.get_name().to_uppercase() == name.to_uppercase() {
1762 return Some(index as u32);
1763 }
1764 }
1765 None
1766 }
1767
1768 pub fn from_bytes(s: &[u8], language_id: &'a str) -> Result<Model<'a>, String> {
1790 let workbook: Workbook =
1791 bitcode::decode(s).map_err(|e| format!("Error parsing workbook: {e}"))?;
1792 Model::from_workbook(workbook, language_id)
1793 }
1794
1795 pub fn from_workbook(workbook: Workbook, language_id: &str) -> Result<Model<'_>, String> {
1814 let parsed_formulas = Vec::new();
1815 let worksheets = &workbook.worksheets;
1816
1817 let worksheet_names = worksheets.iter().map(|s| s.get_name()).collect();
1818
1819 let defined_names = workbook.get_defined_names_with_scope();
1820 let locale =
1831 get_locale(&workbook.settings.locale).map_err(|_| "Invalid locale".to_string())?;
1832 let tz = Tz::parse(&workbook.settings.tz)?;
1833
1834 let language = match get_language(language_id) {
1835 Ok(lang) => lang,
1836 Err(_) => return Err("Invalid language".to_string()),
1837 };
1838 let parser = Parser::new(
1839 worksheet_names,
1840 defined_names,
1841 workbook.tables.clone(),
1842 locale,
1843 language,
1844 );
1845 let mut shared_strings = HashMap::new();
1846 for (index, s) in workbook.shared_strings.iter().enumerate() {
1847 shared_strings.insert(s.to_string(), index);
1848 }
1849
1850 let mut model = Model {
1851 workbook,
1852 parsed_formulas,
1853 shared_formula_lookup: Vec::new(),
1854 shared_strings,
1855 parsed_defined_names: HashMap::new(),
1856 parser,
1857 language,
1858 locale,
1859 tz,
1860 view_id: 0,
1861 variable_stack: HashMap::new(),
1862 last_variable_id: 0,
1863 lambdas: HashMap::new(),
1864 last_lambda_id: 0,
1865 evaluation: Evaluation::default(),
1866 cf_cache: HashMap::new(),
1867 links: HashMap::new(),
1868 };
1869
1870 model.parse_formulas();
1871 model.parse_defined_names();
1872 model.evaluate_conditional_formatting();
1873
1874 Ok(model)
1875 }
1876
1877 pub fn parse_reference(&self, s: &str) -> Option<CellReferenceIndex> {
1893 let bytes = s.as_bytes();
1894 let mut sheet_name = "".to_string();
1895 let mut column = "".to_string();
1896 let mut row = "".to_string();
1897 let mut state = "sheet"; for &byte in bytes {
1899 match state {
1900 "sheet" => {
1901 if byte == b'!' {
1902 state = "col"
1903 } else {
1904 sheet_name.push(byte as char);
1905 }
1906 }
1907 "col" => {
1908 if byte.is_ascii_alphabetic() {
1909 column.push(byte as char);
1910 } else {
1911 state = "row";
1912 row.push(byte as char);
1913 }
1914 }
1915 _ => {
1916 row.push(byte as char);
1917 }
1918 }
1919 }
1920 let sheet = self.get_sheet_index_by_name(&sheet_name)?;
1921 let row = match row.parse::<i32>() {
1922 Ok(r) => r,
1923 Err(_) => return None,
1924 };
1925 if !(1..=constants::LAST_ROW).contains(&row) {
1926 return None;
1927 }
1928
1929 let column = match utils::column_to_number(&column) {
1930 Ok(column) => {
1931 if is_valid_column_number(column) {
1932 column
1933 } else {
1934 return None;
1935 }
1936 }
1937 Err(_) => return None,
1938 };
1939
1940 Some(CellReferenceIndex { sheet, row, column })
1941 }
1942
1943 pub fn move_cell_value_to_area(
1965 &mut self,
1966 value: &str,
1967 source: &CellReferenceIndex,
1968 target: &CellReferenceIndex,
1969 area: &Area,
1970 ) -> Result<String, String> {
1971 let source_sheet_name = self
1972 .workbook
1973 .worksheet(source.sheet)
1974 .map_err(|e| format!("Could not find source worksheet: {e}"))?
1975 .get_name();
1976 if source.sheet != area.sheet {
1977 return Err("Source and area are in different sheets".to_string());
1978 }
1979 if source.row < area.row || source.row >= area.row + area.height {
1980 return Err("Source is outside the area".to_string());
1981 }
1982 if source.column < area.column || source.column >= area.column + area.width {
1983 return Err("Source is outside the area".to_string());
1984 }
1985 let target_sheet_name = self
1986 .workbook
1987 .worksheet(target.sheet)
1988 .map_err(|e| format!("Could not find target worksheet: {e}"))?
1989 .get_name();
1990 if let Some(formula) = self.formula_without_prefix(value) {
1991 let cell_reference = CellReferenceRC {
1992 sheet: source_sheet_name.to_owned(),
1993 row: source.row,
1994 column: source.column,
1995 };
1996 let formula_str = move_formula(
1997 &self.parser.parse(formula, &cell_reference),
1998 &MoveContext {
1999 source_sheet_name: &source_sheet_name,
2000 row: source.row,
2001 column: source.column,
2002 area,
2003 target_sheet_name: &target_sheet_name,
2004 row_delta: target.row - source.row,
2005 column_delta: target.column - source.column,
2006 },
2007 self.locale,
2008 self.language,
2009 );
2010 Ok(format!("={formula_str}"))
2011 } else {
2012 Ok(value.to_string())
2013 }
2014 }
2015
2016 pub fn extend_to(
2037 &self,
2038 sheet: u32,
2039 row: i32,
2040 column: i32,
2041 target_row: i32,
2042 target_column: i32,
2043 ) -> Result<String, String> {
2044 let cell = self.workbook.worksheet(sheet)?.cell(row, column);
2045 let result = match cell {
2046 Some(cell) => match cell.get_formula() {
2047 None => cell.get_localized_text(
2048 &self.workbook.shared_strings,
2049 self.locale,
2050 self.language,
2051 ),
2052 Some(i) => {
2053 let (formula, _static_result) =
2054 &self.parsed_formulas[sheet as usize][i as usize];
2055 let cell_ref = CellReferenceRC {
2056 sheet: self.workbook.worksheets[sheet as usize].get_name(),
2057 row: target_row,
2058 column: target_column,
2059 };
2060 format!(
2061 "={}",
2062 to_localized_string(formula, &cell_ref, self.locale, self.language)
2063 )
2064 }
2065 },
2066 None => "".to_string(),
2067 };
2068 Ok(result)
2069 }
2070
2071 pub fn extend_copied_value(
2092 &mut self,
2093 value: &str,
2094 source: &CellReferenceIndex,
2095 target: &CellReferenceIndex,
2096 ) -> Result<String, String> {
2097 let source_sheet_name = match self.workbook.worksheets.get(source.sheet as usize) {
2098 Some(ws) => ws.get_name(),
2099 None => {
2100 return Err("Invalid worksheet index".to_owned());
2101 }
2102 };
2103 let target_sheet_name = match self.workbook.worksheets.get(target.sheet as usize) {
2104 Some(ws) => ws.get_name(),
2105 None => {
2106 return Err("Invalid worksheet index".to_owned());
2107 }
2108 };
2109
2110 if let Some(formula_str) = self.formula_without_prefix(value) {
2111 let cell_reference = CellReferenceRC {
2112 sheet: source_sheet_name.to_string(),
2113 row: source.row,
2114 column: source.column,
2115 };
2116 let formula = &self.parser.parse(formula_str, &cell_reference);
2117 let cell_reference = CellReferenceRC {
2118 sheet: target_sheet_name,
2119 row: target.row,
2120 column: target.column,
2121 };
2122 return Ok(format!(
2123 "={}",
2124 to_localized_string(formula, &cell_reference, self.locale, self.language)
2125 ));
2126 }
2127 Ok(value.to_string())
2128 }
2129
2130 pub fn get_cell_formula(
2150 &self,
2151 sheet: u32,
2152 row: i32,
2153 column: i32,
2154 ) -> Result<Option<String>, String> {
2155 let worksheet = self.workbook.worksheet(sheet)?;
2156 match worksheet.cell(row, column) {
2157 Some(cell) => match cell.get_formula() {
2158 Some(formula_index) => {
2159 let (formula, _static_result) = &self
2160 .parsed_formulas
2161 .get(sheet as usize)
2162 .ok_or("missing sheet")?
2163 .get(formula_index as usize)
2164 .ok_or("missing formula")?;
2165 let cell_ref = CellReferenceRC {
2166 sheet: worksheet.get_name(),
2167 row,
2168 column,
2169 };
2170 Ok(Some(format!(
2171 "={}",
2172 to_localized_string(formula, &cell_ref, self.locale, self.language)
2173 )))
2174 }
2175 None => Ok(None),
2176 },
2177 None => Ok(None),
2178 }
2179 }
2180
2181 pub(crate) fn get_english_cell_formula(
2186 &self,
2187 sheet: u32,
2188 row: i32,
2189 column: i32,
2190 ) -> Result<Option<String>, String> {
2191 let worksheet = self.workbook.worksheet(sheet)?;
2192 match worksheet.cell(row, column) {
2193 Some(cell) => match cell.get_formula() {
2194 Some(formula_index) => {
2195 let (formula, _static_result) = &self
2196 .parsed_formulas
2197 .get(sheet as usize)
2198 .ok_or("missing sheet")?
2199 .get(formula_index as usize)
2200 .ok_or("missing formula")?;
2201 let cell_ref = CellReferenceRC {
2202 sheet: worksheet.get_name(),
2203 row,
2204 column,
2205 };
2206 let language_en = get_default_language();
2207 Ok(Some(format!(
2208 "={}",
2209 to_localized_string(formula, &cell_ref, self.locale, language_en)
2210 )))
2211 }
2212 None => Ok(None),
2213 },
2214 None => Ok(None),
2215 }
2216 }
2217
2218 pub fn update_cell_with_text(
2243 &mut self,
2244 sheet: u32,
2245 row: i32,
2246 column: i32,
2247 value: &str,
2248 ) -> Result<(), String> {
2249 let style_index = self.get_cell_style_index(sheet, row, column)?;
2250
2251 let new_style_index = if common::value_needs_quoting(value, self.language) {
2252 self.workbook
2253 .styles
2254 .get_style_with_quote_prefix(style_index)?
2255 } else if self.workbook.styles.style_is_quote_prefix(style_index) {
2256 self.workbook
2257 .styles
2258 .get_style_without_quote_prefix(style_index)?
2259 } else {
2260 style_index
2261 };
2262
2263 self.set_cell_with_string(sheet, row, column, value, new_style_index)
2264 }
2265
2266 pub fn update_cell_with_bool(
2291 &mut self,
2292 sheet: u32,
2293 row: i32,
2294 column: i32,
2295 value: bool,
2296 ) -> Result<(), String> {
2297 let style_index = self.get_cell_style_index(sheet, row, column)?;
2298 let new_style_index = if self.workbook.styles.style_is_quote_prefix(style_index) {
2299 self.workbook
2300 .styles
2301 .get_style_without_quote_prefix(style_index)?
2302 } else {
2303 style_index
2304 };
2305 self.set_cell_with_boolean(sheet, row, column, value, new_style_index)
2306 }
2307
2308 pub fn update_cell_with_number(
2333 &mut self,
2334 sheet: u32,
2335 row: i32,
2336 column: i32,
2337 value: f64,
2338 ) -> Result<(), String> {
2339 let style_index = self.get_cell_style_index(sheet, row, column)?;
2340 let new_style_index = if self.workbook.styles.style_is_quote_prefix(style_index) {
2341 self.workbook
2342 .styles
2343 .get_style_without_quote_prefix(style_index)?
2344 } else {
2345 style_index
2346 };
2347 self.set_cell_with_number(sheet, row, column, value, new_style_index)
2348 }
2349
2350 pub fn update_cell_with_formula(
2378 &mut self,
2379 sheet: u32,
2380 row: i32,
2381 column: i32,
2382 formula: String,
2383 ) -> Result<(), String> {
2384 let mut style_index = self.get_cell_style_index(sheet, row, column)?;
2385 if self.workbook.styles.style_is_quote_prefix(style_index) {
2386 style_index = self
2387 .workbook
2388 .styles
2389 .get_style_without_quote_prefix(style_index)?;
2390 }
2391
2392 if let Some(new_formula) = self.formula_without_prefix(&formula) {
2393 self.set_cell_with_formula(sheet, row, column, new_formula, style_index)?;
2394 Ok(())
2395 } else {
2396 Err(format!("\"{formula}\" is not a valid formula"))
2397 }
2398 }
2399
2400 pub(crate) fn prepare_cell_for_user_input(
2408 &mut self,
2409 sheet: u32,
2410 row: i32,
2411 column: i32,
2412 ) -> Result<(), String> {
2413 if self.workbook.worksheet(sheet)?.is_covered_cell(row, column) {
2414 return Err("Cannot edit a cell that is part of a merged cell".to_string());
2415 }
2416 match self.get_cell_structure(sheet, row, column)? {
2417 CellStructure::SingleCell => {
2418 }
2420 CellStructure::ArrayFormula { range } => {
2421 let (width, height) = range;
2423 if width > 1 || height > 1 {
2424 return Err(
2425 "Cannot write in a cell that is part of an array formula".to_string()
2426 );
2427 }
2428 }
2429 CellStructure::DynamicFormula { range } => {
2430 let (width, height) = range;
2432 let ws = self.workbook.worksheet_mut(sheet)?;
2433 for r in row..row + height {
2434 for c in column..column + width {
2435 let _ = ws.cell_clear_contents(r, c);
2437 }
2438 }
2439 }
2440 CellStructure::SpillArray { .. } => {
2441 return Err("Cannot write in a cell that is part of an array formula".to_string());
2442 }
2443 CellStructure::SpillDynamic { anchor, range } => {
2444 let (anchor_row, anchor_column) = anchor;
2448 let (width, height) = range;
2449 let ws = self.workbook.worksheet_mut(sheet)?;
2450 let (formula_index, anchor_style) = {
2452 let anchor_cell = ws
2453 .cell(anchor_row, anchor_column)
2454 .ok_or_else(|| "Dynamic formula anchor not found".to_string())?;
2455 let fi = anchor_cell
2456 .get_formula()
2457 .ok_or_else(|| "Dynamic formula anchor has no formula".to_string())?;
2458 let s = anchor_cell.get_style();
2459 (fi, s)
2460 };
2461 ws.set_cell_with_dynamic_formula(
2462 anchor_row,
2463 anchor_column,
2464 formula_index,
2465 anchor_style,
2466 1,
2467 1,
2468 )?;
2469 for r in anchor_row..anchor_row + height {
2470 for c in anchor_column..anchor_column + width {
2471 if r == anchor_row && c == anchor_column {
2472 continue;
2473 }
2474 let _ = ws.cell_clear_contents(r, c);
2476 }
2477 }
2478 }
2479 };
2480 Ok(())
2481 }
2482
2483 pub fn set_user_input(
2515 &mut self,
2516 sheet: u32,
2517 row: i32,
2518 column: i32,
2519 value: String,
2520 ) -> Result<(), String> {
2521 self.prepare_cell_for_user_input(sheet, row, column)?;
2523 if value.is_empty() {
2524 let ws = self.workbook.worksheet_mut(sheet)?;
2527 ws.cell_clear_contents(row, column)?;
2528 ws.links.remove(&(row, column));
2529 return Ok(());
2530 }
2531
2532 let style_index = self.get_cell_style_index(sheet, row, column)?;
2534 if let Some(new_value) = value.strip_prefix('\'') {
2535 let new_style = self
2536 .workbook
2537 .styles
2538 .get_style_with_quote_prefix(style_index)?;
2539 self.set_cell_with_string(sheet, row, column, new_value, new_style)?;
2540 } else {
2541 let mut new_style_index = style_index;
2542 if self.workbook.styles.style_is_quote_prefix(style_index) {
2543 new_style_index = self
2544 .workbook
2545 .styles
2546 .get_style_without_quote_prefix(style_index)?;
2547 }
2548 if let Some(formula) = self.formula_without_prefix(&value) {
2549 let formula_index =
2550 self.set_cell_with_formula(sheet, row, column, formula, new_style_index)?;
2551 let cell = CellReferenceIndex { sheet, row, column };
2553 let (parsed_formula, _static_result) =
2554 &self.parsed_formulas[sheet as usize][formula_index as usize];
2555 if let Some(units) = self.compute_node_units(parsed_formula, &cell) {
2556 let new_style_index = self
2557 .workbook
2558 .styles
2559 .get_style_with_format(new_style_index, &units.get_num_fmt())?;
2560 let style = self.workbook.styles.get_style(new_style_index)?;
2561 self.set_cell_style(sheet, row, column, &style)?;
2562 }
2563 } else {
2564 let mut currencies = vec!["$", "€"];
2566 let currency = &self.locale.currency.symbol;
2567 if !currencies.iter().any(|e| e == currency) {
2568 currencies.push(currency);
2569 }
2570
2571 if let Ok((v, number_format)) =
2573 parse_formatted_number(&value, ¤cies, self.locale)
2574 {
2575 if let Some(num_fmt) = number_format {
2576 let should_apply_format = !(is_likely_date_number_format(
2579 &self.workbook.styles.get_style(new_style_index)?.num_fmt,
2580 ) && is_likely_date_number_format(&num_fmt));
2581 if should_apply_format {
2582 new_style_index = self
2583 .workbook
2584 .styles
2585 .get_style_with_format(new_style_index, &num_fmt)?;
2586 }
2587 }
2588 let worksheet = self.workbook.worksheet_mut(sheet)?;
2589 worksheet.set_cell_with_number(row, column, v, new_style_index)?;
2590 return Ok(());
2591 }
2592 if let Ok(v) = value.to_lowercase().parse::<bool>() {
2594 let worksheet = self.workbook.worksheet_mut(sheet)?;
2595 worksheet.set_cell_with_boolean(row, column, v, new_style_index)?;
2596 return Ok(());
2597 }
2598 let upper = value.to_uppercase();
2600 let worksheet = self.workbook.worksheet_mut(sheet)?;
2601 match get_error_by_name(&upper, self.language) {
2602 Some(error) => {
2603 worksheet.set_cell_with_error(row, column, error, new_style_index)?;
2604 }
2605 None => {
2606 self.set_cell_with_string(sheet, row, column, &value, new_style_index)?;
2607 self.auto_link_cell(sheet, row, column, &value)?;
2611 }
2612 }
2613 }
2614 }
2615 Ok(())
2616 }
2617
2618 pub fn set_user_array_formula(
2620 &mut self,
2621 sheet: u32,
2622 row: i32,
2623 column: i32,
2624 width: i32,
2625 height: i32,
2626 value: &str,
2627 ) -> Result<(), String> {
2628 if self
2629 .workbook
2630 .worksheet(sheet)?
2631 .merged_cells
2632 .iter()
2633 .any(|m| m.intersects(row, column, width, height))
2634 {
2635 return Err("Cannot set an array formula over merged cells".to_string());
2636 }
2637 for r in row..row + height {
2642 for c in column..column + width {
2643 if (r, c) == (row, column) {
2644 continue;
2645 }
2646 match self.get_cell_structure(sheet, r, c)? {
2647 CellStructure::ArrayFormula { range: (w, h) } if w > 1 || h > 1 => {
2648 return Err(
2649 "Cannot write in a cell that is part of an array formula".to_string()
2650 );
2651 }
2652 CellStructure::SpillArray { .. } => {
2653 return Err(
2654 "Cannot write in a cell that is part of an array formula".to_string()
2655 );
2656 }
2657 _ => {}
2658 }
2659 }
2660 }
2661 for r in row..row + height {
2662 for c in column..column + width {
2663 self.prepare_cell_for_user_input(sheet, r, c)?;
2664 }
2665 }
2666 let style_index = self.get_cell_style_index(sheet, row, column)?;
2668 if value.strip_prefix('\'').is_none() {
2669 let mut new_style_index = style_index;
2670 if self.workbook.styles.style_is_quote_prefix(style_index) {
2671 new_style_index = self
2672 .workbook
2673 .styles
2674 .get_style_without_quote_prefix(style_index)?;
2675 }
2676 if let Some(formula) = value.strip_prefix('=') {
2677 let formula_index = self.set_cell_with_array_formula(
2679 sheet,
2680 row,
2681 column,
2682 formula,
2683 new_style_index,
2684 width,
2685 height,
2686 )?;
2687
2688 let cell = CellReferenceIndex { sheet, row, column };
2690 let (parsed_formula, _static_result) =
2691 &self.parsed_formulas[sheet as usize][formula_index as usize];
2692
2693 if let Some(units) = self.compute_node_units(parsed_formula, &cell) {
2694 let new_style_index = self
2695 .workbook
2696 .styles
2697 .get_style_with_format(new_style_index, &units.get_num_fmt())?;
2698 let style = self.workbook.styles.get_style(new_style_index)?;
2699 self.set_cell_style(sheet, row, column, &style)?;
2700 }
2701 for r in row..row + height {
2707 for c in column..column + width {
2708 if r == row && c == column {
2709 continue;
2710 }
2711 let mut new_style_index_spill = self.get_cell_style_index(sheet, r, c)?;
2712 if self
2713 .workbook
2714 .styles
2715 .style_is_quote_prefix(new_style_index_spill)
2716 {
2717 new_style_index_spill = self
2718 .workbook
2719 .styles
2720 .get_style_without_quote_prefix(new_style_index_spill)?;
2721 }
2722 self.workbook.worksheet_mut(sheet)?.update_cell(
2723 r,
2724 c,
2725 Cell::SpillCell {
2726 s: new_style_index_spill,
2727 a: (row, column),
2728 v: SpillValue::Text(String::new()),
2729 },
2730 )?;
2731 }
2732 }
2733 return Ok(());
2734 }
2735 }
2736 for r in row..row + height {
2738 for c in column..column + width {
2739 self.set_user_input(sheet, r, c, value.to_string())?;
2740 }
2741 }
2742
2743 Ok(())
2744 }
2745
2746 pub(crate) fn get_cell_structure(
2747 &self,
2748 sheet: u32,
2749 row: i32,
2750 column: i32,
2751 ) -> Result<CellStructure, String> {
2752 let worksheet = self.workbook.worksheet(sheet)?;
2753 worksheet.get_cell_structure(row, column)
2754 }
2755
2756 fn shared_formula_index(
2761 &mut self,
2762 sheet: u32,
2763 parsed_formula: Node,
2764 static_result: StaticResult,
2765 ) -> Result<i32, String> {
2766 let text = to_rc_format(&parsed_formula);
2767 let sheet_index = sheet as usize;
2768 let shared_formulas = &mut self.workbook.worksheet_mut(sheet)?.shared_formulas;
2769 if self.shared_formula_lookup.len() <= sheet_index {
2770 self.shared_formula_lookup
2771 .resize_with(sheet_index + 1, SharedFormulaLookup::default);
2772 }
2773 let lookup = &mut self.shared_formula_lookup[sheet_index];
2774 let agrees = |lookup: &SharedFormulaLookup, shared_formulas: &Vec<String>| {
2777 lookup.built_from == shared_formulas.len()
2778 && match lookup.index.get(&text) {
2779 Some(index) => shared_formulas.get(*index as usize) == Some(&text),
2780 None => true,
2781 }
2782 };
2783 if !agrees(lookup, shared_formulas) {
2784 *lookup = build_shared_formula_lookup(shared_formulas);
2785 }
2786 if let Some(index) = lookup.index.get(&text) {
2787 return Ok(*index);
2788 }
2789 let index = shared_formulas.len() as i32;
2790 lookup.index.insert(text.clone(), index);
2791 shared_formulas.push(text);
2792 lookup.built_from = shared_formulas.len();
2793 self.parsed_formulas[sheet_index].push((Arc::new(parsed_formula), static_result));
2794 Ok(index)
2795 }
2796
2797 fn set_cell_with_formula(
2798 &mut self,
2799 sheet: u32,
2800 row: i32,
2801 column: i32,
2802 formula: &str,
2803 style: i32,
2804 ) -> Result<i32, String> {
2805 let worksheet = self.workbook.worksheet_mut(sheet)?;
2806 let cell_reference = CellReferenceRC {
2807 sheet: worksheet.get_name(),
2808 row,
2809 column,
2810 };
2811 let mut parsed_formula = self.parser.parse(formula, &cell_reference);
2812 if let Node::ParseErrorKind { .. } = parsed_formula {
2815 let new_parsed_formula = self.parser.parse(&format!("{formula})"), &cell_reference);
2816 match new_parsed_formula {
2817 Node::ParseErrorKind { .. } => {}
2818 _ => parsed_formula = new_parsed_formula,
2819 }
2820 }
2821 let static_result = run_static_analysis_on_node(&parsed_formula);
2822 let is_dynamic = !matches!(static_result, StaticResult::Scalar);
2823
2824 let formula_index = self.shared_formula_index(sheet, parsed_formula, static_result)?;
2825 let worksheet = self.workbook.worksheet_mut(sheet)?;
2826 if is_dynamic {
2827 worksheet.set_cell_with_dynamic_formula(row, column, formula_index, style, 1, 1)?;
2828 } else {
2829 worksheet.set_cell_with_formula(row, column, formula_index, style)?;
2830 }
2831 Ok(formula_index)
2832 }
2833
2834 #[allow(clippy::too_many_arguments)]
2836 pub(crate) fn set_cell_with_array_formula(
2837 &mut self,
2838 sheet: u32,
2839 row: i32,
2840 column: i32,
2841 formula: &str,
2842 style: i32,
2843 width: i32,
2844 height: i32,
2845 ) -> Result<i32, String> {
2846 let worksheet = self.workbook.worksheet_mut(sheet)?;
2847 let cell_reference = CellReferenceRC {
2848 sheet: worksheet.get_name(),
2849 row,
2850 column,
2851 };
2852 let mut parsed_formula = self.parser.parse(formula, &cell_reference);
2853 if let Node::ParseErrorKind { .. } = parsed_formula {
2856 let new_parsed_formula = self.parser.parse(&format!("{formula})"), &cell_reference);
2857 match new_parsed_formula {
2858 Node::ParseErrorKind { .. } => {}
2859 _ => parsed_formula = new_parsed_formula,
2860 }
2861 }
2862 let static_result = run_static_analysis_on_node(&parsed_formula);
2863
2864 let formula_index = self.shared_formula_index(sheet, parsed_formula, static_result)?;
2865 let worksheet = self.workbook.worksheet_mut(sheet)?;
2866 worksheet.set_cell_with_array_formula(row, column, formula_index, style, width, height)?;
2867 Ok(formula_index)
2868 }
2869
2870 pub(crate) fn set_cell_with_string(
2871 &mut self,
2872 sheet: u32,
2873 row: i32,
2874 column: i32,
2875 value: &str,
2876 style: i32,
2877 ) -> Result<(), String> {
2878 match self.shared_strings.get(value) {
2879 Some(string_index) => {
2880 self.workbook.worksheet_mut(sheet)?.set_cell_with_string(
2881 row,
2882 column,
2883 *string_index as i32,
2884 style,
2885 )?;
2886 }
2887 None => {
2888 let string_index = self.workbook.shared_strings.len();
2889 self.workbook.shared_strings.push(value.to_string());
2890 self.shared_strings.insert(value.to_string(), string_index);
2891 self.workbook.worksheet_mut(sheet)?.set_cell_with_string(
2892 row,
2893 column,
2894 string_index as i32,
2895 style,
2896 )?;
2897 }
2898 }
2899 Ok(())
2900 }
2901
2902 fn set_cell_with_boolean(
2903 &mut self,
2904 sheet: u32,
2905 row: i32,
2906 column: i32,
2907 value: bool,
2908 style: i32,
2909 ) -> Result<(), String> {
2910 self.workbook
2911 .worksheet_mut(sheet)?
2912 .set_cell_with_boolean(row, column, value, style)
2913 }
2914
2915 fn set_cell_with_number(
2916 &mut self,
2917 sheet: u32,
2918 row: i32,
2919 column: i32,
2920 value: f64,
2921 style: i32,
2922 ) -> Result<(), String> {
2923 self.workbook
2924 .worksheet_mut(sheet)?
2925 .set_cell_with_number(row, column, value, style)
2926 }
2927
2928 fn get_parsed_defined_name(
2930 &self,
2931 name: &str,
2932 scope: Option<u32>,
2933 ) -> Result<Option<ParsedDefinedName>, String> {
2934 let name_upper = name.to_uppercase();
2935
2936 for (key, df) in &self.parsed_defined_names {
2937 if key.1.to_uppercase() == name_upper && key.0 == scope {
2938 return Ok(Some(df.clone()));
2939 }
2940 }
2941 Ok(None)
2942 }
2943
2944 pub(crate) fn get_defined_name_formula(
2946 &self,
2947 name: &str,
2948 scope: Option<u32>,
2949 ) -> Result<String, String> {
2950 let name_upper = name.to_uppercase();
2951 let defined_names = &self.workbook.defined_names;
2952 let sheet_id = match scope {
2953 Some(index) => Some(self.workbook.worksheet(index)?.sheet_id),
2954 None => None,
2955 };
2956 for df in defined_names {
2957 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
2958 return Ok(df.formula.clone());
2959 }
2960 }
2961 Err("Defined name not found".to_string())
2962 }
2963
2964 pub fn get_defined_name_list(&self) -> Vec<(String, Option<u32>, String)> {
2969 let context = self.defined_name_context();
2970 self.workbook
2971 .get_defined_names_with_scope()
2972 .into_iter()
2973 .map(|(name, scope, formula)| {
2974 let formula = self.internal_formula_to_display(&formula, &context);
2975 (name, scope, formula)
2976 })
2977 .collect()
2978 }
2979
2980 pub fn get_cell_value_by_ref(&self, cell_ref: &str) -> Result<CellValue, String> {
2985 let cell_reference = match self.parse_reference(cell_ref) {
2986 Some(c) => c,
2987 None => return Err(format!("Error parsing reference: '{cell_ref}'")),
2988 };
2989 let sheet_index = cell_reference.sheet;
2990 let column = cell_reference.column;
2991 let row = cell_reference.row;
2992
2993 self.get_cell_value_by_index(sheet_index, row, column)
2994 }
2995
2996 pub fn get_cell_value_by_index(
3001 &self,
3002 sheet_index: u32,
3003 row: i32,
3004 column: i32,
3005 ) -> Result<CellValue, String> {
3006 let cell = self
3007 .workbook
3008 .worksheet(sheet_index)?
3009 .cell(row, column)
3010 .map(Cow::into_owned)
3011 .unwrap_or_default();
3012 let cell_value = cell.value(&self.workbook.shared_strings, self.language);
3013 Ok(cell_value)
3014 }
3015
3016 pub fn get_formatted_cell_value(
3037 &self,
3038 sheet_index: u32,
3039 row: i32,
3040 column: i32,
3041 ) -> Result<String, String> {
3042 match self.workbook.worksheet(sheet_index)?.cell(row, column) {
3043 Some(cell) => {
3044 let format = self.get_style_for_cell(sheet_index, row, column)?.num_fmt;
3045 let formatted_value =
3046 cell.formatted_value(&self.workbook.shared_strings, self.language, |value| {
3047 format_number(value, &format, self.locale).text
3048 });
3049 Ok(formatted_value)
3050 }
3051 None => Ok("".to_string()),
3052 }
3053 }
3054
3055 pub fn get_cell_type(&self, sheet: u32, row: i32, column: i32) -> Result<CellType, String> {
3057 Ok(match self.workbook.worksheet(sheet)?.cell(row, column) {
3058 Some(c) => c.get_type(),
3059 None => CellType::Number,
3060 })
3061 }
3062
3063 pub fn get_localized_cell_content(
3070 &self,
3071 sheet: u32,
3072 row: i32,
3073 column: i32,
3074 ) -> Result<String, String> {
3075 let worksheet = self.workbook.worksheet(sheet)?;
3076 let cell = match worksheet.cell(row, column) {
3077 Some(c) => c,
3078 None => return Ok("".to_string()),
3079 };
3080 match cell.get_formula() {
3081 Some(formula_index) => {
3082 let formula = &self.parsed_formulas[sheet as usize][formula_index as usize].0;
3083 let cell_ref = CellReferenceRC {
3084 sheet: worksheet.get_name(),
3085 row,
3086 column,
3087 };
3088 Ok(format!(
3089 "={}",
3090 to_localized_string(formula, &cell_ref, self.locale, self.language)
3091 ))
3092 }
3093 None => {
3094 let style_index = cell.get_style();
3095 let style = self.workbook.styles.get_style(style_index)?;
3096 if style.quote_prefix {
3097 Ok(format!(
3098 "'{}",
3099 cell.get_localized_text(
3100 &self.workbook.shared_strings,
3101 self.locale,
3102 self.language,
3103 )
3104 ))
3105 } else {
3106 if is_likely_date_number_format(&style.num_fmt) {
3108 let value = cell.value(&self.workbook.shared_strings, self.language);
3109 if let CellValue::Number(n) = value {
3110 let formatted = format_number(n, &style.num_fmt, self.locale);
3111 if formatted.error.is_none() {
3112 return Ok(formatted.text);
3113 }
3114 }
3115 }
3116 Ok(cell.get_localized_text(
3117 &self.workbook.shared_strings,
3118 self.locale,
3119 self.language,
3120 ))
3121 }
3122 }
3123 }
3124 }
3125
3126 pub fn get_all_cells(&self) -> Vec<CellIndex> {
3129 let mut cells = Vec::new();
3130 for (index, sheet) in self.workbook.worksheets.iter().enumerate() {
3131 for (row, column, _) in sheet.sheet_data.cells() {
3132 cells.push(CellIndex {
3133 index: index as u32,
3134 row,
3135 column,
3136 });
3137 }
3138 }
3139 cells
3140 }
3141
3142 pub fn range_clear_contents(&mut self, range: &Area) -> Result<(), String> {
3171 if !self.can_clear_range(range)? {
3172 return Err("Cannot clear the range because it contains array formulas".to_string());
3173 }
3174 let sheet = range.sheet;
3175 let ws = self.workbook.worksheet_mut(sheet)?;
3176 for row in range.row..range.row + range.height {
3177 for column in range.column..range.column + range.width {
3178 let structure = ws.get_cell_structure(row, column)?;
3179 match structure {
3180 CellStructure::DynamicFormula { range }
3181 | CellStructure::ArrayFormula { range, .. } => {
3182 let (width, height) = range;
3183 for r in row..row + height {
3184 for c in column..column + width {
3185 let _ = ws.cell_clear_contents(r, c);
3186 }
3187 }
3188 }
3189 _ => {
3190 let _ = ws.cell_clear_contents(row, column);
3191 }
3192 }
3193 }
3194 }
3195 ws.links.retain(|&(row, column), _| {
3197 row < range.row
3198 || row >= range.row + range.height
3199 || column < range.column
3200 || column >= range.column + range.width
3201 });
3202 Ok(())
3203 }
3204
3205 pub(crate) fn can_clear_range(&self, range: &Area) -> Result<bool, String> {
3208 let sheet = range.sheet;
3209 for row in range.row..range.row + range.height {
3210 for column in range.column..range.column + range.width {
3211 match self.get_cell_structure(sheet, row, column)? {
3212 CellStructure::ArrayFormula { range: r } => {
3213 let (width, height) = r;
3214 if column + width > range.column + range.width
3215 || row + height > range.row + range.height
3216 {
3217 return Ok(false);
3218 }
3219 }
3220 CellStructure::SpillArray {
3221 anchor: a,
3222 range: r,
3223 } => {
3224 let (anchor_row, anchor_column) = a;
3225 let (width, height) = r;
3226 if anchor_column < range.column
3227 || anchor_row < range.row
3228 || anchor_column + width > range.column + range.width
3229 || anchor_row + height > range.row + range.height
3230 {
3231 return Ok(false);
3232 }
3233 }
3234 _ => {
3235 }
3237 }
3238 }
3239 }
3240 Ok(true)
3241 }
3242
3243 pub fn range_clear_all(&mut self, area: &Area) -> Result<(), String> {
3273 if !self.can_clear_range(area)? {
3274 return Err("Cannot clear the range because it contains array formulas".to_string());
3275 }
3276 let worksheet = self.workbook.worksheet_mut(area.sheet)?;
3277
3278 let sheet_data = &mut worksheet.sheet_data;
3279 let mut cells_to_clear = Vec::new();
3280 for row in area.row..area.row + area.height {
3281 for column in sheet_data.columns_in_row(row) {
3283 if column < area.column || column >= area.column + area.width {
3284 continue;
3285 }
3286 if let Some(Cell::ArrayFormula {
3288 r,
3289 kind: ArrayKind::Dynamic,
3290 ..
3291 }) = sheet_data.cell(row, column).as_deref()
3292 {
3293 let (width, height) = *r;
3295 for r in row..row + height {
3296 for c in column..column + width {
3297 cells_to_clear.push((r, c));
3298 }
3299 }
3300 }
3301 sheet_data.remove_cell(row, column);
3302 }
3303 }
3304 for (row, column) in cells_to_clear {
3305 let _ = worksheet.cell_clear_contents(row, column);
3307 }
3308 worksheet.links.retain(|&(row, column), _| {
3310 row < area.row
3311 || row >= area.row + area.height
3312 || column < area.column
3313 || column >= area.column + area.width
3314 });
3315 Ok(())
3316 }
3317
3318 pub(crate) fn reset_dynamic_array_spills(&mut self, sheet: u32) -> Result<(), String> {
3322 let anchors: Vec<(i32, i32, i32, i32, i32, i32)> = {
3324 let ws = self.workbook.worksheet(sheet)?;
3325 let mut result = Vec::new();
3326 for (row, column, cell) in ws.sheet_data.cells() {
3327 if let Cell::ArrayFormula {
3328 r,
3329 f,
3330 s,
3331 kind: ArrayKind::Dynamic,
3332 ..
3333 } = &*cell
3334 {
3335 let (width, height) = *r;
3336 result.push((row, column, *f, *s, width, height));
3337 }
3338 }
3339 result
3340 };
3341
3342 for (row, column, f, s, width, height) in anchors {
3343 let ws = self.workbook.worksheet_mut(sheet)?;
3344 if let Some(cell) = ws.cell_mut(row, column) {
3346 *cell = Cell::ArrayFormula {
3347 f,
3348 s,
3349 r: (1, 1),
3350 kind: ArrayKind::Dynamic,
3351 v: FormulaValue::Unevaluated,
3352 };
3353 }
3354 for r in row..row + height {
3356 for c in column..column + width {
3357 if r == row && c == column {
3358 continue;
3359 }
3360 let _ = ws.cell_clear_contents(r, c);
3361 }
3362 }
3363 }
3364 Ok(())
3365 }
3366
3367 pub fn get_cell_style_index(&self, sheet: u32, row: i32, column: i32) -> Result<i32, String> {
3369 let cell = self.workbook.worksheet(sheet)?.cell(row, column);
3371
3372 match cell {
3373 Some(cell) => Ok(cell.get_style()),
3374 None => {
3375 let rows = &self.workbook.worksheet(sheet)?.rows;
3376 for r in rows {
3377 if r.r == row {
3378 if r.custom_format {
3379 return Ok(r.s);
3380 }
3381 break;
3382 }
3383 }
3384 let cols = &self.workbook.worksheet(sheet)?.cols;
3385 for c in cols.iter() {
3386 let min = c.min;
3387 let max = c.max;
3388 if column >= min && column <= max {
3389 return Ok(c.style.unwrap_or(0));
3390 }
3391 }
3392 Ok(0)
3393 }
3394 }
3395 }
3396
3397 pub fn get_style_for_cell(&self, sheet: u32, row: i32, column: i32) -> Result<Style, String> {
3400 let style_index = self.get_cell_style_index(sheet, row, column)?;
3401 let style = self.workbook.styles.get_style(style_index)?;
3402 Ok(style)
3403 }
3404
3405 pub fn get_cell_style_or_none(
3407 &self,
3408 sheet: u32,
3409 row: i32,
3410 column: i32,
3411 ) -> Result<Option<Style>, String> {
3412 let style = self
3413 .workbook
3414 .worksheet(sheet)?
3415 .cell(row, column)
3416 .map(|c| self.workbook.styles.get_style(c.get_style()))
3417 .transpose();
3418 style
3419 }
3420
3421 pub fn to_bytes(&self) -> Vec<u8> {
3426 bitcode::encode(&self.workbook)
3427 }
3428
3429 pub fn get_worksheets_properties(&self) -> Vec<SheetProperties> {
3431 self.workbook
3432 .worksheets
3433 .iter()
3434 .map(|worksheet| SheetProperties {
3435 name: worksheet.get_name(),
3436 state: worksheet.state.to_string(),
3437 color: worksheet.color.clone(),
3438 sheet_id: worksheet.sheet_id,
3439 })
3440 .collect()
3441 }
3442
3443 pub fn get_sheet_markup(&self, sheet: u32) -> Result<String, String> {
3445 let worksheet = self.workbook.worksheet(sheet)?;
3446 let dimension = worksheet.dimension();
3447
3448 let mut rows = Vec::new();
3449
3450 for row in 1..(dimension.max_row + 1) {
3451 let mut row_markup: Vec<String> = Vec::new();
3452
3453 for column in 1..(dimension.max_column + 1) {
3454 let mut cell_markup = match self.get_cell_formula(sheet, row, column)? {
3455 Some(formula) => formula,
3456 None => self.get_formatted_cell_value(sheet, row, column)?,
3457 };
3458 let style = self.get_style_for_cell(sheet, row, column)?;
3459 if style.font.b {
3460 cell_markup = format!("**{cell_markup}**")
3461 }
3462 row_markup.push(cell_markup);
3463 }
3464
3465 rows.push(row_markup.join("|"));
3466 }
3467
3468 Ok(rows.join("\n"))
3469 }
3470
3471 pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, String> {
3473 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3474 Ok(worksheet.frozen_rows)
3475 } else {
3476 Err("Invalid sheet".to_string())
3477 }
3478 }
3479
3480 pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, String> {
3482 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3483 Ok(worksheet.frozen_columns)
3484 } else {
3485 Err("Invalid sheet".to_string())
3486 }
3487 }
3488
3489 pub fn set_frozen_rows(&mut self, sheet: u32, frozen_rows: i32) -> Result<(), String> {
3492 if let Some(worksheet) = self.workbook.worksheets.get_mut(sheet as usize) {
3493 if frozen_rows < 0 {
3494 return Err("Frozen rows cannot be negative".to_string());
3495 }
3496 if frozen_rows >= LAST_ROW {
3497 return Err("Too many rows".to_string());
3498 }
3499 worksheet.frozen_rows = frozen_rows;
3500 Ok(())
3501 } else {
3502 Err("Invalid sheet".to_string())
3503 }
3504 }
3505
3506 pub fn set_frozen_columns(&mut self, sheet: u32, frozen_columns: i32) -> Result<(), String> {
3509 if let Some(worksheet) = self.workbook.worksheets.get_mut(sheet as usize) {
3510 if frozen_columns < 0 {
3511 return Err("Frozen columns cannot be negative".to_string());
3512 }
3513 if frozen_columns >= LAST_COLUMN {
3514 return Err("Too many columns".to_string());
3515 }
3516 worksheet.frozen_columns = frozen_columns;
3517 Ok(())
3518 } else {
3519 Err("Invalid sheet".to_string())
3520 }
3521 }
3522
3523 #[inline]
3525 pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, String> {
3526 self.workbook.worksheet(sheet)?.get_column_width(column)
3527 }
3528
3529 #[inline]
3531 pub fn set_column_width(&mut self, sheet: u32, column: i32, width: f64) -> Result<(), String> {
3532 self.workbook
3533 .worksheet_mut(sheet)?
3534 .set_column_width(column, width)
3535 }
3536
3537 #[inline]
3539 pub fn set_column_hidden(
3540 &mut self,
3541 sheet: u32,
3542 column: i32,
3543 hidden: bool,
3544 ) -> Result<(), String> {
3545 self.workbook
3546 .worksheet_mut(sheet)?
3547 .set_column_hidden(column, hidden)
3548 }
3549
3550 #[inline]
3552 pub fn set_row_hidden(&mut self, sheet: u32, row: i32, hidden: bool) -> Result<(), String> {
3553 self.workbook
3554 .worksheet_mut(sheet)?
3555 .set_row_hidden(row, hidden)
3556 }
3557
3558 #[inline]
3560 pub fn is_column_hidden(&self, sheet: u32, column: i32) -> Result<bool, String> {
3561 self.workbook.worksheet(sheet)?.is_column_hidden(column)
3562 }
3563
3564 #[inline]
3566 pub fn is_row_hidden(&self, sheet: u32, row: i32) -> Result<bool, String> {
3567 self.workbook.worksheet(sheet)?.is_row_hidden(row)
3568 }
3569
3570 #[inline]
3572 pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, String> {
3573 self.workbook.worksheet(sheet)?.row_height(row)
3574 }
3575
3576 #[inline]
3578 pub fn set_row_height(&mut self, sheet: u32, column: i32, height: f64) -> Result<(), String> {
3579 self.workbook
3580 .worksheet_mut(sheet)?
3581 .set_row_height(column, height)
3582 }
3583
3584 pub fn new_defined_name(
3587 &mut self,
3588 name: &str,
3589 scope: Option<u32>,
3590 formula: &str,
3591 ) -> Result<(), String> {
3592 let sheet_id = self.is_valid_defined_name(name, scope, formula)?;
3593 let context = self.defined_name_context();
3596 let internal_formula = self.user_formula_to_internal(formula, &context)?;
3597 self.workbook.defined_names.push(DefinedName {
3598 name: name.to_string(),
3599 formula: internal_formula,
3600 sheet_id,
3601 });
3602 self.reset_parsed_structures();
3603
3604 Ok(())
3605 }
3606
3607 pub(crate) fn defined_name_context(&self) -> CellReferenceRC {
3610 CellReferenceRC {
3611 sheet: self
3612 .workbook
3613 .worksheets
3614 .first()
3615 .map(|ws| ws.get_name())
3616 .unwrap_or_else(|| "Sheet1".to_string()),
3617 row: 1,
3618 column: 1,
3619 }
3620 }
3621
3622 pub fn is_valid_defined_name(
3624 &mut self,
3625 name: &str,
3626 scope: Option<u32>,
3627 formula: &str,
3628 ) -> Result<Option<u32>, String> {
3629 if !is_valid_identifier(name) {
3630 return Err("Name: Invalid defined name".to_string());
3631 }
3632 let name_upper = name.to_uppercase();
3633 let defined_names = &self.workbook.defined_names;
3634 let sheet_id = match scope {
3635 Some(index) => match self.workbook.worksheet(index) {
3636 Ok(ws) => Some(ws.sheet_id),
3637 Err(_) => return Err("Scope: Invalid sheet index".to_string()),
3638 },
3639 None => None,
3640 };
3641 for df in defined_names {
3643 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
3644 return Err("Name: Defined name already exists".to_string());
3645 }
3646 }
3647
3648 let is_reference =
3650 common::ParsedReference::parse_reference_formula(None, formula, self.locale, |name| {
3651 self.get_sheet_index_by_name(name)
3652 })
3653 .is_ok();
3654
3655 if !is_reference {
3656 use crate::expressions::types::CellReferenceRC;
3659 let formula_body = formula.strip_prefix('=').unwrap_or(formula);
3660 let dummy_ref = CellReferenceRC {
3661 sheet: self
3662 .workbook
3663 .worksheets
3664 .first()
3665 .map(|ws| ws.get_name())
3666 .unwrap_or_else(|| "Sheet1".to_string()),
3667 row: 1,
3668 column: 1,
3669 };
3670 let mut node = self.parser.parse(formula_body, &dummy_ref);
3674 if let Node::ParseErrorKind { .. } = node {
3675 node = self.parse_internal_formula(formula_body, &dummy_ref);
3676 }
3677 if !matches!(node, Node::LambdaDefKind { .. }) {
3678 return Err("Formula: Invalid defined name formula".to_string());
3679 }
3680 }
3681
3682 Ok(sheet_id)
3683 }
3684
3685 pub fn delete_defined_name(&mut self, name: &str, scope: Option<u32>) -> Result<(), String> {
3687 let name_upper = name.to_uppercase();
3688 let defined_names = &self.workbook.defined_names;
3689 let sheet_id = match scope {
3690 Some(index) => Some(self.workbook.worksheet(index)?.sheet_id),
3691 None => None,
3692 };
3693 let mut index = None;
3694 for (i, df) in defined_names.iter().enumerate() {
3695 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
3696 index = Some(i);
3697 }
3698 }
3699 if let Some(i) = index {
3700 self.workbook.defined_names.remove(i);
3701 self.reset_parsed_structures();
3702 Ok(())
3703 } else {
3704 Err("Defined name not found".to_string())
3705 }
3706 }
3707
3708 pub fn update_defined_name(
3710 &mut self,
3711 name: &str,
3712 scope: Option<u32>,
3713 new_name: &str,
3714 new_scope: Option<u32>,
3715 new_formula: &str,
3716 ) -> Result<(), String> {
3717 if !is_valid_identifier(new_name) {
3718 return Err("Name: Invalid defined name".to_string());
3719 };
3720 let name_upper = name.to_uppercase();
3721 let new_name_upper = new_name.to_uppercase();
3722
3723 if name_upper != new_name_upper || scope != new_scope {
3724 for key in self.parsed_defined_names.keys() {
3725 if key.1.to_uppercase() == new_name_upper && key.0 == new_scope {
3726 return Err("Name: Defined name already exists".to_string());
3727 }
3728 }
3729 }
3730 let defined_names = &self.workbook.defined_names;
3731 let sheet_id = match scope {
3732 Some(index) => Some(
3733 self.workbook
3734 .worksheet(index)
3735 .map_err(|_| "Scope: Invalid sheet index")?
3736 .sheet_id,
3737 ),
3738 None => None,
3739 };
3740
3741 let new_sheet_id = match new_scope {
3742 Some(index) => Some(
3743 self.workbook
3744 .worksheet(index)
3745 .map_err(|_| "Scope: Invalid sheet index")?
3746 .sheet_id,
3747 ),
3748 None => None,
3749 };
3750
3751 let mut index = None;
3752 for (i, df) in defined_names.iter().enumerate() {
3753 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
3754 index = Some(i);
3755 }
3756 }
3757 let context = self.defined_name_context();
3759 let internal_formula = self.user_formula_to_internal(new_formula, &context)?;
3760 if let Some(i) = index {
3761 if let Some(df) = self.workbook.defined_names.get_mut(i) {
3762 if new_name != df.name {
3763 self.parser.set_lexer_mode(LexerMode::R1C1);
3768 let worksheets = &mut self.workbook.worksheets;
3769 for worksheet in worksheets {
3770 let cell_reference = CellReferenceRC {
3771 sheet: worksheet.get_name(),
3772 row: 1,
3773 column: 1,
3774 };
3775 let mut formulas = Vec::new();
3776 for formula in &worksheet.shared_formulas {
3777 let mut t = self.parser.parse(formula, &cell_reference);
3778 rename_defined_name_in_node(&mut t, name, scope, new_name);
3779 formulas.push(to_rc_format(&t));
3780 }
3781 worksheet.shared_formulas = formulas;
3782 }
3783 self.parser.set_lexer_mode(LexerMode::A1);
3785 }
3786 df.name = new_name.to_string();
3787 df.sheet_id = new_sheet_id;
3788 df.formula = internal_formula;
3789 self.reset_parsed_structures();
3790 }
3791 Ok(())
3792 } else {
3793 Err("Defined name not found".to_string())
3794 }
3795 }
3796 pub fn get_column_style(&self, sheet: u32, column: i32) -> Result<Option<Style>, String> {
3798 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3799 let cols = &worksheet.cols;
3800 for col in cols {
3801 if column >= col.min && column <= col.max {
3802 if let Some(style_index) = col.style {
3803 let style = self.workbook.styles.get_style(style_index)?;
3804 return Ok(Some(style));
3805 }
3806 return Ok(None);
3807 }
3808 }
3809 Ok(None)
3810 } else {
3811 Err("Invalid sheet".to_string())
3812 }
3813 }
3814
3815 pub fn get_row_style(&self, sheet: u32, row: i32) -> Result<Option<Style>, String> {
3817 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3818 let rows = &worksheet.rows;
3819 for r in rows {
3820 if row == r.r {
3821 let style = self.workbook.styles.get_style(r.s)?;
3822 return Ok(Some(style));
3823 }
3824 }
3825 Ok(None)
3826 } else {
3827 Err("Invalid sheet".to_string())
3828 }
3829 }
3830
3831 pub fn set_column_style(
3833 &mut self,
3834 sheet: u32,
3835 column: i32,
3836 style: &Style,
3837 ) -> Result<(), String> {
3838 let style_index = self.workbook.styles.get_style_index_or_create(style);
3839 self.workbook
3840 .worksheet_mut(sheet)?
3841 .set_column_style(column, style_index)
3842 }
3843
3844 pub fn set_row_style(&mut self, sheet: u32, row: i32, style: &Style) -> Result<(), String> {
3846 let style_index = self.workbook.styles.get_style_index_or_create(style);
3847 self.workbook
3848 .worksheet_mut(sheet)?
3849 .set_row_style(row, style_index)
3850 }
3851
3852 pub fn delete_column_style(&mut self, sheet: u32, column: i32) -> Result<(), String> {
3854 self.workbook
3855 .worksheet_mut(sheet)?
3856 .delete_column_style(column)
3857 }
3858
3859 pub fn delete_row_style(&mut self, sheet: u32, row: i32) -> Result<(), String> {
3861 self.workbook.worksheet_mut(sheet)?.delete_row_style(row)
3862 }
3863
3864 pub fn set_locale(&mut self, locale_id: &str) -> Result<(), String> {
3866 let locale = match get_locale(locale_id) {
3867 Ok(l) => l,
3868 Err(_) => return Err(format!("Invalid locale: {locale_id}")),
3869 };
3870 self.parser.set_locale(locale);
3871 self.locale = locale;
3872 self.workbook.settings.locale = locale_id.to_string();
3873 self.evaluate();
3874 Ok(())
3875 }
3876
3877 pub fn set_timezone(&mut self, timezone: &str) -> Result<(), String> {
3879 let tz = match Tz::parse(timezone) {
3880 Ok(tz) => tz,
3881 Err(_) => return Err(format!("Invalid timezone: {}", timezone)),
3882 };
3883 self.tz = tz;
3884 self.workbook.settings.tz = timezone.to_string();
3885 self.evaluate();
3886 Ok(())
3887 }
3888
3889 pub fn set_language(&mut self, language_id: &str) -> Result<(), String> {
3891 let language = match get_language(language_id) {
3892 Ok(l) => l,
3893 Err(_) => return Err(format!("Invalid language: {language_id}")),
3894 };
3895 self.parser.set_language(language);
3896 self.language = language;
3897 Ok(())
3898 }
3899
3900 pub fn get_language(&self) -> String {
3902 self.language.code.clone()
3903 }
3904
3905 pub fn get_timezone(&self) -> String {
3907 self.workbook.settings.tz.clone()
3908 }
3909
3910 pub fn get_locale(&self) -> String {
3912 self.workbook.settings.locale.clone()
3913 }
3914
3915 pub fn get_fmt_settings(&self) -> FmtSettings {
3917 let day_example = 46006.0; let currency = self.locale.currency.iso.clone();
3919 let currency_symbol = &self.locale.currency.symbol;
3920 let short_date = &self.locale.dates.date_formats.short;
3922 let long_date = &self.locale.dates.date_formats.long;
3924 let short_date_example = format_number(day_example, short_date, self.locale).text;
3925 let long_date_example = format_number(day_example, long_date, self.locale).text;
3926 let currency_format_template = &self.locale.numbers.currency_formats.standard;
3931 let currency_format = currency_format_template
3932 .replace("¤", &format!("\"{}\"", currency_symbol))
3933 .replace(" ", " ");
3934
3935 let number_fmt = "#,##0.00".to_string();
3936 let number_example = format_number(1234.567, &number_fmt, self.locale).text;
3937 FmtSettings {
3938 currency,
3939 currency_format,
3940 short_date: short_date.clone(),
3941 long_date: long_date.clone(),
3942 short_date_example,
3943 long_date_example,
3944 number_fmt,
3945 number_example,
3946 }
3947 }
3948
3949 pub fn cycle_reference(
3955 &self,
3956 value: &str,
3957 start: usize,
3958 end: usize,
3959 ) -> Result<(String, i32, i32), String> {
3960 crate::expressions::lexer::util::cycle_reference(
3961 value,
3962 start,
3963 end,
3964 self.locale,
3965 self.language,
3966 )
3967 }
3968}
3969
3970#[cfg(test)]
3971mod tests {
3972 #![allow(clippy::expect_used)]
3973 use super::CellReferenceIndex as CellReference;
3974 use crate::{test::util::new_empty_model, types::Cell};
3975
3976 #[test]
3977 fn test_cell_reference_to_string() {
3978 let model = new_empty_model();
3979 let reference = CellReference {
3980 sheet: 0,
3981 row: 32,
3982 column: 16,
3983 };
3984 assert_eq!(
3985 model.cell_reference_to_string(&reference),
3986 Ok("Sheet1!P32".to_string())
3987 )
3988 }
3989
3990 #[test]
3991 fn test_cell_reference_to_string_invalid_worksheet() {
3992 let model = new_empty_model();
3993 let reference = CellReference {
3994 sheet: 10,
3995 row: 1,
3996 column: 1,
3997 };
3998 assert_eq!(
3999 model.cell_reference_to_string(&reference),
4000 Err("Invalid sheet index".to_string())
4001 )
4002 }
4003
4004 #[test]
4005 fn test_cell_reference_to_string_invalid_column() {
4006 let model = new_empty_model();
4007 let reference = CellReference {
4008 sheet: 0,
4009 row: 1,
4010 column: 20_000,
4011 };
4012 assert_eq!(
4013 model.cell_reference_to_string(&reference),
4014 Err("Invalid column".to_string())
4015 )
4016 }
4017
4018 #[test]
4019 fn test_cell_reference_to_string_invalid_row() {
4020 let model = new_empty_model();
4021 let reference = CellReference {
4022 sheet: 0,
4023 row: 2_000_000,
4024 column: 1,
4025 };
4026 assert_eq!(
4027 model.cell_reference_to_string(&reference),
4028 Err("Invalid row".to_string())
4029 )
4030 }
4031
4032 #[test]
4033 fn test_get_cell() {
4034 let mut model = new_empty_model();
4035 model._set("A1", "35");
4036 model._set("A2", "");
4037 let worksheet = model.workbook.worksheet(0).expect("Invalid sheet");
4038
4039 assert_eq!(
4040 worksheet.cell(1, 1).as_deref(),
4041 Some(&Cell::NumberCell { v: 35.0, s: 0 })
4042 );
4043
4044 assert_eq!(
4046 worksheet.cell(2, 1).as_deref(),
4047 Some(&Cell::EmptyCell { s: 0 })
4048 );
4049 assert_eq!(worksheet.cell(3, 1), None)
4050 }
4051
4052 #[test]
4053 fn test_get_cell_invalid_sheet() {
4054 let model = new_empty_model();
4055 assert_eq!(
4056 model.workbook.worksheet(5),
4057 Err("Invalid sheet index".to_string()),
4058 )
4059 }
4060
4061 #[test]
4062 fn test_update_cell_with_sign_prefixed_formulas() {
4063 let mut model = new_empty_model();
4064
4065 let update_result = model.update_cell_with_formula(0, 1, 1, "-A2*2".to_string());
4066 model.evaluate();
4067 assert_eq!(update_result, Ok(()));
4068 assert_eq!(model._get_formula("A1"), *"=-A2*2");
4069 }
4070}