1#![deny(missing_docs)]
2
3use std::collections::HashMap;
4use std::vec::Vec;
5
6use crate::expressions::parser::static_analysis::run_static_analysis_on_node;
7use crate::{
8 calc_result::{CalcResult, Range},
9 cell::CellValue,
10 constants::{self, LAST_COLUMN, LAST_ROW},
11 expressions::{
12 lexer::LexerMode,
13 parser::{
14 move_formula::{move_formula, MoveContext},
15 new_parser_english,
16 static_analysis::StaticResult,
17 stringify::{
18 rename_defined_name_in_node, to_english_string, to_localized_string, to_rc_format,
19 },
20 ArrayNode, CompletionContext, NamedVariable, Node, Parser,
21 },
22 token::{get_error_by_name, Error, OpProduct, OpSum, OpUnary},
23 types::*,
24 utils::{self, is_valid_column_number, is_valid_identifier, is_valid_row},
25 },
26 formatter::{
27 format::{format_number, parse_formatted_number},
28 lexer::is_likely_date_number_format,
29 },
30 implicit_intersection::implicit_intersection,
31 language::{get_default_language, get_language, Language},
32 locale::{get_default_locale, get_locale, Locale},
33 types::*,
34 utils as common,
35};
36
37use crate::{cf_types::CfCellResult, tz::Tz};
38
39#[cfg(any(test, feature = "mock_time"))]
40pub use crate::mock_time::get_milliseconds_since_epoch;
41
42#[cfg(not(any(test, feature = "mock_time")))]
48#[cfg(not(target_arch = "wasm32"))]
49#[allow(clippy::expect_used)]
50pub fn get_milliseconds_since_epoch() -> i64 {
51 use std::time::{SystemTime, UNIX_EPOCH};
52 SystemTime::now()
53 .duration_since(UNIX_EPOCH)
54 .expect("problem with system time")
55 .as_millis() as i64
56}
57
58#[cfg(not(any(test, feature = "mock_time")))]
64#[cfg(target_arch = "wasm32")]
65pub fn get_milliseconds_since_epoch() -> i64 {
66 use js_sys::Date;
67 Date::now() as i64
68}
69
70pub(crate) enum CellStructure {
78 SingleCell,
79 ArrayFormula {
80 range: (i32, i32),
81 },
82 DynamicFormula {
83 range: (i32, i32),
84 },
85 SpillArray {
86 anchor: (i32, i32),
87 range: (i32, i32),
88 },
89 SpillDynamic {
90 anchor: (i32, i32),
91 range: (i32, i32),
92 },
93}
94
95#[derive(Clone)]
97pub(crate) enum CellState {
98 Evaluated,
100 Evaluating,
102}
103
104#[derive(Clone)]
106pub(crate) enum ParsedDefinedName {
107 CellReference(CellReferenceIndex),
109 RangeReference(Range),
111 LambdaDefinition(Vec<NamedVariable>, Node),
113 InvalidDefinedNameFormula,
115}
116
117pub struct FmtSettings {
119 pub currency: String,
121 pub currency_format: String,
123 pub short_date: String,
125 pub short_date_example: String,
127 pub long_date: String,
129 pub long_date_example: String,
131 pub number_fmt: String,
133 pub number_example: String,
135}
136
137fn array_node_to_formula_value(node: ArrayNode) -> FormulaValue {
138 match node {
139 ArrayNode::Boolean(b) => FormulaValue::Boolean(b),
140 ArrayNode::Number(n) => FormulaValue::Number(n),
141 ArrayNode::String(s) => FormulaValue::Text(s),
142 ArrayNode::Error(ei) => FormulaValue::Error {
143 ei,
144 o: String::new(),
145 m: String::new(),
146 },
147 ArrayNode::Empty => FormulaValue::Number(0.0),
148 }
149}
150
151fn array_node_to_spill_value(node: ArrayNode) -> SpillValue {
152 match node {
153 ArrayNode::Boolean(b) => SpillValue::Boolean(b),
154 ArrayNode::Number(n) => SpillValue::Number(n),
155 ArrayNode::String(s) => SpillValue::Text(s),
156 ArrayNode::Error(ei) => SpillValue::Error(ei),
157 ArrayNode::Empty => SpillValue::Number(0.0),
158 }
159}
160
161fn formula_value_to_spill_value(v: &FormulaValue) -> SpillValue {
162 match v {
163 FormulaValue::Unevaluated => SpillValue::Error(Error::ERROR),
164 FormulaValue::Boolean(b) => SpillValue::Boolean(*b),
165 FormulaValue::Number(n) => SpillValue::Number(*n),
166 FormulaValue::Text(s) => SpillValue::Text(s.clone()),
167 FormulaValue::Error { ei, .. } => SpillValue::Error(ei.clone()),
168 }
169}
170
171pub(crate) enum CellOrRange {
172 Cell((u32, i32, i32)),
174 Range((u32, i32, i32, i32, i32)),
176}
177
178pub struct Model<'a> {
191 pub workbook: Workbook,
193 pub parsed_formulas: Vec<Vec<(Node, StaticResult)>>,
195 pub(crate) parsed_defined_names: HashMap<(Option<u32>, String), ParsedDefinedName>,
197 pub(crate) shared_strings: HashMap<String, usize>,
199 pub(crate) parser: Parser<'a>,
201 pub(crate) cells: HashMap<(u32, i32, i32), CellState>,
203 pub(crate) locale: &'a Locale,
205 pub(crate) language: &'a Language,
207 pub(crate) tz: Tz,
209 pub(crate) view_id: u32,
211 pub(crate) variable_stack: HashMap<usize, CalcResult>,
213 pub(crate) last_variable_id: usize,
215 pub(crate) lambdas: HashMap<usize, (Vec<NamedVariable>, Node)>,
217 pub(crate) last_lambda_id: usize,
219 pub(crate) spill_cells: Vec<CellReferenceIndex>,
221 pub(crate) support: HashMap<CellReferenceIndex, Vec<CellOrRange>>,
223 pub(crate) cf_cache: HashMap<(u32, i32, i32), Vec<CfCellResult>>,
226}
227
228pub struct CellIndex {
231 pub index: u32,
233 pub row: i32,
235 pub column: i32,
237}
238
239impl<'a> Model<'a> {
240 pub(crate) fn get_next_variable_id(&mut self) -> usize {
241 let id = self.last_variable_id;
242 self.last_variable_id += 1;
243 id
244 }
245 fn clear_variable_stack(&mut self) {
246 self.variable_stack.clear();
247 self.last_variable_id = 0;
248 }
249 pub(crate) fn get_next_lambda_id(&mut self) -> usize {
250 let id = self.last_lambda_id;
251 self.last_lambda_id += 1;
252 id
253 }
254 fn clear_lambdas(&mut self) {
255 self.lambdas.clear();
256 self.last_lambda_id = 0;
257 }
258 pub(crate) fn evaluate_node_with_reference(
259 &mut self,
260 node: &Node,
261 cell: CellReferenceIndex,
262 ) -> CalcResult {
263 match node {
264 Node::ReferenceKind {
265 sheet_name: _,
266 sheet_index,
267 absolute_row,
268 absolute_column,
269 row,
270 column,
271 } => {
272 let mut row1 = *row;
273 let mut column1 = *column;
274 if !absolute_row {
275 row1 += cell.row;
276 }
277 if !absolute_column {
278 column1 += cell.column;
279 }
280 CalcResult::Range {
281 left: CellReferenceIndex {
282 sheet: *sheet_index,
283 row: row1,
284 column: column1,
285 },
286 right: CellReferenceIndex {
287 sheet: *sheet_index,
288 row: row1,
289 column: column1,
290 },
291 }
292 }
293 Node::RangeKind {
294 sheet_name: _,
295 sheet_index,
296 absolute_row1,
297 absolute_column1,
298 row1,
299 column1,
300 absolute_row2,
301 absolute_column2,
302 row2,
303 column2,
304 } => {
305 let mut row_left = *row1;
306 let mut column_left = *column1;
307 if !absolute_row1 {
308 row_left += cell.row;
309 }
310 if !absolute_column1 {
311 column_left += cell.column;
312 }
313 let mut row_right = *row2;
314 let mut column_right = *column2;
315 if !absolute_row2 {
316 row_right += cell.row;
317 }
318 if !absolute_column2 {
319 column_right += cell.column;
320 }
321 CalcResult::Range {
323 left: CellReferenceIndex {
324 sheet: *sheet_index,
325 row: row_left,
326 column: column_left,
327 },
328 right: CellReferenceIndex {
329 sheet: *sheet_index,
330 row: row_right,
331 column: column_right,
332 },
333 }
334 }
335 Node::ImplicitIntersection {
336 automatic: _,
337 child,
338 } => match self.evaluate_node_with_reference(child, cell) {
339 CalcResult::Range { left, right } => CalcResult::Range { left, right },
340 _ => CalcResult::new_error(
341 Error::ERROR,
342 cell,
343 format!("Error with Implicit Intersection in cell {cell:?}"),
344 ),
345 },
346 _ => self.evaluate_node_in_context(node, cell),
347 }
348 }
349
350 fn get_range(&mut self, left: &Node, right: &Node, cell: CellReferenceIndex) -> CalcResult {
351 let left_result = self.evaluate_node_with_reference(left, cell);
352 let right_result = self.evaluate_node_with_reference(right, cell);
353 match (left_result, right_result) {
354 (
355 CalcResult::Range {
356 left: left1,
357 right: right1,
358 },
359 CalcResult::Range {
360 left: left2,
361 right: right2,
362 },
363 ) => {
364 if left1.row == right1.row
365 && left1.column == right1.column
366 && left2.row == right2.row
367 && left2.column == right2.column
368 {
369 return CalcResult::Range {
370 left: left1,
371 right: right2,
372 };
373 }
374 CalcResult::Error {
375 error: Error::VALUE,
376 origin: cell,
377 message: "Invalid range".to_string(),
378 }
379 }
380 _ => CalcResult::Error {
381 error: Error::VALUE,
382 origin: cell,
383 message: "Invalid range".to_string(),
384 },
385 }
386 }
387
388 pub(crate) fn formula_without_prefix<'b>(&self, value: &'b str) -> Option<&'b str> {
389 if let Some(stripped) = value.strip_prefix('=') {
390 if stripped.is_empty() {
391 None
392 } else {
393 Some(stripped)
394 }
395 } else if let Some(stripped) = value.strip_prefix(['+', '-']) {
396 if stripped.is_empty() || self.cast_number(stripped).is_some() {
397 None
398 } else {
399 Some(value)
400 }
401 } else {
402 None
403 }
404 }
405
406 pub(crate) fn parse_internal_formula(&mut self, body: &str, context: &CellReferenceRC) -> Node {
415 let locale = self.locale;
416 let language = self.language;
417 self.parser.set_locale(get_default_locale());
418 self.parser.set_language(get_default_language());
419 let node = self.parser.parse(body, context);
420 self.parser.set_locale(locale);
421 self.parser.set_language(language);
422 node
423 }
424
425 pub(crate) fn user_formula_to_internal(
434 &mut self,
435 formula: &str,
436 context: &CellReferenceRC,
437 ) -> Result<String, String> {
438 let trimmed = formula.trim();
439 let had_equals = trimmed.starts_with('=');
440 let body = trimmed.strip_prefix('=').unwrap_or(trimmed);
441 let mut node = self.parser.parse(body, context);
442 if let Node::ParseErrorKind { .. } = node {
443 node = self.parse_internal_formula(body, context);
446 }
447 if let Node::ParseErrorKind { .. } = node {
448 return Err(format!("Invalid formula: '{formula}'"));
449 }
450 let english = to_english_string(&node, context);
451 Ok(if had_equals {
452 format!("={english}")
453 } else {
454 english
455 })
456 }
457
458 pub fn formula_completion(
465 &mut self,
466 sheet: u32,
467 row: i32,
468 column: i32,
469 formula: &str,
470 cursor: usize,
471 ) -> Result<CompletionContext, String> {
472 let sheet_name = self.workbook.worksheet(sheet)?.get_name();
473 let cell_reference = CellReferenceRC {
474 sheet: sheet_name,
475 row,
476 column,
477 };
478 let (body, cursor) = match formula.strip_prefix('=') {
481 Some(rest) => (rest, cursor.saturating_sub(1)),
482 None => (formula, cursor),
483 };
484 Ok(self.parser.parse_at_cursor(body, cursor, &cell_reference))
485 }
486
487 pub(crate) fn internal_formula_to_display(
491 &self,
492 formula: &str,
493 context: &CellReferenceRC,
494 ) -> String {
495 let trimmed = formula.trim();
496 let had_equals = trimmed.starts_with('=');
497 let body = trimmed.strip_prefix('=').unwrap_or(trimmed);
498 if body.is_empty() {
499 return formula.to_string();
500 }
501 let worksheet_names = self
503 .workbook
504 .worksheets
505 .iter()
506 .map(|s| s.get_name())
507 .collect();
508 let defined_names = self.workbook.get_defined_names_with_scope();
509 let mut parser =
510 new_parser_english(worksheet_names, defined_names, self.workbook.tables.clone());
511 let node = parser.parse(body, context);
512 if let Node::ParseErrorKind { .. } = node {
513 return formula.to_string();
514 }
515 let local = to_localized_string(&node, context, self.locale, self.language);
516 if had_equals {
517 format!("={local}")
518 } else {
519 local
520 }
521 }
522
523 pub(crate) fn evaluate_formula(&mut self, formula: &str, sheet: u32) -> Option<f64> {
527 let body = formula.trim().strip_prefix('=').unwrap_or(formula.trim());
528 if body.is_empty() {
529 return None;
530 }
531 let sheet_name = self.workbook.worksheets.get(sheet as usize)?.get_name();
532 let context_rc = CellReferenceRC {
533 sheet: sheet_name,
534 row: 1,
535 column: 1,
536 };
537 let node = self.parse_internal_formula(body, &context_rc);
538 let context_index = CellReferenceIndex {
539 sheet,
540 row: 1,
541 column: 1,
542 };
543 match self.evaluate_node_in_context(&node, context_index) {
544 CalcResult::Number(n) => Some(n),
545 _ => None,
546 }
547 }
548
549 pub(crate) fn evaluate_node_in_context(
550 &mut self,
551 node: &Node,
552 cell: CellReferenceIndex,
553 ) -> CalcResult {
554 use Node::*;
555 match node {
556 OpSumKind { kind, left, right } => match kind {
557 OpSum::Add => self.handle_arithmetic(left, right, cell, &|f1, f2| Ok(f1 + f2)),
558 OpSum::Minus => self.handle_arithmetic(left, right, cell, &|f1, f2| Ok(f1 - f2)),
559 },
560 NumberKind(value) => CalcResult::Number(*value),
561 StringKind(value) => CalcResult::String(value.replace(r#""""#, r#"""#)),
562 BooleanKind(value) => CalcResult::Boolean(*value),
563 ReferenceKind {
564 sheet_name: _,
565 sheet_index,
566 absolute_row,
567 absolute_column,
568 row,
569 column,
570 } => {
571 let mut row1 = *row;
572 let mut column1 = *column;
573 if !absolute_row {
574 row1 += cell.row;
575 }
576 if !absolute_column {
577 column1 += cell.column;
578 }
579 self.support
580 .entry(cell)
581 .or_default()
582 .push(CellOrRange::Cell((*sheet_index, row1, column1)));
583 self.evaluate_cell(CellReferenceIndex {
584 sheet: *sheet_index,
585 row: row1,
586 column: column1,
587 })
588 }
589 WrongReferenceKind { .. } => {
590 CalcResult::new_error(Error::REF, cell, "Wrong reference".to_string())
591 }
592 OpRangeKind { left, right } => self.get_range(left, right, cell),
593 WrongRangeKind { .. } => {
594 CalcResult::new_error(Error::REF, cell, "Wrong range".to_string())
595 }
596 RangeKind {
597 sheet_index,
598 row1,
599 column1,
600 row2,
601 column2,
602 absolute_column1,
603 absolute_row2,
604 absolute_row1,
605 absolute_column2,
606 sheet_name: _,
607 } => {
608 let r1 = if *absolute_row1 {
609 *row1
610 } else {
611 *row1 + cell.row
612 };
613 let r2 = if *absolute_row2 {
614 *row2
615 } else {
616 *row2 + cell.row
617 };
618 let c1 = if *absolute_column1 {
619 *column1
620 } else {
621 *column1 + cell.column
622 };
623 let c2 = if *absolute_column2 {
624 *column2
625 } else {
626 *column2 + cell.column
627 };
628 self.support
629 .entry(cell)
630 .or_default()
631 .push(CellOrRange::Range((
632 *sheet_index,
633 r1.min(r2),
634 c1.min(c2),
635 r1.max(r2),
636 c1.max(c2),
637 )));
638 CalcResult::Range {
639 left: CellReferenceIndex {
640 sheet: *sheet_index,
641 row: r1.min(r2),
642 column: c1.min(c2),
643 },
644 right: CellReferenceIndex {
645 sheet: *sheet_index,
646 row: r1.max(r2),
647 column: c1.max(c2),
648 },
649 }
650 }
651 OpConcatenateKind { left, right } => self.handle_concatenate(left, right, cell),
652 OpProductKind { kind, left, right } => match kind {
653 OpProduct::Times => {
654 self.handle_arithmetic(left, right, cell, &|f1, f2| Ok(f1 * f2))
655 }
656 OpProduct::Divide => self.handle_arithmetic(left, right, cell, &|f1, f2| {
657 if f2 == 0.0 {
658 Err(Error::DIV)
659 } else {
660 Ok(f1 / f2)
661 }
662 }),
663 },
664 OpPowerKind { left, right } => {
665 self.handle_arithmetic(left, right, cell, &|f1, f2| Ok(f1.powf(f2)))
666 }
667 FunctionKind { kind, args } => self.evaluate_function(kind, args, cell),
668 NamedFunctionKind { name, args, id } => {
669 let lambda_result = if let Some(var_id) = id {
670 match self.variable_stack.get(&(*var_id as usize)) {
672 Some(v) => v.clone(),
673 None => {
674 return CalcResult::new_error(
675 Error::NAME,
676 cell,
677 format!("Variable \"{name}\" not found in scope."),
678 )
679 }
680 }
681 } else {
682 let name_lower = name.to_lowercase();
686 let found = self
687 .parsed_defined_names
688 .get(&(Some(cell.sheet), name_lower.clone()))
689 .or_else(|| self.parsed_defined_names.get(&(None, name_lower)))
690 .cloned();
691 match found {
692 Some(ParsedDefinedName::LambdaDefinition(param_names, body)) => {
693 let lambda_id = self.get_next_lambda_id();
694 self.lambdas.insert(lambda_id, (param_names, body));
695 CalcResult::Lambda(lambda_id)
696 }
697 _ => {
698 return CalcResult::new_error(
699 Error::NAME,
700 cell,
701 format!("Invalid function: {name}"),
702 )
703 }
704 }
705 };
706 self.call_lambda(lambda_result, args, cell)
707 }
708 ArrayKind(s) => CalcResult::Array(s.to_owned()),
709 DefinedNameKind((name, scope, _)) => {
710 if let Ok(Some(parsed_defined_name)) = self.get_parsed_defined_name(name, *scope) {
711 match parsed_defined_name {
712 ParsedDefinedName::CellReference(reference) => {
713 self.evaluate_cell(reference)
714 }
715 ParsedDefinedName::RangeReference(range) => CalcResult::Range {
716 left: range.left,
717 right: range.right,
718 },
719 ParsedDefinedName::LambdaDefinition(param_names, body) => {
720 let lambda_id = self.get_next_lambda_id();
721 self.lambdas.insert(lambda_id, (param_names, body));
722 CalcResult::Lambda(lambda_id)
723 }
724 ParsedDefinedName::InvalidDefinedNameFormula => CalcResult::new_error(
725 Error::NAME,
726 cell,
727 format!("Defined name \"{name}\" is not a reference."),
728 ),
729 }
730 } else {
731 CalcResult::new_error(
732 Error::NAME,
733 cell,
734 format!("Defined name \"{name}\" not found."),
735 )
736 }
737 }
738 TableNameKind(s) => CalcResult::new_error(
739 Error::NAME,
740 cell,
741 format!("table name \"{s}\" not supported."),
742 ),
743 NamedVariableKind { name, id: Some(id) } => {
744 match self.variable_stack.get(&(*id as usize)) {
745 Some(v) => v.clone(),
746 None => CalcResult::new_error(
747 Error::NAME,
748 cell,
749 format!("Variable \"{name}\" not found in scope."),
750 ),
751 }
752 }
753 NamedVariableKind { name, id: None } => CalcResult::new_error(
754 Error::NAME,
755 cell,
756 format!("Variable name \"{name}\" not found."),
757 ),
758 CompareKind { kind, left, right } => self.handle_comparison(left, right, cell, kind),
759 UnaryKind { kind, right } => {
760 let r = match self.get_number(right, cell) {
761 Ok(f) => f,
762 Err(s) => {
763 return s;
764 }
765 };
766 match kind {
767 OpUnary::Minus => CalcResult::Number(-r),
768 OpUnary::Percentage => CalcResult::Number(r / 100.0),
769 }
770 }
771 ErrorKind(kind) => CalcResult::new_error(kind.clone(), cell, "".to_string()),
772 ParseErrorKind {
773 formula, message, ..
774 } => CalcResult::new_error(
775 Error::ERROR,
776 cell,
777 format!("Error parsing {formula}: {message}"),
778 ),
779 EmptyArgKind => CalcResult::EmptyArg,
780 SpillRangeOperator { child } => match self.evaluate_node_with_reference(child, cell) {
781 CalcResult::Range { left, right } => {
782 if left != right {
783 return CalcResult::new_error(
784 Error::ERROR,
785 cell,
786 format!("Error with Spill Range Operator in cell {cell:?}"),
787 );
788 }
789 let sheet = left.sheet;
791 let row = left.row;
792 let column = left.column;
793 let worksheet = match self.workbook.worksheet(sheet) {
794 Ok(s) => s,
795 Err(e) => {
796 return CalcResult::new_error(
797 Error::REF,
798 cell,
799 format!("Sheet index {sheet} not found: {e}"),
800 );
801 }
802 };
803 match worksheet.get_cell_spill(row, column) {
804 Ok((width, height)) => CalcResult::Range {
805 left: CellReferenceIndex { sheet, row, column },
806 right: CellReferenceIndex {
807 sheet,
808 row: row + height - 1,
809 column: column + width - 1,
810 },
811 },
812 Err(e) => CalcResult::new_error(
813 Error::REF,
814 cell,
815 format!("Cell {sheet}!{row},{column} not found: {e}"),
816 ),
817 }
818 }
819 _ => CalcResult::new_error(
820 Error::ERROR,
821 cell,
822 format!("Error with Spill Range Operator in cell {cell:?}"),
823 ),
824 },
825 ImplicitIntersection {
826 automatic: _,
827 child,
828 } => match self.evaluate_node_with_reference(child, cell) {
829 CalcResult::Range { left, right } => {
830 match implicit_intersection(&cell, &Range { left, right }) {
831 Some(cell_reference) => self.evaluate_cell(cell_reference),
832 None => CalcResult::new_error(
833 Error::VALUE,
834 cell,
835 format!("Error with Implicit Intersection in cell {cell:?}"),
836 ),
837 }
838 }
839 _ => self.evaluate_node_in_context(child, cell),
840 },
841 LambdaDefKind { parameters, body } => {
842 let id = self.get_next_lambda_id();
843 self.lambdas.insert(id, (parameters.clone(), *body.clone()));
844 CalcResult::Lambda(id)
845 }
846 LambdaCallKind { lambda, args } => {
847 let lambda_result = self.evaluate_node_in_context(lambda, cell);
848 self.call_lambda(lambda_result, args, cell)
849 }
850 }
851 }
852
853 fn cell_reference_to_string(
854 &self,
855 cell_reference: &CellReferenceIndex,
856 ) -> Result<String, String> {
857 let sheet = self.workbook.worksheet(cell_reference.sheet)?;
858 let column = utils::number_to_column(cell_reference.column)
859 .ok_or_else(|| "Invalid column".to_string())?;
860 if !is_valid_row(cell_reference.row) {
861 return Err("Invalid row".to_string());
862 }
863 Ok(format!("{}!{}{}", sheet.name, column, cell_reference.row))
864 }
865
866 fn get_value_from_array(
867 &self,
868 array: &[Vec<ArrayNode>],
869 row: i32,
870 column: i32,
871 ) -> Option<ArrayNode> {
872 let width = array[0].len() as i32;
873 let height = array.len() as i32;
874 if row < 1 || row > height || column < 1 || column > width {
875 return None;
876 }
877 let value = &array[(row - 1) as usize][(column - 1) as usize];
878 Some(value.clone())
879 }
880
881 fn set_cells_with_result(
889 &mut self,
890 cell_reference: CellReferenceIndex,
891 cell: &Cell,
892 result: &CalcResult,
893 ) -> Result<(), String> {
894 let CellReferenceIndex { sheet, column, row } = cell_reference;
895 let original_range = match cell {
896 Cell::ArrayFormula {
897 r,
898 kind: ArrayKind::Cse,
899 ..
900 } => Some((false, (r.0, r.1))),
901 Cell::ArrayFormula {
902 r,
903 kind: ArrayKind::Dynamic,
904 ..
905 } => Some((true, (r.0, r.1))),
906 _ => None,
907 };
908 let s = cell.get_style();
909 let formula = match cell.get_formula() {
910 Some(f) => f,
911 None => return Ok(()),
912 };
913 if let CalcResult::Array(array) = result {
917 if array.is_empty() || array[0].is_empty() {
918 return self.set_cells_with_result(
919 cell_reference,
920 cell,
921 &CalcResult::new_error(
922 Error::CALC,
923 cell_reference,
924 "Formula produced a zero-size array".to_string(),
925 ),
926 );
927 }
928 let array_width = array[0].len() as i32;
929 let array_height = array.len() as i32;
930
931 match original_range {
932 Some((true, _)) => {
933 if row + array_height - 1 > LAST_ROW || column + array_width - 1 > LAST_COLUMN {
934 return self.set_cells_with_result(
935 cell_reference,
936 cell,
937 &CalcResult::new_error(
938 Error::SPILL,
939 cell_reference,
940 "Spill would exceed worksheet bounds".to_string(),
941 ),
942 );
943 }
944 let sheet_data = &self.workbook.worksheets[sheet as usize].sheet_data;
947 for r in row..row + array_height {
948 let row_data = sheet_data.get(&r);
949 for c in column..column + array_width {
950 if r == row && c == column {
951 continue;
952 }
953 let blocking = row_data
960 .and_then(|row_map| row_map.get(&c))
961 .map(|cell| match cell {
962 Cell::EmptyCell { .. } => false,
963 Cell::SpillCell { a, .. } if *a == (row, column) => false,
964 _ => true,
965 })
966 .unwrap_or(false);
967 if blocking {
968 return self.set_cells_with_result(
969 cell_reference,
970 cell,
971 &CalcResult::new_error(
972 Error::SPILL,
973 cell_reference,
974 "Cannot spill array result".to_string(),
975 ),
976 );
977 }
978 }
979 }
980 let worksheet = &mut self.workbook.worksheets[sheet as usize];
981 for r in row..row + array_height {
984 for c in column..column + array_width {
985 let value = array[(r - row) as usize][(c - column) as usize].clone();
986 let cell = if r == row && c == column {
987 Cell::ArrayFormula {
988 f: formula,
989 s,
990 r: (array_width, array_height),
991 kind: ArrayKind::Dynamic,
992 v: array_node_to_formula_value(value),
993 }
994 } else {
995 let existing_style = worksheet.get_style(r, c);
996 Cell::SpillCell {
997 a: (row, column),
998 s: existing_style,
999 v: array_node_to_spill_value(value),
1000 }
1001 };
1002 worksheet.update_cell(r, c, cell)?;
1003 }
1004 }
1005 return Ok(());
1006 }
1007 Some((false, (original_width, original_height))) => {
1008 for r in row..row + original_height {
1011 for c in column..column + original_width {
1012 let rel_row = r - row + 1;
1013 let rel_col = c - column + 1;
1014 let value = self.get_value_from_array(array, rel_row, rel_col);
1015 let new_cell = if r == row && c == column {
1016 let fv = match value {
1017 Some(node) => array_node_to_formula_value(node),
1018 None => FormulaValue::Error {
1019 ei: Error::NIMPL,
1020 o: "".to_string(),
1021 m: "Unexpected array result".to_string(),
1022 },
1023 };
1024 Cell::ArrayFormula {
1025 f: formula,
1026 s,
1027 r: (original_width, original_height),
1028 kind: ArrayKind::Cse,
1029 v: fv,
1030 }
1031 } else {
1032 let sv = match value {
1033 Some(node) => array_node_to_spill_value(node),
1034 None => SpillValue::Error(Error::VALUE),
1035 };
1036 let existing_style =
1037 self.workbook.worksheets[sheet as usize].get_style(r, c);
1038 Cell::SpillCell {
1039 s: existing_style,
1040 a: (row, column),
1041 v: sv,
1042 }
1043 };
1044 *self.workbook.worksheets[sheet as usize]
1045 .sheet_data
1046 .get_mut(&r)
1047 .ok_or("expected a row")?
1048 .get_mut(&c)
1049 .ok_or("expected a column")? = new_cell;
1050 }
1051 }
1052 return Ok(());
1054 }
1055 None => {
1056 let coerced = if array_width == 1 && array_height == 1 {
1065 match self.get_value_from_array(array, 1, 1) {
1066 Some(node) => array_node_to_formula_value(node),
1067 None => FormulaValue::Error {
1068 ei: Error::VALUE,
1069 o: "".to_string(),
1070 m: "Unexpected array result".to_string(),
1071 },
1072 }
1073 } else {
1074 debug_assert!(
1081 false,
1082 "Larger-than-1x1 array reached scalar-context cell \
1083 (sheet={sheet}, row={row}, column={column}, \
1084 {array_width}x{array_height}); implicit intersection \
1085 was expected to collapse it.",
1086 );
1087 FormulaValue::Error {
1088 ei: Error::VALUE,
1089 o: "".to_string(),
1090 m: "Array result in scalar context".to_string(),
1091 }
1092 };
1093 *self.workbook.worksheets[sheet as usize]
1094 .sheet_data
1095 .get_mut(&row)
1096 .ok_or("expected a row")?
1097 .get_mut(&column)
1098 .ok_or("expected a column")? = Cell::CellFormula {
1099 f: formula,
1100 s,
1101 v: coerced,
1102 };
1103 return Ok(());
1104 }
1105 }
1106 }
1107
1108 let formula_value = match result {
1109 CalcResult::Number(value) => {
1110 if value.is_nan() || value.is_infinite() {
1112 return self.set_cells_with_result(
1114 cell_reference,
1115 cell,
1116 &CalcResult::Error {
1117 error: Error::NUM,
1118 origin: cell_reference,
1119 message: "".to_string(),
1120 },
1121 );
1122 }
1123 FormulaValue::Number(*value)
1124 }
1125 CalcResult::String(value) => FormulaValue::Text(value.clone()),
1126 CalcResult::Boolean(value) => FormulaValue::Boolean(*value),
1127 CalcResult::Error {
1128 error,
1129 origin,
1130 message,
1131 } => {
1132 let o = match self.cell_reference_to_string(origin) {
1133 Ok(s) => s,
1134 Err(_) => "".to_string(),
1135 };
1136 FormulaValue::Error {
1137 ei: error.clone(),
1138 o,
1139 m: message.to_string(),
1140 }
1141 }
1142 CalcResult::Range { .. } => {
1143 debug_assert!(false, "Unexpected range result in non-array formula");
1145 return Err("Cannot set a range as cell value".to_string());
1146 }
1147 CalcResult::EmptyCell | CalcResult::EmptyArg => {
1148 return self.set_cells_with_result(cell_reference, cell, &CalcResult::Number(0.0));
1150 }
1151 CalcResult::Array(_) | CalcResult::Lambda(_) => {
1153 debug_assert!(false, "Unexpected array result in non-array formula");
1154 return Err("Unexpected array result in non-array formula".to_string());
1155 }
1156 };
1157
1158 let new_cell = match original_range {
1159 Some((is_dynamic, (width, height))) => {
1160 let (kind, r) = if is_dynamic {
1161 (ArrayKind::Dynamic, (1, 1))
1162 } else {
1163 (ArrayKind::Cse, (width, height))
1164 };
1165 Cell::ArrayFormula {
1166 f: formula,
1167 s,
1168 r,
1169 kind,
1170 v: formula_value.clone(),
1171 }
1172 }
1173 None => Cell::CellFormula {
1174 f: formula,
1175 s,
1176 v: formula_value.clone(),
1177 },
1178 };
1179
1180 if let Some((false, (width, height))) = original_range {
1182 let spill_value = formula_value_to_spill_value(&formula_value);
1183 let ws = &mut self.workbook.worksheets[sheet as usize];
1184 for r in row..row + height {
1185 for c in column..column + width {
1186 if r == row && c == column {
1187 continue;
1188 }
1189 let existing_style = ws.get_style(r, c);
1190 ws.update_cell(
1191 r,
1192 c,
1193 Cell::SpillCell {
1194 a: (row, column),
1195 s: existing_style,
1196 v: spill_value.clone(),
1197 },
1198 )?;
1199 }
1200 }
1201 }
1202
1203 self.workbook.worksheets[sheet as usize].update_cell(row, column, new_cell)?;
1204 Ok(())
1205 }
1206
1207 pub fn set_sheet_color(&mut self, sheet: u32, color: &Color) -> Result<(), String> {
1222 let worksheet = self.workbook.worksheet_mut(sheet)?;
1223 worksheet.color = color.clone();
1224 Ok(())
1225 }
1226
1227 pub fn set_sheet_state(&mut self, sheet: u32, state: SheetState) -> Result<(), String> {
1229 let worksheet = self.workbook.worksheet_mut(sheet)?;
1230 worksheet.state = state;
1231 Ok(())
1232 }
1233
1234 pub fn set_theme(&mut self, theme: crate::types::Theme) {
1236 self.workbook.theme = theme;
1237 self.evaluate_conditional_formatting();
1238 }
1239
1240 pub fn get_theme(&self) -> Theme {
1242 self.workbook.theme.clone()
1243 }
1244
1245 pub fn set_show_grid_lines(&mut self, sheet: u32, show_grid_lines: bool) -> Result<(), String> {
1247 let worksheet = self.workbook.worksheet_mut(sheet)?;
1248 worksheet.show_grid_lines = show_grid_lines;
1249 Ok(())
1250 }
1251
1252 fn get_cell_value(&self, cell: &Cell, cell_reference: CellReferenceIndex) -> CalcResult {
1254 use Cell::*;
1255 match cell {
1256 EmptyCell { .. } => CalcResult::EmptyCell,
1257 BooleanCell { v, .. } => CalcResult::Boolean(*v),
1258 NumberCell { v, .. } => CalcResult::Number(*v),
1259 ErrorCell { ei, .. } => {
1260 let message = ei.to_localized_error_string(self.language);
1261 CalcResult::new_error(ei.clone(), cell_reference, message)
1262 }
1263 SharedString { si, .. } => {
1264 if let Some(s) = self.workbook.shared_strings.get(*si as usize) {
1265 CalcResult::String(s.clone())
1266 } else {
1267 let message = "Invalid shared string".to_string();
1268 CalcResult::new_error(Error::ERROR, cell_reference, message)
1269 }
1270 }
1271 CellFormula {
1272 v: FormulaValue::Unevaluated,
1273 ..
1274 }
1275 | ArrayFormula {
1276 v: FormulaValue::Unevaluated,
1277 ..
1278 } => CalcResult::Error {
1279 error: Error::ERROR,
1280 origin: cell_reference,
1281 message: "Unevaluated formula".to_string(),
1282 },
1283 CellFormula {
1284 v: FormulaValue::Boolean(v),
1285 ..
1286 }
1287 | ArrayFormula {
1288 v: FormulaValue::Boolean(v),
1289 ..
1290 } => CalcResult::Boolean(*v),
1291 CellFormula {
1292 v: FormulaValue::Number(v),
1293 ..
1294 }
1295 | ArrayFormula {
1296 v: FormulaValue::Number(v),
1297 ..
1298 } => CalcResult::Number(*v),
1299 CellFormula {
1300 v: FormulaValue::Text(v),
1301 ..
1302 }
1303 | ArrayFormula {
1304 v: FormulaValue::Text(v),
1305 ..
1306 } => CalcResult::String(v.clone()),
1307 CellFormula {
1308 v: FormulaValue::Error { ei, o, m },
1309 ..
1310 }
1311 | ArrayFormula {
1312 v: FormulaValue::Error { ei, o, m },
1313 ..
1314 } => {
1315 if let Some(cell_reference) = self.parse_reference(o) {
1316 CalcResult::new_error(ei.clone(), cell_reference, m.clone())
1317 } else {
1318 CalcResult::Error {
1319 error: ei.clone(),
1320 origin: cell_reference,
1321 message: ei.to_localized_error_string(self.language),
1322 }
1323 }
1324 }
1325 SpillCell {
1326 v: SpillValue::Number(v),
1327 ..
1328 } => CalcResult::Number(*v),
1329 SpillCell {
1330 v: SpillValue::Boolean(v),
1331 ..
1332 } => CalcResult::Boolean(*v),
1333 SpillCell {
1334 v: SpillValue::Text(v),
1335 ..
1336 } => CalcResult::String(v.clone()),
1337 SpillCell {
1338 v: SpillValue::Error(ei),
1339 ..
1340 } => {
1341 let message = ei.to_localized_error_string(self.language);
1342 CalcResult::new_error(ei.clone(), cell_reference, message)
1343 }
1344 }
1345 }
1346
1347 pub fn is_empty_cell(&self, sheet: u32, row: i32, column: i32) -> Result<bool, String> {
1362 self.workbook.worksheet(sheet)?.is_empty_cell(row, column)
1363 }
1364
1365 pub(crate) fn evaluate_range(
1367 &mut self,
1368 left: CellReferenceIndex,
1369 right: CellReferenceIndex,
1370 ) -> Vec<Vec<ArrayNode>> {
1371 let mut result = Vec::new();
1372 for r in left.row..=right.row {
1373 let mut row_result = Vec::new();
1374 for c in left.column..=right.column {
1375 let cell_reference = CellReferenceIndex {
1376 sheet: left.sheet,
1377 row: r,
1378 column: c,
1379 };
1380 let value = match self.evaluate_cell(cell_reference) {
1381 CalcResult::Number(n) => ArrayNode::Number(n),
1382 CalcResult::Boolean(b) => ArrayNode::Boolean(b),
1383 CalcResult::String(s) => ArrayNode::String(s),
1384 CalcResult::Error { error, .. } => ArrayNode::Error(error),
1385 CalcResult::EmptyCell | CalcResult::EmptyArg => ArrayNode::Empty,
1386 CalcResult::Range { .. } | CalcResult::Array(_) | CalcResult::Lambda(_) => {
1387 debug_assert!(false, "Unexpected array result in non-array formula");
1389 ArrayNode::Error(Error::NIMPL)
1390 }
1391 };
1392 row_result.push(value);
1393 }
1394 result.push(row_result);
1395 }
1396 result
1397 }
1398
1399 #[inline(always)]
1400 fn fetch_cell(&self, cell_reference: CellReferenceIndex) -> Option<&Cell> {
1401 self.workbook.worksheets[cell_reference.sheet as usize]
1402 .sheet_data
1403 .get(&cell_reference.row)?
1404 .get(&cell_reference.column)
1405 }
1406
1407 pub(crate) fn evaluate_cell(&mut self, cell_reference: CellReferenceIndex) -> CalcResult {
1410 let original_cell = match self.fetch_cell(cell_reference) {
1411 Some(c) => c.clone(),
1412 None => return CalcResult::EmptyCell,
1413 };
1414
1415 if let Cell::SpillCell { a, .. } = original_cell {
1416 let anchor_cell_reference = CellReferenceIndex {
1420 sheet: cell_reference.sheet,
1421 column: a.1,
1422 row: a.0,
1423 };
1424 let _ = self.evaluate_cell(anchor_cell_reference);
1426 let cell = match self.fetch_cell(cell_reference) {
1428 Some(c) => c,
1429 None => return CalcResult::EmptyCell,
1430 };
1431 return self.get_cell_value(cell, cell_reference);
1433 };
1434
1435 match original_cell.get_formula() {
1436 Some(f) => {
1437 let key = (
1438 cell_reference.sheet,
1439 cell_reference.row,
1440 cell_reference.column,
1441 );
1442 if let Some(state) = self.cells.get(&key) {
1443 match state {
1444 CellState::Evaluating => {
1445 return CalcResult::new_error(
1446 Error::CIRC,
1447 cell_reference,
1448 "Circular reference detected".to_string(),
1449 );
1450 }
1451 CellState::Evaluated => {
1452 return self.get_cell_value(&original_cell, cell_reference);
1453 }
1454 }
1455 }
1456 if let Cell::ArrayFormula {
1460 r,
1461 kind: ArrayKind::Dynamic,
1462 ..
1463 } = &original_cell
1464 {
1465 let (width, height) = *r;
1466 let ws = match self.workbook.worksheet_mut(cell_reference.sheet) {
1467 Ok(ws) => ws,
1468 Err(_) => {
1469 return CalcResult::new_error(
1470 Error::ERROR,
1471 cell_reference,
1472 "Invalid sheet".to_string(),
1473 )
1474 }
1475 };
1476 for r in cell_reference.row..cell_reference.row + height {
1477 for c in cell_reference.column..cell_reference.column + width {
1478 if r == cell_reference.row && c == cell_reference.column {
1479 continue;
1480 }
1481 let is_own_spill = ws
1485 .sheet_data
1486 .get(&r)
1487 .and_then(|row_data| row_data.get(&c))
1488 .map(|cell| {
1489 matches!(cell, Cell::SpillCell { a, .. }
1490 if *a == (cell_reference.row, cell_reference.column))
1491 })
1492 .unwrap_or(false);
1493 if is_own_spill {
1494 let _ = ws.cell_clear_contents(r, c);
1495 }
1496 }
1497 }
1498 }
1499 self.cells.insert(key, CellState::Evaluating);
1501 let (node, _static_result) =
1502 &self.parsed_formulas[cell_reference.sheet as usize][f as usize];
1503 let result = self.evaluate_node_in_context(&node.clone(), cell_reference);
1504
1505 let result = if let CalcResult::Range { left, right } = result {
1507 if left.sheet == right.sheet
1508 && left.row == right.row
1509 && left.column == right.column
1510 {
1511 self.evaluate_cell(left)
1513 } else {
1514 let array_height = right.row - left.row + 1;
1515 let array_width = right.column - left.column + 1;
1516 let last_row = cell_reference.row + array_height - 1;
1517 let last_col = cell_reference.column + array_width - 1;
1518 if last_row > LAST_ROW || last_col > LAST_COLUMN {
1519 CalcResult::new_error(
1520 Error::SPILL,
1521 cell_reference,
1522 "Spill would exceed worksheet bounds".to_string(),
1523 )
1524 } else {
1525 let array = self.evaluate_range(left, right);
1526 CalcResult::Array(array)
1527 }
1528 }
1529 } else if matches!(result, CalcResult::Lambda(_)) {
1530 CalcResult::new_error(
1531 Error::CALC,
1532 cell_reference,
1533 "A LAMBDA was returned but not called".to_string(),
1534 )
1535 } else {
1536 result
1537 };
1538
1539 if let Err(e) = self.set_cells_with_result(cell_reference, &original_cell, &result)
1540 {
1541 self.cells.insert(key, CellState::Evaluated);
1542 return CalcResult::new_error(Error::ERROR, cell_reference, e);
1544 };
1545
1546 self.cells.insert(key, CellState::Evaluated);
1548
1549 match result {
1551 CalcResult::Array(a) => {
1552 let is_array_formula = matches!(original_cell, Cell::ArrayFormula { .. });
1563 let array_height = a.len();
1564 let array_width = if array_height > 0 { a[0].len() } else { 0 };
1565 if !is_array_formula && (array_width != 1 || array_height != 1) {
1566 debug_assert!(
1575 false,
1576 "Larger-than-1x1 array reached scalar-context cell \
1577 ({cell_reference:?}, {array_width}x{array_height}); \
1578 implicit intersection was expected to collapse it.",
1579 );
1580 CalcResult::new_error(
1581 Error::VALUE,
1582 cell_reference,
1583 "Array result in scalar context".to_string(),
1584 )
1585 } else if array_height == 0 || array_width == 0 {
1586 CalcResult::new_error(
1587 Error::CALC,
1588 cell_reference,
1589 "Formula produced a zero-size array".to_string(),
1590 )
1591 } else {
1592 match a[0][0] {
1593 ArrayNode::Number(n) => CalcResult::Number(n),
1594 ArrayNode::Boolean(b) => CalcResult::Boolean(b),
1595 ArrayNode::String(ref s) => CalcResult::String(s.clone()),
1596 ArrayNode::Error(ref error) => {
1597 let message = error.to_localized_error_string(self.language);
1598 CalcResult::new_error(error.clone(), cell_reference, message)
1599 }
1600 ArrayNode::Empty => CalcResult::EmptyCell,
1601 }
1602 }
1603 }
1604 _ => result,
1605 }
1606 }
1607 None => self.get_cell_value(&original_cell, cell_reference),
1608 }
1609 }
1610
1611 pub(crate) fn get_sheet_index_by_name(&self, name: &str) -> Option<u32> {
1612 let worksheets = &self.workbook.worksheets;
1613 for (index, worksheet) in worksheets.iter().enumerate() {
1614 if worksheet.get_name().to_uppercase() == name.to_uppercase() {
1615 return Some(index as u32);
1616 }
1617 }
1618 None
1619 }
1620
1621 pub fn from_bytes(s: &[u8], language_id: &'a str) -> Result<Model<'a>, String> {
1643 let workbook: Workbook =
1644 bitcode::decode(s).map_err(|e| format!("Error parsing workbook: {e}"))?;
1645 Model::from_workbook(workbook, language_id)
1646 }
1647
1648 pub fn from_workbook(workbook: Workbook, language_id: &str) -> Result<Model<'_>, String> {
1667 let parsed_formulas = Vec::new();
1668 let worksheets = &workbook.worksheets;
1669
1670 let worksheet_names = worksheets.iter().map(|s| s.get_name()).collect();
1671
1672 let defined_names = workbook.get_defined_names_with_scope();
1673 let cells = HashMap::new();
1684 let locale =
1685 get_locale(&workbook.settings.locale).map_err(|_| "Invalid locale".to_string())?;
1686 let tz = Tz::parse(&workbook.settings.tz)?;
1687
1688 let language = match get_language(language_id) {
1689 Ok(lang) => lang,
1690 Err(_) => return Err("Invalid language".to_string()),
1691 };
1692 let parser = Parser::new(
1693 worksheet_names,
1694 defined_names,
1695 workbook.tables.clone(),
1696 locale,
1697 language,
1698 );
1699 let mut shared_strings = HashMap::new();
1700 for (index, s) in workbook.shared_strings.iter().enumerate() {
1701 shared_strings.insert(s.to_string(), index);
1702 }
1703
1704 let mut model = Model {
1705 workbook,
1706 parsed_formulas,
1707 shared_strings,
1708 parsed_defined_names: HashMap::new(),
1709 parser,
1710 cells,
1711 language,
1712 locale,
1713 tz,
1714 view_id: 0,
1715 variable_stack: HashMap::new(),
1716 last_variable_id: 0,
1717 lambdas: HashMap::new(),
1718 last_lambda_id: 0,
1719 spill_cells: Vec::new(),
1720 support: HashMap::new(),
1721 cf_cache: HashMap::new(),
1722 };
1723
1724 model.parse_formulas();
1725 model.parse_defined_names();
1726 model.evaluate_conditional_formatting();
1727
1728 Ok(model)
1729 }
1730
1731 pub fn parse_reference(&self, s: &str) -> Option<CellReferenceIndex> {
1747 let bytes = s.as_bytes();
1748 let mut sheet_name = "".to_string();
1749 let mut column = "".to_string();
1750 let mut row = "".to_string();
1751 let mut state = "sheet"; for &byte in bytes {
1753 match state {
1754 "sheet" => {
1755 if byte == b'!' {
1756 state = "col"
1757 } else {
1758 sheet_name.push(byte as char);
1759 }
1760 }
1761 "col" => {
1762 if byte.is_ascii_alphabetic() {
1763 column.push(byte as char);
1764 } else {
1765 state = "row";
1766 row.push(byte as char);
1767 }
1768 }
1769 _ => {
1770 row.push(byte as char);
1771 }
1772 }
1773 }
1774 let sheet = self.get_sheet_index_by_name(&sheet_name)?;
1775 let row = match row.parse::<i32>() {
1776 Ok(r) => r,
1777 Err(_) => return None,
1778 };
1779 if !(1..=constants::LAST_ROW).contains(&row) {
1780 return None;
1781 }
1782
1783 let column = match utils::column_to_number(&column) {
1784 Ok(column) => {
1785 if is_valid_column_number(column) {
1786 column
1787 } else {
1788 return None;
1789 }
1790 }
1791 Err(_) => return None,
1792 };
1793
1794 Some(CellReferenceIndex { sheet, row, column })
1795 }
1796
1797 pub fn move_cell_value_to_area(
1819 &mut self,
1820 value: &str,
1821 source: &CellReferenceIndex,
1822 target: &CellReferenceIndex,
1823 area: &Area,
1824 ) -> Result<String, String> {
1825 let source_sheet_name = self
1826 .workbook
1827 .worksheet(source.sheet)
1828 .map_err(|e| format!("Could not find source worksheet: {e}"))?
1829 .get_name();
1830 if source.sheet != area.sheet {
1831 return Err("Source and area are in different sheets".to_string());
1832 }
1833 if source.row < area.row || source.row >= area.row + area.height {
1834 return Err("Source is outside the area".to_string());
1835 }
1836 if source.column < area.column || source.column >= area.column + area.width {
1837 return Err("Source is outside the area".to_string());
1838 }
1839 let target_sheet_name = self
1840 .workbook
1841 .worksheet(target.sheet)
1842 .map_err(|e| format!("Could not find target worksheet: {e}"))?
1843 .get_name();
1844 if let Some(formula) = self.formula_without_prefix(value) {
1845 let cell_reference = CellReferenceRC {
1846 sheet: source_sheet_name.to_owned(),
1847 row: source.row,
1848 column: source.column,
1849 };
1850 let formula_str = move_formula(
1851 &self.parser.parse(formula, &cell_reference),
1852 &MoveContext {
1853 source_sheet_name: &source_sheet_name,
1854 row: source.row,
1855 column: source.column,
1856 area,
1857 target_sheet_name: &target_sheet_name,
1858 row_delta: target.row - source.row,
1859 column_delta: target.column - source.column,
1860 },
1861 self.locale,
1862 self.language,
1863 );
1864 Ok(format!("={formula_str}"))
1865 } else {
1866 Ok(value.to_string())
1867 }
1868 }
1869
1870 pub fn extend_to(
1891 &self,
1892 sheet: u32,
1893 row: i32,
1894 column: i32,
1895 target_row: i32,
1896 target_column: i32,
1897 ) -> Result<String, String> {
1898 let cell = self.workbook.worksheet(sheet)?.cell(row, column);
1899 let result = match cell {
1900 Some(cell) => match cell.get_formula() {
1901 None => cell.get_localized_text(
1902 &self.workbook.shared_strings,
1903 self.locale,
1904 self.language,
1905 ),
1906 Some(i) => {
1907 let (formula, _static_result) =
1908 &self.parsed_formulas[sheet as usize][i as usize];
1909 let cell_ref = CellReferenceRC {
1910 sheet: self.workbook.worksheets[sheet as usize].get_name(),
1911 row: target_row,
1912 column: target_column,
1913 };
1914 format!(
1915 "={}",
1916 to_localized_string(formula, &cell_ref, self.locale, self.language)
1917 )
1918 }
1919 },
1920 None => "".to_string(),
1921 };
1922 Ok(result)
1923 }
1924
1925 pub fn extend_copied_value(
1946 &mut self,
1947 value: &str,
1948 source: &CellReferenceIndex,
1949 target: &CellReferenceIndex,
1950 ) -> Result<String, String> {
1951 let source_sheet_name = match self.workbook.worksheets.get(source.sheet as usize) {
1952 Some(ws) => ws.get_name(),
1953 None => {
1954 return Err("Invalid worksheet index".to_owned());
1955 }
1956 };
1957 let target_sheet_name = match self.workbook.worksheets.get(target.sheet as usize) {
1958 Some(ws) => ws.get_name(),
1959 None => {
1960 return Err("Invalid worksheet index".to_owned());
1961 }
1962 };
1963
1964 if let Some(formula_str) = self.formula_without_prefix(value) {
1965 let cell_reference = CellReferenceRC {
1966 sheet: source_sheet_name.to_string(),
1967 row: source.row,
1968 column: source.column,
1969 };
1970 let formula = &self.parser.parse(formula_str, &cell_reference);
1971 let cell_reference = CellReferenceRC {
1972 sheet: target_sheet_name,
1973 row: target.row,
1974 column: target.column,
1975 };
1976 return Ok(format!(
1977 "={}",
1978 to_localized_string(formula, &cell_reference, self.locale, self.language)
1979 ));
1980 }
1981 Ok(value.to_string())
1982 }
1983
1984 pub fn get_cell_formula(
2004 &self,
2005 sheet: u32,
2006 row: i32,
2007 column: i32,
2008 ) -> Result<Option<String>, String> {
2009 let worksheet = self.workbook.worksheet(sheet)?;
2010 match worksheet.cell(row, column) {
2011 Some(cell) => match cell.get_formula() {
2012 Some(formula_index) => {
2013 let (formula, _static_result) = &self
2014 .parsed_formulas
2015 .get(sheet as usize)
2016 .ok_or("missing sheet")?
2017 .get(formula_index as usize)
2018 .ok_or("missing formula")?;
2019 let cell_ref = CellReferenceRC {
2020 sheet: worksheet.get_name(),
2021 row,
2022 column,
2023 };
2024 Ok(Some(format!(
2025 "={}",
2026 to_localized_string(formula, &cell_ref, self.locale, self.language)
2027 )))
2028 }
2029 None => Ok(None),
2030 },
2031 None => Ok(None),
2032 }
2033 }
2034
2035 pub(crate) fn get_english_cell_formula(
2040 &self,
2041 sheet: u32,
2042 row: i32,
2043 column: i32,
2044 ) -> Result<Option<String>, String> {
2045 let worksheet = self.workbook.worksheet(sheet)?;
2046 match worksheet.cell(row, column) {
2047 Some(cell) => match cell.get_formula() {
2048 Some(formula_index) => {
2049 let (formula, _static_result) = &self
2050 .parsed_formulas
2051 .get(sheet as usize)
2052 .ok_or("missing sheet")?
2053 .get(formula_index as usize)
2054 .ok_or("missing formula")?;
2055 let cell_ref = CellReferenceRC {
2056 sheet: worksheet.get_name(),
2057 row,
2058 column,
2059 };
2060 let language_en = get_default_language();
2061 Ok(Some(format!(
2062 "={}",
2063 to_localized_string(formula, &cell_ref, self.locale, language_en)
2064 )))
2065 }
2066 None => Ok(None),
2067 },
2068 None => Ok(None),
2069 }
2070 }
2071
2072 pub fn update_cell_with_text(
2097 &mut self,
2098 sheet: u32,
2099 row: i32,
2100 column: i32,
2101 value: &str,
2102 ) -> Result<(), String> {
2103 let style_index = self.get_cell_style_index(sheet, row, column)?;
2104 let new_style_index;
2105 if common::value_needs_quoting(value, self.language) {
2106 new_style_index = self
2107 .workbook
2108 .styles
2109 .get_style_with_quote_prefix(style_index)?;
2110 } else if self.workbook.styles.style_is_quote_prefix(style_index) {
2111 new_style_index = self
2112 .workbook
2113 .styles
2114 .get_style_without_quote_prefix(style_index)?;
2115 } else {
2116 new_style_index = style_index;
2117 }
2118
2119 self.set_cell_with_string(sheet, row, column, value, new_style_index)
2120 }
2121
2122 pub fn update_cell_with_bool(
2147 &mut self,
2148 sheet: u32,
2149 row: i32,
2150 column: i32,
2151 value: bool,
2152 ) -> Result<(), String> {
2153 let style_index = self.get_cell_style_index(sheet, row, column)?;
2154 let new_style_index = if self.workbook.styles.style_is_quote_prefix(style_index) {
2155 self.workbook
2156 .styles
2157 .get_style_without_quote_prefix(style_index)?
2158 } else {
2159 style_index
2160 };
2161 self.set_cell_with_boolean(sheet, row, column, value, new_style_index)
2162 }
2163
2164 pub fn update_cell_with_number(
2189 &mut self,
2190 sheet: u32,
2191 row: i32,
2192 column: i32,
2193 value: f64,
2194 ) -> Result<(), String> {
2195 let style_index = self.get_cell_style_index(sheet, row, column)?;
2196 let new_style_index = if self.workbook.styles.style_is_quote_prefix(style_index) {
2197 self.workbook
2198 .styles
2199 .get_style_without_quote_prefix(style_index)?
2200 } else {
2201 style_index
2202 };
2203 self.set_cell_with_number(sheet, row, column, value, new_style_index)
2204 }
2205
2206 pub fn update_cell_with_formula(
2234 &mut self,
2235 sheet: u32,
2236 row: i32,
2237 column: i32,
2238 formula: String,
2239 ) -> Result<(), String> {
2240 let mut style_index = self.get_cell_style_index(sheet, row, column)?;
2241 if self.workbook.styles.style_is_quote_prefix(style_index) {
2242 style_index = self
2243 .workbook
2244 .styles
2245 .get_style_without_quote_prefix(style_index)?;
2246 }
2247
2248 if let Some(new_formula) = self.formula_without_prefix(&formula) {
2249 self.set_cell_with_formula(sheet, row, column, new_formula, style_index)?;
2250 Ok(())
2251 } else {
2252 Err(format!("\"{formula}\" is not a valid formula"))
2253 }
2254 }
2255
2256 fn prepare_cell_for_user_input(
2264 &mut self,
2265 sheet: u32,
2266 row: i32,
2267 column: i32,
2268 ) -> Result<(), String> {
2269 match self.get_cell_structure(sheet, row, column)? {
2270 CellStructure::SingleCell => {
2271 }
2273 CellStructure::ArrayFormula { range } => {
2274 let (width, height) = range;
2276 if width > 1 || height > 1 {
2277 return Err(
2278 "Cannot write in a cell that is part of an array formula".to_string()
2279 );
2280 }
2281 }
2282 CellStructure::DynamicFormula { range } => {
2283 let (width, height) = range;
2285 let ws = self.workbook.worksheet_mut(sheet)?;
2286 for r in row..row + height {
2287 for c in column..column + width {
2288 let _ = ws.cell_clear_contents(r, c);
2290 }
2291 }
2292 }
2293 CellStructure::SpillArray { .. } => {
2294 return Err("Cannot write in a cell that is part of an array formula".to_string());
2295 }
2296 CellStructure::SpillDynamic { anchor, range } => {
2297 let (anchor_row, anchor_column) = anchor;
2301 let (width, height) = range;
2302 let ws = self.workbook.worksheet_mut(sheet)?;
2303 let (formula_index, anchor_style) = {
2305 let anchor_cell = ws
2306 .cell(anchor_row, anchor_column)
2307 .ok_or_else(|| "Dynamic formula anchor not found".to_string())?;
2308 let fi = anchor_cell
2309 .get_formula()
2310 .ok_or_else(|| "Dynamic formula anchor has no formula".to_string())?;
2311 let s = anchor_cell.get_style();
2312 (fi, s)
2313 };
2314 ws.set_cell_with_dynamic_formula(
2315 anchor_row,
2316 anchor_column,
2317 formula_index,
2318 anchor_style,
2319 1,
2320 1,
2321 )?;
2322 for r in anchor_row..anchor_row + height {
2323 for c in anchor_column..anchor_column + width {
2324 if r == anchor_row && c == anchor_column {
2325 continue;
2326 }
2327 let _ = ws.cell_clear_contents(r, c);
2329 }
2330 }
2331 }
2332 };
2333 Ok(())
2334 }
2335
2336 pub fn set_user_input(
2368 &mut self,
2369 sheet: u32,
2370 row: i32,
2371 column: i32,
2372 value: String,
2373 ) -> Result<(), String> {
2374 self.prepare_cell_for_user_input(sheet, row, column)?;
2376 if value.is_empty() {
2377 let ws = self.workbook.worksheet_mut(sheet)?;
2379 ws.cell_clear_contents(row, column)?;
2380 return Ok(());
2381 }
2382
2383 let style_index = self.get_cell_style_index(sheet, row, column)?;
2385 if let Some(new_value) = value.strip_prefix('\'') {
2386 let new_style = self
2387 .workbook
2388 .styles
2389 .get_style_with_quote_prefix(style_index)?;
2390 self.set_cell_with_string(sheet, row, column, new_value, new_style)?;
2391 } else {
2392 let mut new_style_index = style_index;
2393 if self.workbook.styles.style_is_quote_prefix(style_index) {
2394 new_style_index = self
2395 .workbook
2396 .styles
2397 .get_style_without_quote_prefix(style_index)?;
2398 }
2399 if let Some(formula) = self.formula_without_prefix(&value) {
2400 let formula_index =
2401 self.set_cell_with_formula(sheet, row, column, formula, new_style_index)?;
2402 let cell = CellReferenceIndex { sheet, row, column };
2404 let (parsed_formula, _static_result) =
2405 &self.parsed_formulas[sheet as usize][formula_index as usize];
2406 if let Some(units) = self.compute_node_units(parsed_formula, &cell) {
2407 let new_style_index = self
2408 .workbook
2409 .styles
2410 .get_style_with_format(new_style_index, &units.get_num_fmt())?;
2411 let style = self.workbook.styles.get_style(new_style_index)?;
2412 self.set_cell_style(sheet, row, column, &style)?;
2413 }
2414 } else {
2415 let mut currencies = vec!["$", "€"];
2417 let currency = &self.locale.currency.symbol;
2418 if !currencies.iter().any(|e| e == currency) {
2419 currencies.push(currency);
2420 }
2421
2422 if let Ok((v, number_format)) =
2424 parse_formatted_number(&value, ¤cies, self.locale)
2425 {
2426 if let Some(num_fmt) = number_format {
2427 let should_apply_format = !(is_likely_date_number_format(
2430 &self.workbook.styles.get_style(new_style_index)?.num_fmt,
2431 ) && is_likely_date_number_format(&num_fmt));
2432 if should_apply_format {
2433 new_style_index = self
2434 .workbook
2435 .styles
2436 .get_style_with_format(new_style_index, &num_fmt)?;
2437 }
2438 }
2439 let worksheet = self.workbook.worksheet_mut(sheet)?;
2440 worksheet.set_cell_with_number(row, column, v, new_style_index)?;
2441 return Ok(());
2442 }
2443 if let Ok(v) = value.to_lowercase().parse::<bool>() {
2445 let worksheet = self.workbook.worksheet_mut(sheet)?;
2446 worksheet.set_cell_with_boolean(row, column, v, new_style_index)?;
2447 return Ok(());
2448 }
2449 let upper = value.to_uppercase();
2451 let worksheet = self.workbook.worksheet_mut(sheet)?;
2452 match get_error_by_name(&upper, self.language) {
2453 Some(error) => {
2454 worksheet.set_cell_with_error(row, column, error, new_style_index)?;
2455 }
2456 None => {
2457 self.set_cell_with_string(sheet, row, column, &value, new_style_index)?;
2458 }
2459 }
2460 }
2461 }
2462 Ok(())
2463 }
2464
2465 pub fn set_user_array_formula(
2467 &mut self,
2468 sheet: u32,
2469 row: i32,
2470 column: i32,
2471 width: i32,
2472 height: i32,
2473 value: &str,
2474 ) -> Result<(), String> {
2475 self.prepare_cell_for_user_input(sheet, row, column)?;
2476 let style_index = self.get_cell_style_index(sheet, row, column)?;
2478 if value.strip_prefix('\'').is_none() {
2479 let mut new_style_index = style_index;
2480 if self.workbook.styles.style_is_quote_prefix(style_index) {
2481 new_style_index = self
2482 .workbook
2483 .styles
2484 .get_style_without_quote_prefix(style_index)?;
2485 }
2486 if let Some(formula) = value.strip_prefix('=') {
2487 let formula_index = self.set_cell_with_array_formula(
2489 sheet,
2490 row,
2491 column,
2492 formula,
2493 new_style_index,
2494 width,
2495 height,
2496 )?;
2497
2498 let cell = CellReferenceIndex { sheet, row, column };
2500 let (parsed_formula, _static_result) =
2501 &self.parsed_formulas[sheet as usize][formula_index as usize];
2502
2503 if let Some(units) = self.compute_node_units(parsed_formula, &cell) {
2504 let new_style_index = self
2505 .workbook
2506 .styles
2507 .get_style_with_format(new_style_index, &units.get_num_fmt())?;
2508 let style = self.workbook.styles.get_style(new_style_index)?;
2509 self.set_cell_style(sheet, row, column, &style)?;
2510 }
2511 for r in row..row + height {
2513 for c in column..column + width {
2514 if r == row && c == column {
2515 continue;
2516 }
2517 let mut new_style_index_spill = self.get_cell_style_index(sheet, r, c)?;
2518 if self
2519 .workbook
2520 .styles
2521 .style_is_quote_prefix(new_style_index_spill)
2522 {
2523 new_style_index_spill = self
2524 .workbook
2525 .styles
2526 .get_style_without_quote_prefix(new_style_index_spill)?;
2527 }
2528
2529 self.set_cell_with_string(sheet, r, c, "", new_style_index_spill)?;
2530 }
2531 }
2532 return Ok(());
2533 }
2534 }
2535 for r in row..row + height {
2537 for c in column..column + width {
2538 self.set_user_input(sheet, r, c, value.to_string())?;
2539 }
2540 }
2541
2542 Ok(())
2543 }
2544
2545 pub(crate) fn get_cell_structure(
2546 &self,
2547 sheet: u32,
2548 row: i32,
2549 column: i32,
2550 ) -> Result<CellStructure, String> {
2551 let worksheet = self.workbook.worksheet(sheet)?;
2552 worksheet.get_cell_structure(row, column)
2553 }
2554
2555 fn set_cell_with_formula(
2556 &mut self,
2557 sheet: u32,
2558 row: i32,
2559 column: i32,
2560 formula: &str,
2561 style: i32,
2562 ) -> Result<i32, String> {
2563 let worksheet = self.workbook.worksheet_mut(sheet)?;
2564 let cell_reference = CellReferenceRC {
2565 sheet: worksheet.get_name(),
2566 row,
2567 column,
2568 };
2569 let shared_formulas = &mut worksheet.shared_formulas;
2570 let mut parsed_formula = self.parser.parse(formula, &cell_reference);
2571 if let Node::ParseErrorKind { .. } = parsed_formula {
2574 let new_parsed_formula = self.parser.parse(&format!("{formula})"), &cell_reference);
2575 match new_parsed_formula {
2576 Node::ParseErrorKind { .. } => {}
2577 _ => parsed_formula = new_parsed_formula,
2578 }
2579 }
2580 let static_result = run_static_analysis_on_node(&parsed_formula);
2581 let is_dynamic = !matches!(static_result, StaticResult::Scalar);
2582
2583 let s = to_rc_format(&parsed_formula);
2584 let mut formula_index: i32 = -1;
2585 if let Some(index) = shared_formulas.iter().position(|x| x == &s) {
2586 formula_index = index as i32;
2587 }
2588 if formula_index == -1 {
2589 shared_formulas.push(s);
2590 self.parsed_formulas[sheet as usize].push((parsed_formula, static_result));
2591 formula_index = (shared_formulas.len() as i32) - 1;
2592 }
2593 if is_dynamic {
2594 worksheet.set_cell_with_dynamic_formula(row, column, formula_index, style, 1, 1)?;
2595 } else {
2596 worksheet.set_cell_with_formula(row, column, formula_index, style)?;
2597 }
2598 Ok(formula_index)
2599 }
2600
2601 #[allow(clippy::too_many_arguments)]
2603 pub(crate) fn set_cell_with_array_formula(
2604 &mut self,
2605 sheet: u32,
2606 row: i32,
2607 column: i32,
2608 formula: &str,
2609 style: i32,
2610 width: i32,
2611 height: i32,
2612 ) -> Result<i32, String> {
2613 let worksheet = self.workbook.worksheet_mut(sheet)?;
2614 let cell_reference = CellReferenceRC {
2615 sheet: worksheet.get_name(),
2616 row,
2617 column,
2618 };
2619 let shared_formulas = &mut worksheet.shared_formulas;
2620 let mut parsed_formula = self.parser.parse(formula, &cell_reference);
2621 if let Node::ParseErrorKind { .. } = parsed_formula {
2624 let new_parsed_formula = self.parser.parse(&format!("{formula})"), &cell_reference);
2625 match new_parsed_formula {
2626 Node::ParseErrorKind { .. } => {}
2627 _ => parsed_formula = new_parsed_formula,
2628 }
2629 }
2630 let static_result = run_static_analysis_on_node(&parsed_formula);
2631
2632 let s = to_rc_format(&parsed_formula);
2633 let mut formula_index: i32 = -1;
2634 if let Some(index) = shared_formulas.iter().position(|x| x == &s) {
2635 formula_index = index as i32;
2636 }
2637 if formula_index == -1 {
2638 shared_formulas.push(s);
2639 self.parsed_formulas[sheet as usize].push((parsed_formula, static_result));
2640 formula_index = (shared_formulas.len() as i32) - 1;
2641 }
2642 worksheet.set_cell_with_array_formula(row, column, formula_index, style, width, height)?;
2643 Ok(formula_index)
2644 }
2645
2646 pub(crate) fn set_cell_with_string(
2647 &mut self,
2648 sheet: u32,
2649 row: i32,
2650 column: i32,
2651 value: &str,
2652 style: i32,
2653 ) -> Result<(), String> {
2654 match self.shared_strings.get(value) {
2655 Some(string_index) => {
2656 self.workbook.worksheet_mut(sheet)?.set_cell_with_string(
2657 row,
2658 column,
2659 *string_index as i32,
2660 style,
2661 )?;
2662 }
2663 None => {
2664 let string_index = self.workbook.shared_strings.len();
2665 self.workbook.shared_strings.push(value.to_string());
2666 self.shared_strings.insert(value.to_string(), string_index);
2667 self.workbook.worksheet_mut(sheet)?.set_cell_with_string(
2668 row,
2669 column,
2670 string_index as i32,
2671 style,
2672 )?;
2673 }
2674 }
2675 Ok(())
2676 }
2677
2678 fn set_cell_with_boolean(
2679 &mut self,
2680 sheet: u32,
2681 row: i32,
2682 column: i32,
2683 value: bool,
2684 style: i32,
2685 ) -> Result<(), String> {
2686 self.workbook
2687 .worksheet_mut(sheet)?
2688 .set_cell_with_boolean(row, column, value, style)
2689 }
2690
2691 fn set_cell_with_number(
2692 &mut self,
2693 sheet: u32,
2694 row: i32,
2695 column: i32,
2696 value: f64,
2697 style: i32,
2698 ) -> Result<(), String> {
2699 self.workbook
2700 .worksheet_mut(sheet)?
2701 .set_cell_with_number(row, column, value, style)
2702 }
2703
2704 fn get_parsed_defined_name(
2706 &self,
2707 name: &str,
2708 scope: Option<u32>,
2709 ) -> Result<Option<ParsedDefinedName>, String> {
2710 let name_upper = name.to_uppercase();
2711
2712 for (key, df) in &self.parsed_defined_names {
2713 if key.1.to_uppercase() == name_upper && key.0 == scope {
2714 return Ok(Some(df.clone()));
2715 }
2716 }
2717 Ok(None)
2718 }
2719
2720 pub(crate) fn get_defined_name_formula(
2722 &self,
2723 name: &str,
2724 scope: Option<u32>,
2725 ) -> Result<String, String> {
2726 let name_upper = name.to_uppercase();
2727 let defined_names = &self.workbook.defined_names;
2728 let sheet_id = match scope {
2729 Some(index) => Some(self.workbook.worksheet(index)?.sheet_id),
2730 None => None,
2731 };
2732 for df in defined_names {
2733 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
2734 return Ok(df.formula.clone());
2735 }
2736 }
2737 Err("Defined name not found".to_string())
2738 }
2739
2740 pub fn get_defined_name_list(&self) -> Vec<(String, Option<u32>, String)> {
2745 let context = self.defined_name_context();
2746 self.workbook
2747 .get_defined_names_with_scope()
2748 .into_iter()
2749 .map(|(name, scope, formula)| {
2750 let formula = self.internal_formula_to_display(&formula, &context);
2751 (name, scope, formula)
2752 })
2753 .collect()
2754 }
2755
2756 pub fn get_cell_value_by_ref(&self, cell_ref: &str) -> Result<CellValue, String> {
2761 let cell_reference = match self.parse_reference(cell_ref) {
2762 Some(c) => c,
2763 None => return Err(format!("Error parsing reference: '{cell_ref}'")),
2764 };
2765 let sheet_index = cell_reference.sheet;
2766 let column = cell_reference.column;
2767 let row = cell_reference.row;
2768
2769 self.get_cell_value_by_index(sheet_index, row, column)
2770 }
2771
2772 pub fn get_cell_value_by_index(
2777 &self,
2778 sheet_index: u32,
2779 row: i32,
2780 column: i32,
2781 ) -> Result<CellValue, String> {
2782 let cell = self
2783 .workbook
2784 .worksheet(sheet_index)?
2785 .cell(row, column)
2786 .cloned()
2787 .unwrap_or_default();
2788 let cell_value = cell.value(&self.workbook.shared_strings, self.language);
2789 Ok(cell_value)
2790 }
2791
2792 pub fn get_formatted_cell_value(
2813 &self,
2814 sheet_index: u32,
2815 row: i32,
2816 column: i32,
2817 ) -> Result<String, String> {
2818 match self.workbook.worksheet(sheet_index)?.cell(row, column) {
2819 Some(cell) => {
2820 let format = self.get_style_for_cell(sheet_index, row, column)?.num_fmt;
2821 let formatted_value =
2822 cell.formatted_value(&self.workbook.shared_strings, self.language, |value| {
2823 format_number(value, &format, self.locale).text
2824 });
2825 Ok(formatted_value)
2826 }
2827 None => Ok("".to_string()),
2828 }
2829 }
2830
2831 pub fn get_cell_type(&self, sheet: u32, row: i32, column: i32) -> Result<CellType, String> {
2833 Ok(match self.workbook.worksheet(sheet)?.cell(row, column) {
2834 Some(c) => c.get_type(),
2835 None => CellType::Number,
2836 })
2837 }
2838
2839 pub fn get_localized_cell_content(
2846 &self,
2847 sheet: u32,
2848 row: i32,
2849 column: i32,
2850 ) -> Result<String, String> {
2851 let worksheet = self.workbook.worksheet(sheet)?;
2852 let cell = match worksheet.cell(row, column) {
2853 Some(c) => c,
2854 None => return Ok("".to_string()),
2855 };
2856 match cell.get_formula() {
2857 Some(formula_index) => {
2858 let formula = &self.parsed_formulas[sheet as usize][formula_index as usize].0;
2859 let cell_ref = CellReferenceRC {
2860 sheet: worksheet.get_name(),
2861 row,
2862 column,
2863 };
2864 Ok(format!(
2865 "={}",
2866 to_localized_string(formula, &cell_ref, self.locale, self.language)
2867 ))
2868 }
2869 None => {
2870 let style_index = cell.get_style();
2871 let style = self.workbook.styles.get_style(style_index)?;
2872 if style.quote_prefix {
2873 Ok(format!(
2874 "'{}",
2875 cell.get_localized_text(
2876 &self.workbook.shared_strings,
2877 self.locale,
2878 self.language,
2879 )
2880 ))
2881 } else {
2882 if is_likely_date_number_format(&style.num_fmt) {
2884 let value = cell.value(&self.workbook.shared_strings, self.language);
2885 if let CellValue::Number(n) = value {
2886 let formatted = format_number(n, &style.num_fmt, self.locale);
2887 if formatted.error.is_none() {
2888 return Ok(formatted.text);
2889 }
2890 }
2891 }
2892 Ok(cell.get_localized_text(
2893 &self.workbook.shared_strings,
2894 self.locale,
2895 self.language,
2896 ))
2897 }
2898 }
2899 }
2900 }
2901
2902 pub fn get_all_cells(&self) -> Vec<CellIndex> {
2904 let mut cells = Vec::new();
2905 for (index, sheet) in self.workbook.worksheets.iter().enumerate() {
2906 let mut sorted_rows: Vec<_> = sheet.sheet_data.keys().collect();
2907 sorted_rows.sort_unstable();
2908 for row in sorted_rows {
2909 let row_data = &sheet.sheet_data[row];
2910 let mut sorted_columns: Vec<_> = row_data.keys().collect();
2911 sorted_columns.sort_unstable();
2912 for column in sorted_columns {
2913 cells.push(CellIndex {
2914 index: index as u32,
2915 row: *row,
2916 column: *column,
2917 });
2918 }
2919 }
2920 }
2921 cells
2922 }
2923
2924 fn collect_spill_cells(&mut self) {
2927 let mut spill_cells = Vec::new();
2928 for (sheet_index, worksheet) in self.workbook.worksheets.iter().enumerate() {
2929 let mut sorted_rows: Vec<i32> = worksheet.sheet_data.keys().copied().collect();
2930 sorted_rows.sort_unstable();
2931 for row in &sorted_rows {
2932 let row_data = &worksheet.sheet_data[row];
2933 let mut sorted_cols: Vec<i32> = row_data.keys().copied().collect();
2934 sorted_cols.sort_unstable();
2935 for col in &sorted_cols {
2936 if matches!(
2937 &row_data[col],
2938 Cell::ArrayFormula {
2939 kind: ArrayKind::Dynamic,
2940 ..
2941 }
2942 ) {
2943 spill_cells.push(CellReferenceIndex {
2944 sheet: sheet_index as u32,
2945 row: *row,
2946 column: *col,
2947 });
2948 }
2949 }
2950 }
2951 }
2952 self.spill_cells = spill_cells;
2953 }
2954
2955 fn get_spill_area(&self, cell_ref: CellReferenceIndex) -> Vec<CellReferenceIndex> {
2958 let ws = match self.workbook.worksheet(cell_ref.sheet) {
2959 Ok(ws) => ws,
2960 Err(_) => return Vec::new(),
2961 };
2962 let (width, height) = match ws.cell(cell_ref.row, cell_ref.column) {
2963 Some(Cell::ArrayFormula {
2964 r,
2965 kind: ArrayKind::Dynamic,
2966 ..
2967 }) => *r,
2968 _ => return Vec::new(),
2969 };
2970 (cell_ref.row..cell_ref.row + height)
2971 .flat_map(|r| {
2972 (cell_ref.column..cell_ref.column + width).map(move |c| CellReferenceIndex {
2973 sheet: cell_ref.sheet,
2974 row: r,
2975 column: c,
2976 })
2977 })
2978 .collect()
2979 }
2980
2981 fn position_in_support(
2983 &self,
2984 cell: CellReferenceIndex,
2985 positions: &[CellReferenceIndex],
2986 ) -> bool {
2987 let deps = match self.support.get(&cell) {
2988 Some(d) => d,
2989 None => return false,
2990 };
2991 for dep in deps {
2992 match *dep {
2993 CellOrRange::Cell((sheet, row, col)) => {
2994 if positions
2995 .iter()
2996 .any(|p| p.sheet == sheet && p.row == row && p.column == col)
2997 {
2998 return true;
2999 }
3000 }
3001 CellOrRange::Range((sheet, r1, c1, r2, c2)) => {
3002 if positions.iter().any(|p| {
3003 p.sheet == sheet
3004 && p.row >= r1
3005 && p.row <= r2
3006 && p.column >= c1
3007 && p.column <= c2
3008 }) {
3009 return true;
3010 }
3011 }
3012 }
3013 }
3014 false
3015 }
3016
3017 pub fn evaluate(&mut self) {
3028 self.collect_spill_cells();
3029
3030 let n = self.spill_cells.len();
3031 let max_restarts = n * n + 1;
3033 let mut retry = true;
3034 let mut restart_count = 0;
3035
3036 while retry && restart_count < max_restarts {
3037 retry = false;
3038 self.cells.clear();
3039 self.support.clear();
3040 self.clear_variable_stack();
3041 self.clear_lambdas();
3042
3043 for i in 0..self.spill_cells.len() {
3045 let spill_cell = self.spill_cells[i];
3046 self.evaluate_cell(spill_cell);
3047
3048 let spill_area = self.get_spill_area(spill_cell);
3050
3051 for j in 0..i {
3054 let prev = self.spill_cells[j];
3055 if self.position_in_support(prev, &spill_area) {
3056 let moved = self.spill_cells.remove(i);
3057 self.spill_cells.insert(j, moved);
3058 retry = true;
3059 restart_count += 1;
3060 break;
3061 }
3062 }
3063 if retry {
3064 break;
3065 }
3066 }
3067 }
3068
3069 let all_cells = self.get_all_cells();
3072 for cell in all_cells {
3073 self.evaluate_cell(CellReferenceIndex {
3074 sheet: cell.index,
3075 row: cell.row,
3076 column: cell.column,
3077 });
3078 }
3079 self.evaluate_conditional_formatting();
3080 }
3081
3082 pub fn range_clear_contents(&mut self, range: &Area) -> Result<(), String> {
3111 if !self.can_clear_range(range)? {
3112 return Err("Cannot clear the range because it contains array formulas".to_string());
3113 }
3114 let sheet = range.sheet;
3115 let ws = self.workbook.worksheet_mut(sheet)?;
3116 for row in range.row..range.row + range.height {
3117 for column in range.column..range.column + range.width {
3118 let structure = ws.get_cell_structure(row, column)?;
3119 match structure {
3120 CellStructure::DynamicFormula { range }
3121 | CellStructure::ArrayFormula { range, .. } => {
3122 let (width, height) = range;
3123 for r in row..row + height {
3124 for c in column..column + width {
3125 let _ = ws.cell_clear_contents(r, c);
3126 }
3127 }
3128 }
3129 _ => {
3130 let _ = ws.cell_clear_contents(row, column);
3131 }
3132 }
3133 }
3134 }
3135 Ok(())
3136 }
3137
3138 pub(crate) fn can_clear_range(&self, range: &Area) -> Result<bool, String> {
3141 let sheet = range.sheet;
3142 for row in range.row..range.row + range.height {
3143 for column in range.column..range.column + range.width {
3144 match self.get_cell_structure(sheet, row, column)? {
3145 CellStructure::ArrayFormula { range: r } => {
3146 let (width, height) = r;
3147 if column + width > range.column + range.width
3148 || row + height > range.row + range.height
3149 {
3150 return Ok(false);
3151 }
3152 }
3153 CellStructure::SpillArray {
3154 anchor: a,
3155 range: r,
3156 } => {
3157 let (anchor_row, anchor_column) = a;
3158 let (width, height) = r;
3159 if anchor_column < range.column
3160 || anchor_row < range.row
3161 || anchor_column + width > range.column + range.width
3162 || anchor_row + height > range.row + range.height
3163 {
3164 return Ok(false);
3165 }
3166 }
3167 _ => {
3168 }
3170 }
3171 }
3172 }
3173 Ok(true)
3174 }
3175
3176 pub fn range_clear_all(&mut self, area: &Area) -> Result<(), String> {
3206 if !self.can_clear_range(area)? {
3207 return Err("Cannot clear the range because it contains array formulas".to_string());
3208 }
3209 let worksheet = self.workbook.worksheet_mut(area.sheet)?;
3210
3211 let sheet_data = &mut worksheet.sheet_data;
3212 let mut cells_to_clear = Vec::new();
3213 for row in area.row..area.row + area.height {
3214 if let Some(row_data) = sheet_data.get_mut(&row) {
3215 for column in area.column..area.column + area.width {
3216 if let Some(Cell::ArrayFormula {
3218 r,
3219 kind: ArrayKind::Dynamic,
3220 ..
3221 }) = row_data.get(&column)
3222 {
3223 let (width, height) = r;
3225 for r in row..row + height {
3226 for c in column..column + width {
3227 cells_to_clear.push((r, c));
3228 }
3229 }
3230 }
3231 row_data.remove(&column);
3232 }
3233 if row_data.is_empty() {
3234 sheet_data.remove(&row);
3235 };
3236 }
3237 }
3238 for (row, column) in cells_to_clear {
3239 let _ = worksheet.cell_clear_contents(row, column);
3241 }
3242 Ok(())
3243 }
3244
3245 pub(crate) fn reset_dynamic_array_spills(&mut self, sheet: u32) -> Result<(), String> {
3249 let anchors: Vec<(i32, i32, i32, i32, i32, i32)> = {
3251 let ws = self.workbook.worksheet(sheet)?;
3252 let mut result = Vec::new();
3253 for (row, row_data) in &ws.sheet_data {
3254 for (column, cell) in row_data {
3255 if let Cell::ArrayFormula {
3256 r,
3257 f,
3258 s,
3259 kind: ArrayKind::Dynamic,
3260 ..
3261 } = cell
3262 {
3263 let (width, height) = *r;
3264 result.push((*row, *column, *f, *s, width, height));
3265 }
3266 }
3267 }
3268 result
3269 };
3270
3271 for (row, column, f, s, width, height) in anchors {
3272 let ws = self.workbook.worksheet_mut(sheet)?;
3273 if let Some(row_data) = ws.sheet_data.get_mut(&row) {
3275 row_data.insert(
3276 column,
3277 Cell::ArrayFormula {
3278 f,
3279 s,
3280 r: (1, 1),
3281 kind: ArrayKind::Dynamic,
3282 v: FormulaValue::Unevaluated,
3283 },
3284 );
3285 }
3286 for r in row..row + height {
3288 for c in column..column + width {
3289 if r == row && c == column {
3290 continue;
3291 }
3292 let _ = ws.cell_clear_contents(r, c);
3293 }
3294 }
3295 }
3296 Ok(())
3297 }
3298
3299 pub fn get_cell_style_index(&self, sheet: u32, row: i32, column: i32) -> Result<i32, String> {
3301 let cell = self.workbook.worksheet(sheet)?.cell(row, column);
3303
3304 match cell {
3305 Some(cell) => Ok(cell.get_style()),
3306 None => {
3307 let rows = &self.workbook.worksheet(sheet)?.rows;
3308 for r in rows {
3309 if r.r == row {
3310 if r.custom_format {
3311 return Ok(r.s);
3312 }
3313 break;
3314 }
3315 }
3316 let cols = &self.workbook.worksheet(sheet)?.cols;
3317 for c in cols.iter() {
3318 let min = c.min;
3319 let max = c.max;
3320 if column >= min && column <= max {
3321 return Ok(c.style.unwrap_or(0));
3322 }
3323 }
3324 Ok(0)
3325 }
3326 }
3327 }
3328
3329 pub fn get_style_for_cell(&self, sheet: u32, row: i32, column: i32) -> Result<Style, String> {
3332 let style_index = self.get_cell_style_index(sheet, row, column)?;
3333 let style = self.workbook.styles.get_style(style_index)?;
3334 Ok(style)
3335 }
3336
3337 pub fn get_cell_style_or_none(
3339 &self,
3340 sheet: u32,
3341 row: i32,
3342 column: i32,
3343 ) -> Result<Option<Style>, String> {
3344 let style = self
3345 .workbook
3346 .worksheet(sheet)?
3347 .cell(row, column)
3348 .map(|c| self.workbook.styles.get_style(c.get_style()))
3349 .transpose();
3350 style
3351 }
3352
3353 pub fn to_bytes(&self) -> Vec<u8> {
3358 bitcode::encode(&self.workbook)
3359 }
3360
3361 pub fn get_worksheets_properties(&self) -> Vec<SheetProperties> {
3363 self.workbook
3364 .worksheets
3365 .iter()
3366 .map(|worksheet| SheetProperties {
3367 name: worksheet.get_name(),
3368 state: worksheet.state.to_string(),
3369 color: worksheet.color.clone(),
3370 sheet_id: worksheet.sheet_id,
3371 })
3372 .collect()
3373 }
3374
3375 pub fn get_sheet_markup(&self, sheet: u32) -> Result<String, String> {
3377 let worksheet = self.workbook.worksheet(sheet)?;
3378 let dimension = worksheet.dimension();
3379
3380 let mut rows = Vec::new();
3381
3382 for row in 1..(dimension.max_row + 1) {
3383 let mut row_markup: Vec<String> = Vec::new();
3384
3385 for column in 1..(dimension.max_column + 1) {
3386 let mut cell_markup = match self.get_cell_formula(sheet, row, column)? {
3387 Some(formula) => formula,
3388 None => self.get_formatted_cell_value(sheet, row, column)?,
3389 };
3390 let style = self.get_style_for_cell(sheet, row, column)?;
3391 if style.font.b {
3392 cell_markup = format!("**{cell_markup}**")
3393 }
3394 row_markup.push(cell_markup);
3395 }
3396
3397 rows.push(row_markup.join("|"));
3398 }
3399
3400 Ok(rows.join("\n"))
3401 }
3402
3403 pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, String> {
3405 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3406 Ok(worksheet.frozen_rows)
3407 } else {
3408 Err("Invalid sheet".to_string())
3409 }
3410 }
3411
3412 pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, String> {
3414 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3415 Ok(worksheet.frozen_columns)
3416 } else {
3417 Err("Invalid sheet".to_string())
3418 }
3419 }
3420
3421 pub fn set_frozen_rows(&mut self, sheet: u32, frozen_rows: i32) -> Result<(), String> {
3424 if let Some(worksheet) = self.workbook.worksheets.get_mut(sheet as usize) {
3425 if frozen_rows < 0 {
3426 return Err("Frozen rows cannot be negative".to_string());
3427 }
3428 if frozen_rows >= LAST_ROW {
3429 return Err("Too many rows".to_string());
3430 }
3431 worksheet.frozen_rows = frozen_rows;
3432 Ok(())
3433 } else {
3434 Err("Invalid sheet".to_string())
3435 }
3436 }
3437
3438 pub fn set_frozen_columns(&mut self, sheet: u32, frozen_columns: i32) -> Result<(), String> {
3441 if let Some(worksheet) = self.workbook.worksheets.get_mut(sheet as usize) {
3442 if frozen_columns < 0 {
3443 return Err("Frozen columns cannot be negative".to_string());
3444 }
3445 if frozen_columns >= LAST_COLUMN {
3446 return Err("Too many columns".to_string());
3447 }
3448 worksheet.frozen_columns = frozen_columns;
3449 Ok(())
3450 } else {
3451 Err("Invalid sheet".to_string())
3452 }
3453 }
3454
3455 #[inline]
3457 pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, String> {
3458 self.workbook.worksheet(sheet)?.get_column_width(column)
3459 }
3460
3461 #[inline]
3463 pub fn set_column_width(&mut self, sheet: u32, column: i32, width: f64) -> Result<(), String> {
3464 self.workbook
3465 .worksheet_mut(sheet)?
3466 .set_column_width(column, width)
3467 }
3468
3469 #[inline]
3471 pub fn set_column_hidden(
3472 &mut self,
3473 sheet: u32,
3474 column: i32,
3475 hidden: bool,
3476 ) -> Result<(), String> {
3477 self.workbook
3478 .worksheet_mut(sheet)?
3479 .set_column_hidden(column, hidden)
3480 }
3481
3482 #[inline]
3484 pub fn set_row_hidden(&mut self, sheet: u32, row: i32, hidden: bool) -> Result<(), String> {
3485 self.workbook
3486 .worksheet_mut(sheet)?
3487 .set_row_hidden(row, hidden)
3488 }
3489
3490 #[inline]
3492 pub fn is_column_hidden(&self, sheet: u32, column: i32) -> Result<bool, String> {
3493 self.workbook.worksheet(sheet)?.is_column_hidden(column)
3494 }
3495
3496 #[inline]
3498 pub fn is_row_hidden(&self, sheet: u32, row: i32) -> Result<bool, String> {
3499 self.workbook.worksheet(sheet)?.is_row_hidden(row)
3500 }
3501
3502 #[inline]
3504 pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, String> {
3505 self.workbook.worksheet(sheet)?.row_height(row)
3506 }
3507
3508 #[inline]
3510 pub fn set_row_height(&mut self, sheet: u32, column: i32, height: f64) -> Result<(), String> {
3511 self.workbook
3512 .worksheet_mut(sheet)?
3513 .set_row_height(column, height)
3514 }
3515
3516 pub fn new_defined_name(
3519 &mut self,
3520 name: &str,
3521 scope: Option<u32>,
3522 formula: &str,
3523 ) -> Result<(), String> {
3524 let sheet_id = self.is_valid_defined_name(name, scope, formula)?;
3525 let context = self.defined_name_context();
3528 let internal_formula = self.user_formula_to_internal(formula, &context)?;
3529 self.workbook.defined_names.push(DefinedName {
3530 name: name.to_string(),
3531 formula: internal_formula,
3532 sheet_id,
3533 });
3534 self.reset_parsed_structures();
3535
3536 Ok(())
3537 }
3538
3539 pub(crate) fn defined_name_context(&self) -> CellReferenceRC {
3542 CellReferenceRC {
3543 sheet: self
3544 .workbook
3545 .worksheets
3546 .first()
3547 .map(|ws| ws.get_name())
3548 .unwrap_or_else(|| "Sheet1".to_string()),
3549 row: 1,
3550 column: 1,
3551 }
3552 }
3553
3554 pub fn is_valid_defined_name(
3556 &mut self,
3557 name: &str,
3558 scope: Option<u32>,
3559 formula: &str,
3560 ) -> Result<Option<u32>, String> {
3561 if !is_valid_identifier(name) {
3562 return Err("Name: Invalid defined name".to_string());
3563 }
3564 let name_upper = name.to_uppercase();
3565 let defined_names = &self.workbook.defined_names;
3566 let sheet_id = match scope {
3567 Some(index) => match self.workbook.worksheet(index) {
3568 Ok(ws) => Some(ws.sheet_id),
3569 Err(_) => return Err("Scope: Invalid sheet index".to_string()),
3570 },
3571 None => None,
3572 };
3573 for df in defined_names {
3575 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
3576 return Err("Name: Defined name already exists".to_string());
3577 }
3578 }
3579
3580 let is_reference =
3582 common::ParsedReference::parse_reference_formula(None, formula, self.locale, |name| {
3583 self.get_sheet_index_by_name(name)
3584 })
3585 .is_ok();
3586
3587 if !is_reference {
3588 use crate::expressions::types::CellReferenceRC;
3591 let formula_body = formula.strip_prefix('=').unwrap_or(formula);
3592 let dummy_ref = CellReferenceRC {
3593 sheet: self
3594 .workbook
3595 .worksheets
3596 .first()
3597 .map(|ws| ws.get_name())
3598 .unwrap_or_else(|| "Sheet1".to_string()),
3599 row: 1,
3600 column: 1,
3601 };
3602 let mut node = self.parser.parse(formula_body, &dummy_ref);
3606 if let Node::ParseErrorKind { .. } = node {
3607 node = self.parse_internal_formula(formula_body, &dummy_ref);
3608 }
3609 if !matches!(node, Node::LambdaDefKind { .. }) {
3610 return Err("Formula: Invalid defined name formula".to_string());
3611 }
3612 }
3613
3614 Ok(sheet_id)
3615 }
3616
3617 pub fn delete_defined_name(&mut self, name: &str, scope: Option<u32>) -> Result<(), String> {
3619 let name_upper = name.to_uppercase();
3620 let defined_names = &self.workbook.defined_names;
3621 let sheet_id = match scope {
3622 Some(index) => Some(self.workbook.worksheet(index)?.sheet_id),
3623 None => None,
3624 };
3625 let mut index = None;
3626 for (i, df) in defined_names.iter().enumerate() {
3627 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
3628 index = Some(i);
3629 }
3630 }
3631 if let Some(i) = index {
3632 self.workbook.defined_names.remove(i);
3633 self.reset_parsed_structures();
3634 Ok(())
3635 } else {
3636 Err("Defined name not found".to_string())
3637 }
3638 }
3639
3640 pub fn update_defined_name(
3642 &mut self,
3643 name: &str,
3644 scope: Option<u32>,
3645 new_name: &str,
3646 new_scope: Option<u32>,
3647 new_formula: &str,
3648 ) -> Result<(), String> {
3649 if !is_valid_identifier(new_name) {
3650 return Err("Name: Invalid defined name".to_string());
3651 };
3652 let name_upper = name.to_uppercase();
3653 let new_name_upper = new_name.to_uppercase();
3654
3655 if name_upper != new_name_upper || scope != new_scope {
3656 for key in self.parsed_defined_names.keys() {
3657 if key.1.to_uppercase() == new_name_upper && key.0 == new_scope {
3658 return Err("Name: Defined name already exists".to_string());
3659 }
3660 }
3661 }
3662 let defined_names = &self.workbook.defined_names;
3663 let sheet_id = match scope {
3664 Some(index) => Some(
3665 self.workbook
3666 .worksheet(index)
3667 .map_err(|_| "Scope: Invalid sheet index")?
3668 .sheet_id,
3669 ),
3670 None => None,
3671 };
3672
3673 let new_sheet_id = match new_scope {
3674 Some(index) => Some(
3675 self.workbook
3676 .worksheet(index)
3677 .map_err(|_| "Scope: Invalid sheet index")?
3678 .sheet_id,
3679 ),
3680 None => None,
3681 };
3682
3683 let mut index = None;
3684 for (i, df) in defined_names.iter().enumerate() {
3685 if df.name.to_uppercase() == name_upper && df.sheet_id == sheet_id {
3686 index = Some(i);
3687 }
3688 }
3689 let context = self.defined_name_context();
3691 let internal_formula = self.user_formula_to_internal(new_formula, &context)?;
3692 if let Some(i) = index {
3693 if let Some(df) = self.workbook.defined_names.get_mut(i) {
3694 if new_name != df.name {
3695 self.parser.set_lexer_mode(LexerMode::R1C1);
3700 let worksheets = &mut self.workbook.worksheets;
3701 for worksheet in worksheets {
3702 let cell_reference = CellReferenceRC {
3703 sheet: worksheet.get_name(),
3704 row: 1,
3705 column: 1,
3706 };
3707 let mut formulas = Vec::new();
3708 for formula in &worksheet.shared_formulas {
3709 let mut t = self.parser.parse(formula, &cell_reference);
3710 rename_defined_name_in_node(&mut t, name, scope, new_name);
3711 formulas.push(to_rc_format(&t));
3712 }
3713 worksheet.shared_formulas = formulas;
3714 }
3715 self.parser.set_lexer_mode(LexerMode::A1);
3717 }
3718 df.name = new_name.to_string();
3719 df.sheet_id = new_sheet_id;
3720 df.formula = internal_formula;
3721 self.reset_parsed_structures();
3722 }
3723 Ok(())
3724 } else {
3725 Err("Defined name not found".to_string())
3726 }
3727 }
3728 pub fn get_column_style(&self, sheet: u32, column: i32) -> Result<Option<Style>, String> {
3730 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3731 let cols = &worksheet.cols;
3732 for col in cols {
3733 if column >= col.min && column <= col.max {
3734 if let Some(style_index) = col.style {
3735 let style = self.workbook.styles.get_style(style_index)?;
3736 return Ok(Some(style));
3737 }
3738 return Ok(None);
3739 }
3740 }
3741 Ok(None)
3742 } else {
3743 Err("Invalid sheet".to_string())
3744 }
3745 }
3746
3747 pub fn get_row_style(&self, sheet: u32, row: i32) -> Result<Option<Style>, String> {
3749 if let Some(worksheet) = self.workbook.worksheets.get(sheet as usize) {
3750 let rows = &worksheet.rows;
3751 for r in rows {
3752 if row == r.r {
3753 let style = self.workbook.styles.get_style(r.s)?;
3754 return Ok(Some(style));
3755 }
3756 }
3757 Ok(None)
3758 } else {
3759 Err("Invalid sheet".to_string())
3760 }
3761 }
3762
3763 pub fn set_column_style(
3765 &mut self,
3766 sheet: u32,
3767 column: i32,
3768 style: &Style,
3769 ) -> Result<(), String> {
3770 let style_index = self.workbook.styles.get_style_index_or_create(style);
3771 self.workbook
3772 .worksheet_mut(sheet)?
3773 .set_column_style(column, style_index)
3774 }
3775
3776 pub fn set_row_style(&mut self, sheet: u32, row: i32, style: &Style) -> Result<(), String> {
3778 let style_index = self.workbook.styles.get_style_index_or_create(style);
3779 self.workbook
3780 .worksheet_mut(sheet)?
3781 .set_row_style(row, style_index)
3782 }
3783
3784 pub fn delete_column_style(&mut self, sheet: u32, column: i32) -> Result<(), String> {
3786 self.workbook
3787 .worksheet_mut(sheet)?
3788 .delete_column_style(column)
3789 }
3790
3791 pub fn delete_row_style(&mut self, sheet: u32, row: i32) -> Result<(), String> {
3793 self.workbook.worksheet_mut(sheet)?.delete_row_style(row)
3794 }
3795
3796 pub fn set_locale(&mut self, locale_id: &str) -> Result<(), String> {
3798 let locale = match get_locale(locale_id) {
3799 Ok(l) => l,
3800 Err(_) => return Err(format!("Invalid locale: {locale_id}")),
3801 };
3802 self.parser.set_locale(locale);
3803 self.locale = locale;
3804 self.workbook.settings.locale = locale_id.to_string();
3805 self.evaluate();
3806 Ok(())
3807 }
3808
3809 pub fn set_timezone(&mut self, timezone: &str) -> Result<(), String> {
3811 let tz = match Tz::parse(timezone) {
3812 Ok(tz) => tz,
3813 Err(_) => return Err(format!("Invalid timezone: {}", timezone)),
3814 };
3815 self.tz = tz;
3816 self.workbook.settings.tz = timezone.to_string();
3817 self.evaluate();
3818 Ok(())
3819 }
3820
3821 pub fn set_language(&mut self, language_id: &str) -> Result<(), String> {
3823 let language = match get_language(language_id) {
3824 Ok(l) => l,
3825 Err(_) => return Err(format!("Invalid language: {language_id}")),
3826 };
3827 self.parser.set_language(language);
3828 self.language = language;
3829 Ok(())
3830 }
3831
3832 pub fn get_language(&self) -> String {
3834 self.language.code.clone()
3835 }
3836
3837 pub fn get_timezone(&self) -> String {
3839 self.workbook.settings.tz.clone()
3840 }
3841
3842 pub fn get_locale(&self) -> String {
3844 self.workbook.settings.locale.clone()
3845 }
3846
3847 pub fn get_fmt_settings(&self) -> FmtSettings {
3849 let day_example = 46006.0; let currency = self.locale.currency.iso.clone();
3851 let currency_symbol = &self.locale.currency.symbol;
3852 let short_date = &self.locale.dates.date_formats.short;
3854 let long_date = &self.locale.dates.date_formats.long;
3856 let short_date_example = format_number(day_example, short_date, self.locale).text;
3857 let long_date_example = format_number(day_example, long_date, self.locale).text;
3858 let currency_format_template = &self.locale.numbers.currency_formats.standard;
3863 let currency_format = currency_format_template
3864 .replace("¤", &format!("\"{}\"", currency_symbol))
3865 .replace(" ", " ");
3866
3867 let number_fmt = "#,##0.00".to_string();
3868 let number_example = format_number(1234.567, &number_fmt, self.locale).text;
3869 FmtSettings {
3870 currency,
3871 currency_format,
3872 short_date: short_date.clone(),
3873 long_date: long_date.clone(),
3874 short_date_example,
3875 long_date_example,
3876 number_fmt,
3877 number_example,
3878 }
3879 }
3880
3881 pub fn cycle_reference(
3887 &self,
3888 value: &str,
3889 start: usize,
3890 end: usize,
3891 ) -> Result<(String, i32, i32), String> {
3892 crate::expressions::lexer::util::cycle_reference(
3893 value,
3894 start,
3895 end,
3896 self.locale,
3897 self.language,
3898 )
3899 }
3900}
3901
3902#[cfg(test)]
3903mod tests {
3904 #![allow(clippy::expect_used)]
3905 use super::CellReferenceIndex as CellReference;
3906 use crate::{test::util::new_empty_model, types::Cell};
3907
3908 #[test]
3909 fn test_cell_reference_to_string() {
3910 let model = new_empty_model();
3911 let reference = CellReference {
3912 sheet: 0,
3913 row: 32,
3914 column: 16,
3915 };
3916 assert_eq!(
3917 model.cell_reference_to_string(&reference),
3918 Ok("Sheet1!P32".to_string())
3919 )
3920 }
3921
3922 #[test]
3923 fn test_cell_reference_to_string_invalid_worksheet() {
3924 let model = new_empty_model();
3925 let reference = CellReference {
3926 sheet: 10,
3927 row: 1,
3928 column: 1,
3929 };
3930 assert_eq!(
3931 model.cell_reference_to_string(&reference),
3932 Err("Invalid sheet index".to_string())
3933 )
3934 }
3935
3936 #[test]
3937 fn test_cell_reference_to_string_invalid_column() {
3938 let model = new_empty_model();
3939 let reference = CellReference {
3940 sheet: 0,
3941 row: 1,
3942 column: 20_000,
3943 };
3944 assert_eq!(
3945 model.cell_reference_to_string(&reference),
3946 Err("Invalid column".to_string())
3947 )
3948 }
3949
3950 #[test]
3951 fn test_cell_reference_to_string_invalid_row() {
3952 let model = new_empty_model();
3953 let reference = CellReference {
3954 sheet: 0,
3955 row: 2_000_000,
3956 column: 1,
3957 };
3958 assert_eq!(
3959 model.cell_reference_to_string(&reference),
3960 Err("Invalid row".to_string())
3961 )
3962 }
3963
3964 #[test]
3965 fn test_get_cell() {
3966 let mut model = new_empty_model();
3967 model._set("A1", "35");
3968 model._set("A2", "");
3969 let worksheet = model.workbook.worksheet(0).expect("Invalid sheet");
3970
3971 assert_eq!(
3972 worksheet.cell(1, 1),
3973 Some(&Cell::NumberCell { v: 35.0, s: 0 })
3974 );
3975
3976 assert_eq!(worksheet.cell(2, 1), Some(&Cell::EmptyCell { s: 0 }));
3978 assert_eq!(worksheet.cell(3, 1), None)
3979 }
3980
3981 #[test]
3982 fn test_get_cell_invalid_sheet() {
3983 let model = new_empty_model();
3984 assert_eq!(
3985 model.workbook.worksheet(5),
3986 Err("Invalid sheet index".to_string()),
3987 )
3988 }
3989
3990 #[test]
3991 fn test_update_cell_with_sign_prefixed_formulas() {
3992 let mut model = new_empty_model();
3993
3994 let update_result = model.update_cell_with_formula(0, 1, 1, "-A2*2".to_string());
3995 model.evaluate();
3996 assert_eq!(update_result, Ok(()));
3997 assert_eq!(model._get_formula("A1"), *"=-A2*2");
3998 }
3999}