diff --git a/base/src/functions/information.rs b/base/src/functions/information.rs index 6d2aaa7..fca7280 100644 --- a/base/src/functions/information.rs +++ b/base/src/functions/information.rs @@ -293,4 +293,43 @@ impl Model { message: "Invalid name".to_string(), } } + + pub(crate) fn fn_formulatext(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() != 1 { + return CalcResult::new_args_number_error(cell); + } + if let CalcResult::Range { left, right } = self.evaluate_node_with_reference(&args[0], cell) + { + if left.sheet != right.sheet { + return CalcResult::Error { + error: Error::ERROR, + origin: cell, + message: "3D ranges not supported".to_string(), + }; + } + if left.row != right.row && left.column != right.column { + // FIXME: Implicit intersection or dynamic arrays + return CalcResult::Error { + error: Error::VALUE, + origin: cell, + message: "argument must be a reference to a single cell".to_string(), + }; + } + if let Ok(Some(f)) = self.get_cell_formula(left.sheet, left.row, left.column) { + CalcResult::String(f) + } else { + CalcResult::Error { + error: Error::NA, + origin: cell, + message: "Reference does not have a formula".to_string(), + } + } + } else { + CalcResult::Error { + error: Error::VALUE, + origin: cell, + message: "Argument must be a reference".to_string(), + } + } + } } diff --git a/base/src/functions/mod.rs b/base/src/functions/mod.rs index 6fcff67..9f3a0aa 100644 --- a/base/src/functions/mod.rs +++ b/base/src/functions/mod.rs @@ -75,6 +75,7 @@ pub enum Function { // Information ErrorType, + Formulatext, Isblank, Iserr, Iserror, @@ -247,7 +248,7 @@ pub enum Function { } impl Function { - pub fn into_iter() -> IntoIter { + pub fn into_iter() -> IntoIter { [ Function::And, Function::False, @@ -332,6 +333,7 @@ impl Function { Function::Isodd, Function::Iseven, Function::ErrorType, + Function::Formulatext, Function::Isformula, Function::Type, Function::Sheet, @@ -482,6 +484,7 @@ impl Function { Function::Valuetotext => "_xlfn.VALUETOTEXT".to_string(), Function::Isformula => "_xlfn.ISFORMULA".to_string(), Function::Sheet => "_xlfn.SHEET".to_string(), + Function::Formulatext => "_xlfn.FORMULATEXT".to_string(), _ => self.to_string(), } } @@ -592,6 +595,7 @@ impl Function { "ISODD" => Some(Function::Isodd), "ISEVEN" => Some(Function::Iseven), "ERROR.TYPE" => Some(Function::ErrorType), + "FORMULATEXT" | "_XLFN.FORMULATEXT" => Some(Function::Formulatext), "ISFORMULA" | "_XLFN.ISFORMULA" => Some(Function::Isformula), "TYPE" => Some(Function::Type), "SHEET" | "_XLFN.SHEET" => Some(Function::Sheet), @@ -798,6 +802,7 @@ impl fmt::Display for Function { Function::Isodd => write!(f, "ISODD"), Function::Iseven => write!(f, "ISEVEN"), Function::ErrorType => write!(f, "ERROR.TYPE"), + Function::Formulatext => write!(f, "FORMULATEXT"), Function::Isformula => write!(f, "ISFORMULA"), Function::Type => write!(f, "TYPE"), Function::Sheet => write!(f, "SHEET"), @@ -1033,6 +1038,7 @@ impl Model { Function::Isodd => self.fn_isodd(args, cell), Function::Iseven => self.fn_iseven(args, cell), Function::ErrorType => self.fn_errortype(args, cell), + Function::Formulatext => self.fn_formulatext(args, cell), Function::Isformula => self.fn_isformula(args, cell), Function::Type => self.fn_type(args, cell), Function::Sheet => self.fn_sheet(args, cell), diff --git a/base/src/test/mod.rs b/base/src/test/mod.rs index a6571f0..222fe1b 100644 --- a/base/src/test/mod.rs +++ b/base/src/test/mod.rs @@ -15,6 +15,7 @@ mod test_fn_concatenate; mod test_fn_count; mod test_fn_exact; mod test_fn_financial; +mod test_fn_formulatext; mod test_fn_if; mod test_fn_maxifs; mod test_fn_minifs; diff --git a/base/src/test/test_fn_formulatext.rs b/base/src/test/test_fn_formulatext.rs new file mode 100644 index 0000000..622ecfa --- /dev/null +++ b/base/src/test/test_fn_formulatext.rs @@ -0,0 +1,17 @@ +#![allow(clippy::unwrap_used)] + +use crate::test::util::new_empty_model; + +#[test] +fn simple_cases() {} + +#[test] +fn wrong_number_of_arguments() { + let mut model = new_empty_model(); + model._set("A1", "=UNICODE()"); + model._set("A2", "=UNICODE(\"B\",\"A\")"); + model.evaluate(); + + assert_eq!(model._get_text("A1"), *"#ERROR!"); + assert_eq!(model._get_text("A2"), *"#ERROR!"); +} diff --git a/xlsx/tests/calc_tests/FORMULATEXT.xlsx b/xlsx/tests/calc_tests/FORMULATEXT.xlsx new file mode 100644 index 0000000..1b5ceae Binary files /dev/null and b/xlsx/tests/calc_tests/FORMULATEXT.xlsx differ