mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-31 06:06:48 -06:00
Names: a name over several ranges reads its top-level commas as unions (fixes #728)
This commit is contained in:
@@ -1206,7 +1206,7 @@ pub(crate) fn rewrite_all_formulas(wb: &mut gridcraft_model::Workbook, target: &
|
||||
}
|
||||
}
|
||||
for n in wb.names.iter_mut() {
|
||||
if let Ok(expr) = gridcraft_formula::parse(&n.formula) {
|
||||
if let Ok(expr) = gridcraft_formula::parse_name(&n.formula) {
|
||||
// Names are workbook-level: unqualified refs don't occur; qualified ones adjust.
|
||||
let new = gridcraft_formula::adjust::adjust(expr, "\u{0}", target, e);
|
||||
n.formula = gridcraft_formula::print(&new);
|
||||
|
||||
@@ -265,7 +265,7 @@ fn define_name(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
let refers = match str_param(p, "refersTo") {
|
||||
// As in Excel, relative references are relative to the active cell; names keep them
|
||||
// relative to A1, as files do.
|
||||
Some(r) => match gridcraft_formula::parse(r.trim_start_matches('=')) {
|
||||
Some(r) => match gridcraft_formula::parse_name(r.trim_start_matches('=')) {
|
||||
Ok(e) if gridcraft_formula::adjust::has_relative_refs(&e) => {
|
||||
let at = d.selection.active;
|
||||
gridcraft_formula::print(&gridcraft_formula::adjust::shift_relative_wrapping(e, -(at.row as i64), -(at.col as i64)))
|
||||
@@ -280,7 +280,7 @@ fn define_name(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
format!("{}!{}", gridcraft_formula::quote_sheet(&sh.name), body)
|
||||
}
|
||||
};
|
||||
if gridcraft_formula::parse(&refers).is_err() {
|
||||
if gridcraft_formula::parse_name(&refers).is_err() {
|
||||
return Err(EngineError::Other("There's a problem with this formula.".into()));
|
||||
}
|
||||
let comment = str_param(p, "comment").unwrap_or("").to_string();
|
||||
@@ -355,7 +355,7 @@ fn rename_name_in_formulas(wb: &mut gridcraft_model::Workbook, old: &str, old_sc
|
||||
}
|
||||
for n in wb.names.iter_mut() {
|
||||
if n.scope.is_none_or(applies)
|
||||
&& let Some(e) = gridcraft_formula::parse(&n.formula).ok().and_then(rename)
|
||||
&& let Some(e) = gridcraft_formula::parse_name(&n.formula).ok().and_then(rename)
|
||||
{
|
||||
n.formula = gridcraft_formula::print(&e);
|
||||
}
|
||||
@@ -610,4 +610,27 @@ mod tests {
|
||||
let r = s.execute("formulas.defineName", json!({"name": "First", "refersTo": "=Sheet1!$A$1"})).unwrap();
|
||||
assert_eq!(r["refersTo"], "=Sheet1!$A$1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn names_referring_to_several_ranges() {
|
||||
let mut s = Session::new();
|
||||
s.new_workbook();
|
||||
s.execute("range.setValues", json!({"range": "A1:C2", "values": [[1, 0, 5], [2, 0, 7]]})).unwrap();
|
||||
// Excel writes and accepts a union in a name without parentheses.
|
||||
let r = s.execute("formulas.defineName", json!({"name": "u", "refersTo": "=Sheet1!$A$1:$A$2,Sheet1!$C$1:$C$2"})).unwrap();
|
||||
assert_eq!(r["refersTo"], "=Sheet1!$A$1:$A$2,Sheet1!$C$1:$C$2");
|
||||
for (cell, input) in [("E1", "=SUM(u)"), ("E2", "=AREAS(u)"), ("E3", "=MIN(u)"), ("E4", "=INDEX(u,2,1,2)")] {
|
||||
s.execute("cell.set", json!({"cell": cell, "input": input})).unwrap();
|
||||
}
|
||||
let v = |s: &mut Session, a: &str| s.execute("cell.get", json!({"cell": a})).unwrap()["value"].clone();
|
||||
assert_eq!(v(&mut s, "E1"), json!(15.0));
|
||||
assert_eq!(v(&mut s, "E2"), json!(2.0));
|
||||
assert_eq!(v(&mut s, "E3"), json!(1.0));
|
||||
assert_eq!(v(&mut s, "E4"), json!(7.0));
|
||||
// Renaming the sheet follows every area, and the definition keeps Excel's form.
|
||||
s.execute("sheet.rename", json!({"name": "Data"})).unwrap();
|
||||
let name = s.doc().unwrap().wb.names.iter().find(|n| n.name == "u").map(|n| n.formula.clone());
|
||||
assert_eq!(name.as_deref(), Some("Data!$A$1:$A$2,Data!$C$1:$C$2"));
|
||||
assert_eq!(v(&mut s, "E1"), json!(15.0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +704,7 @@ fn delete_sheet(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
*sc -= 1;
|
||||
}
|
||||
// Names referring to the sheet become #REF!.
|
||||
if let Ok(e) = gridcraft_formula::parse(&n.formula) {
|
||||
if let Ok(e) = gridcraft_formula::parse_name(&n.formula) {
|
||||
let ne = gridcraft_formula::adjust::delete_sheet(e.clone(), &name, &order);
|
||||
if ne != e {
|
||||
n.formula = gridcraft_formula::print(&ne);
|
||||
@@ -766,7 +766,7 @@ fn rename_sheet(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
}
|
||||
}
|
||||
for n in cx.wb.names.iter_mut() {
|
||||
if let Ok(e) = gridcraft_formula::parse(&n.formula) {
|
||||
if let Ok(e) = gridcraft_formula::parse_name(&n.formula) {
|
||||
n.formula = gridcraft_formula::print(&gridcraft_formula::adjust::rename_sheet(e, &old, &name));
|
||||
}
|
||||
}
|
||||
@@ -805,7 +805,7 @@ fn move_sheet(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
.iter()
|
||||
.filter(|nm| nm.scope == Some(i))
|
||||
.map(|nm| {
|
||||
let formula = gridcraft_formula::parse(&nm.formula)
|
||||
let formula = gridcraft_formula::parse_name(&nm.formula)
|
||||
.map(|e| gridcraft_formula::print(&gridcraft_formula::adjust::rename_sheet(e, &base, &sh.name)))
|
||||
.unwrap_or_else(|_| nm.formula.clone());
|
||||
gridcraft_model::DefinedName { scope: Some(at), formula, ..nm.clone() }
|
||||
|
||||
Reference in New Issue
Block a user