Formula bar: hide _xludf. like Excel, keep it when the edit is confirmed unchanged (#726)
This commit is contained in:
parent
f63a437d5b
commit
6939d95cae
|
|
@ -9,6 +9,14 @@ pub(crate) fn canonical(
|
|||
sheet: usize,
|
||||
cell: gridcraft_engine::core::CellRef,
|
||||
) -> Result<String, ParseError> {
|
||||
// The editor hid the `_xludf.` prefixes of this cell's formula; confirming it unchanged keeps
|
||||
// the user-defined calls instead of binding them to the built-ins of the same name.
|
||||
if let Some(stored) = wb.sheet(sheet).and_then(|sh| sh.cell(cell)).filter(|c| c.formula.is_some()).map(|c| c.input_text())
|
||||
&& has_udf_prefix(&stored)
|
||||
&& text == display(&stored, locale, wb, sheet)
|
||||
{
|
||||
return Ok(stored);
|
||||
}
|
||||
if locale == FormulaLocale::En || wb.sheet(sheet).is_some_and(|sh| wb.styles.get(sh.style_id(cell)).num_fmt.as_str() == "@") {
|
||||
return Ok(text.to_string());
|
||||
}
|
||||
|
|
@ -40,16 +48,42 @@ pub(crate) fn canonical(
|
|||
}
|
||||
|
||||
pub(crate) fn display(text: &str, locale: FormulaLocale, wb: &Workbook, sheet: usize) -> String {
|
||||
// English (and every language without a formula table) shows the stored text untouched,
|
||||
// and skips a parse per frame.
|
||||
// English (and every language without a formula table) shows the stored text, `_xludf.`
|
||||
// prefixes aside, and skips a parse per frame.
|
||||
if locale == FormulaLocale::En {
|
||||
return text.to_string();
|
||||
return hide_udf_prefix(text, locale);
|
||||
}
|
||||
let Some(body) = text.strip_prefix('=') else { return text.to_string() };
|
||||
formula::parse(body)
|
||||
let shown = formula::parse(body)
|
||||
.and_then(|expr| formula::print_input(&expr, locale, |name| wb.name(name, sheet).is_some() || wb.table(name).is_some()))
|
||||
.map(|body| format!("={body}"))
|
||||
.unwrap_or_else(|_| text.to_string())
|
||||
.unwrap_or_else(|_| text.to_string());
|
||||
hide_udf_prefix(&shown, locale)
|
||||
}
|
||||
|
||||
const UDF_PREFIX: &str = "_xludf.";
|
||||
|
||||
fn has_udf_prefix(text: &str) -> bool {
|
||||
text.to_ascii_lowercase().contains(UDF_PREFIX)
|
||||
}
|
||||
|
||||
/// Excel shows a user-defined call such as `_xludf.EOMONTH()` as `=EOMONTH()`. Only function
|
||||
/// names lose the prefix: text literals and names keep it.
|
||||
fn hide_udf_prefix(text: &str, locale: FormulaLocale) -> String {
|
||||
let Some(body) = text.strip_prefix('=').filter(|b| has_udf_prefix(b)) else { return text.to_string() };
|
||||
let Ok(tokens) = formula::lexer::tokenize_locale(body, locale) else { return text.to_string() };
|
||||
let mut out = String::from("=");
|
||||
let mut from = 0;
|
||||
for t in tokens {
|
||||
if matches!(t.tok, formula::lexer::Tok::Func(_))
|
||||
&& body.get(t.start..t.start + UDF_PREFIX.len()).is_some_and(|p| p.eq_ignore_ascii_case(UDF_PREFIX))
|
||||
{
|
||||
out.push_str(body.get(from..t.start).unwrap_or(""));
|
||||
from = t.start + UDF_PREFIX.len();
|
||||
}
|
||||
}
|
||||
out.push_str(body.get(from..).unwrap_or(""));
|
||||
out
|
||||
}
|
||||
|
||||
// Descriptions/signatures for the supported Spanish function table; untranslated functions
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Language selection must affect UI entry, never the canonical engine/file boundary.
|
||||
use gridcraft_engine::{
|
||||
Session,
|
||||
core::{CellRef, Value},
|
||||
core::{CellError, CellRef, Value},
|
||||
};
|
||||
use gridcraft_ui_egui::{SheetApp, UiState, i18n::Language};
|
||||
use serde_json::json;
|
||||
|
|
@ -201,3 +201,21 @@ fn czech_interface_retains_its_canonical_formula_fallback() {
|
|||
let restored: UiState = serde_json::from_str(&serde_json::to_string(&app.ui).unwrap()).unwrap();
|
||||
assert_eq!(restored.language, Language::Cs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_defined_prefix_is_hidden_while_editing_and_kept_on_commit() {
|
||||
// Excel shows `_xludf.EOMONTH()` as `=EOMONTH()`; the cell still holds the user-defined call
|
||||
// (#726), and committing the edit unchanged must not turn it into the built-in.
|
||||
let mut app = app();
|
||||
app.run("cell.set", json!({"cell":"A1","input":"=_xludf.EOMONTH()&_xludf.CONCAT(\"_xludf.x\")"})).unwrap();
|
||||
app.begin_edit(None, true);
|
||||
assert_eq!(app.editor.as_ref().unwrap().text, "=EOMONTH()&CONCAT(\"_xludf.x\")");
|
||||
assert!(app.commit_edit(0, 0, false, false));
|
||||
assert_eq!(formula(&app), "_xludf.EOMONTH()&_xludf.CONCAT(\"_xludf.x\")");
|
||||
assert_eq!(app.session.active().unwrap().wb.active().unwrap().value(CellRef::new(0, 0)), Value::Error(CellError::Name));
|
||||
app.run("app.language.set", json!({"language":"es"})).unwrap();
|
||||
app.begin_edit(None, true);
|
||||
assert_eq!(app.editor.as_ref().unwrap().text, "=EOMONTH()&CONCAT(\"_xludf.x\")");
|
||||
assert!(app.commit_edit(0, 0, false, false));
|
||||
assert_eq!(formula(&app), "_xludf.EOMONTH()&_xludf.CONCAT(\"_xludf.x\")");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue