mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-29 13:16:50 -06:00
Recalc: a spill that goes away unblocks the arrays it blocked
With =SEQUENCE(5) in F8 and =SEQUENCE(1,3) in E10 (blocked by F10), typing 0 into F9 blocks F8's array, which frees F10, but E10 stayed #SPILL! until a full recalculation. When a formula stops spilling over an area, #SPILL! anchors above or to the left of it are evaluated again.
This commit is contained in:
@@ -524,6 +524,7 @@ impl Calc {
|
||||
self.circular = cycles;
|
||||
// Write back.
|
||||
let mut spill_changes: Vec<Key> = Vec::new();
|
||||
let mut freed: Vec<(usize, RangeRef)> = Vec::new();
|
||||
for (k, v) in results {
|
||||
let Some(sheet) = wb.sheet_mut(k.0) else { continue };
|
||||
if let Some(cell) = sheet.cells.get_mut(k.1)
|
||||
@@ -572,6 +573,23 @@ impl Calc {
|
||||
self.graph.dependents_of_range(k.0, r, &mut deps);
|
||||
spill_changes.extend(deps);
|
||||
}
|
||||
if let Some(o) = old
|
||||
&& !sheet.spill_ranges.get(&k.1).is_some_and(|n| n.contains(o.start) && n.contains(o.end))
|
||||
{
|
||||
freed.push((k.0, o));
|
||||
}
|
||||
}
|
||||
// An area a formula no longer spills over may unblock another formula's array.
|
||||
for (si, o) in freed {
|
||||
for &(s, c) in self.graph.nodes.keys() {
|
||||
if s == si
|
||||
&& c.row <= o.end.row
|
||||
&& c.col <= o.end.col
|
||||
&& wb.sheet(s).is_some_and(|sh| sh.value(c) == Value::Error(CellError::Spill))
|
||||
{
|
||||
spill_changes.push((s, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
if full {
|
||||
// Everything was already evaluated once; spill dependents need another pass.
|
||||
|
||||
@@ -194,6 +194,18 @@ fn clearing_a_distant_blocker_unblocks_the_spill() {
|
||||
assert_eq!((v(&s, "A1"), v(&s, "A100")), (Value::Number(1.0), Value::Number(100.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_spill_that_goes_away_unblocks_another() {
|
||||
let mut s = s();
|
||||
s.execute("cell.set", json!({"cell": "F8", "input": "=SEQUENCE(5)"})).unwrap();
|
||||
s.execute("cell.set", json!({"cell": "E10", "input": "=SEQUENCE(1,3)"})).unwrap();
|
||||
assert_eq!(v(&s, "E10"), Value::Error(gridcraft_core::CellError::Spill));
|
||||
// Blocking F8's array frees F10 for E10's.
|
||||
s.execute("cell.set", json!({"cell": "F9", "input": "0"})).unwrap();
|
||||
assert_eq!(v(&s, "F8"), Value::Error(gridcraft_core::CellError::Spill));
|
||||
assert_eq!((v(&s, "E10"), v(&s, "G10")), (Value::Number(1.0), Value::Number(3.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_command_survives_empty_params() {
|
||||
let mut s = Session::new();
|
||||
|
||||
Reference in New Issue
Block a user