mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-03 08:51:30 -06:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c851d7906 |
@@ -425,6 +425,9 @@ impl NumberFormat {
|
|||||||
/// The `TEXT()` worksheet function: formats a value with a format code. Numeric text is
|
/// The `TEXT()` worksheet function: formats a value with a format code. Numeric text is
|
||||||
/// converted to a number first; other text and booleans (as `TRUE`/`FALSE`) go through the text
|
/// converted to a number first; other text and booleans (as `TRUE`/`FALSE`) go through the text
|
||||||
/// section, or are returned as is.
|
/// section, or are returned as is.
|
||||||
|
/// Longest text a cell holds, in characters (Excel's limit), and so the longest `TEXT` result.
|
||||||
|
const MAX_CELL_TEXT_CHARS: usize = 32_767;
|
||||||
|
|
||||||
pub fn text_function(v: &Value, code: &str, sys: DateSystem) -> Result<String, CellError> {
|
pub fn text_function(v: &Value, code: &str, sys: DateSystem) -> Result<String, CellError> {
|
||||||
if code.is_empty() {
|
if code.is_empty() {
|
||||||
return Ok(String::new());
|
return Ok(String::new());
|
||||||
@@ -440,7 +443,15 @@ pub fn text_function(v: &Value, code: &str, sys: DateSystem) -> Result<String, C
|
|||||||
Value::Bool(b) => return Ok(fmt.format_text(if b { "TRUE" } else { "FALSE" }).text),
|
Value::Bool(b) => return Ok(fmt.format_text(if b { "TRUE" } else { "FALSE" }).text),
|
||||||
Value::Text(t) => match gridcraft_core::parse::parse_number_text(&t) {
|
Value::Text(t) => match gridcraft_core::parse::parse_number_text(&t) {
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => return Ok(fmt.format_text(&t).text),
|
// Every `@` repeats the text: a result past a cell's limit is `#VALUE!`, so nested
|
||||||
|
// TEXT calls can't multiply it further.
|
||||||
|
None => {
|
||||||
|
let out = fmt.format_text(&t).text;
|
||||||
|
if out.len() > MAX_CELL_TEXT_CHARS && out.chars().count() > MAX_CELL_TEXT_CHARS {
|
||||||
|
return Err(CellError::Value);
|
||||||
|
}
|
||||||
|
return Ok(out);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Value::Array(_) => return Err(CellError::Value),
|
Value::Array(_) => return Err(CellError::Value),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -396,6 +396,10 @@ fn text_fn() {
|
|||||||
assert_eq!(text_function(&Value::Number(1234.5), "$#,##0.00", S), Ok("$1,234.50".into()));
|
assert_eq!(text_function(&Value::Number(1234.5), "$#,##0.00", S), Ok("$1,234.50".into()));
|
||||||
assert_eq!(text_function(&Value::from("5"), "0.00", S), Ok("5.00".into()));
|
assert_eq!(text_function(&Value::from("5"), "0.00", S), Ok("5.00".into()));
|
||||||
assert_eq!(text_function(&Value::from("abc"), "0.00", S), Ok("abc".into()));
|
assert_eq!(text_function(&Value::from("abc"), "0.00", S), Ok("abc".into()));
|
||||||
|
// Each `@` repeats the text: up to a cell's 32,767 characters, then #VALUE!.
|
||||||
|
let at = "@".repeat(255);
|
||||||
|
assert_eq!(text_function(&Value::from("x".repeat(128).as_str()), &at, S).map(|s| s.len()), Ok(128 * 255));
|
||||||
|
assert_eq!(text_function(&Value::from("x".repeat(32_000).as_str()), &at, S), Err(CellError::Value));
|
||||||
assert_eq!(text_function(&Value::Error(CellError::NA), "0", S), Err(CellError::NA));
|
assert_eq!(text_function(&Value::Error(CellError::NA), "0", S), Err(CellError::NA));
|
||||||
assert_eq!(text_function(&Value::Number(46302.0), "yyyy", S), Ok("2026".into()));
|
assert_eq!(text_function(&Value::Number(46302.0), "yyyy", S), Ok("2026".into()));
|
||||||
assert_eq!(text_function(&Value::Number(0.5), "General", S), Ok("0.5".into()));
|
assert_eq!(text_function(&Value::Number(0.5), "General", S), Ok("0.5".into()));
|
||||||
|
|||||||
Reference in New Issue
Block a user