mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-27 20:26:48 -06:00
Recalc: replacing or clearing a spilling formula removes its spill
Typing a value over a dynamic array formula, or clearing it, left the values it had spilled: with =SEQUENCE(3) in A1, typing 2 into A1 kept 2 and 3 in A2:A3, and =SUM(A1:A3) gave 7. Only formulas are evaluated again, so the old spill of a cell that no longer holds a formula was never written back. It is now removed when the formula goes, and the formulas reading its area are recalculated.
This commit is contained in:
@@ -351,6 +351,7 @@ impl Calc {
|
||||
|
||||
/// Updates the graph for cells whose content changed and recalculates what depends on them.
|
||||
pub fn cells_changed(&mut self, wb: &mut Workbook, changed: &[Key]) {
|
||||
let mut cleared: Vec<(usize, RangeRef)> = Vec::new();
|
||||
for &k in changed {
|
||||
let formula = wb.sheet(k.0).and_then(|s| s.cell(k.1)).and_then(|c| c.formula.clone());
|
||||
match formula.and_then(|f| f.expr()) {
|
||||
@@ -360,6 +361,15 @@ impl Calc {
|
||||
}
|
||||
None => {
|
||||
self.graph.remove(k);
|
||||
// A formula replaced by a constant (or cleared) takes its spilled values with it.
|
||||
if let Some(sh) = wb.sheet_mut(k.0)
|
||||
&& let Some(r) = sh.spill_ranges.remove(&k.1)
|
||||
{
|
||||
for c in r.iter() {
|
||||
sh.spill.remove(&c);
|
||||
}
|
||||
cleared.push((k.0, r));
|
||||
}
|
||||
// A formula that doesn't parse evaluates to #NAME?.
|
||||
if let Some(cell) = wb.sheet_mut(k.0).and_then(|s| s.cells.get_mut(k.1))
|
||||
&& cell.formula.is_some()
|
||||
@@ -398,6 +408,9 @@ impl Calc {
|
||||
seeds.extend(r.iter().take(65536).map(|c| (k.0, c)));
|
||||
}
|
||||
}
|
||||
for (si, r) in &cleared {
|
||||
seeds.extend(r.iter().take(65536).map(|c| (*si, c)));
|
||||
}
|
||||
let t0 = prof_now();
|
||||
let dirty = self.dirty_closure(wb, &seeds);
|
||||
let t1 = prof_now();
|
||||
|
||||
@@ -153,6 +153,18 @@ fn samples_build() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replacing_a_spilling_formula_clears_its_spill() {
|
||||
let mut s = s();
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "=SEQUENCE(3)"})).unwrap();
|
||||
s.execute("cell.set", json!({"cell": "B1", "input": "=SUM(A1:A3)"})).unwrap();
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "2"})).unwrap();
|
||||
assert_eq!((v(&s, "A2"), v(&s, "A3"), v(&s, "B1")), (Value::Empty, Value::Empty, Value::Number(2.0)));
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "=SEQUENCE(3)"})).unwrap();
|
||||
s.execute("edit.clearContents", json!({"range": "A1"})).unwrap();
|
||||
assert_eq!((v(&s, "A2"), v(&s, "B1")), (Value::Empty, Value::Number(0.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_command_survives_empty_params() {
|
||||
let mut s = Session::new();
|
||||
|
||||
Reference in New Issue
Block a user