Engine: a Python cell that keeps only its value keeps its whole cached result

When a file is opened, a Python cell falls back to keeping only its value in
four cases: its code is missing from the Python part or the part is damaged
(the xlsx reader), its code is too long for a cell, its kept result is
malformed, or its result is past the adoption budget. The first kept the
values the cell spilled as plain values; the others dropped them, so values
the file showed were lost. All of them now follow one rule, through
Sheet::settle_spill: the anchor and every spilled cell keep their cached
values as plain values, with no live spill range; a cell's own content and
format are never overwritten; and the work is bounded by the spilled values
stored, not by the range. The values move from the spill into the cells, so
nothing is copied. The cut-by-budget test is renamed for what it now checks,
the dropped-result test now expects the values kept, and the adoption warning
and the file-format docs say so.
This commit is contained in:
prxnvt
2026-11-01 13:28:19 -05:00
parent 84d4f6aa84
commit ec7ee8d4ea
4 changed files with 112 additions and 36 deletions
+23
View File
@@ -215,6 +215,29 @@ impl Sheet {
}
}
/// Turns the spill anchored at `anchor` into plain values, for a Python cell that keeps only
/// its value: the range is forgotten, and each spilled value in it becomes its cell's value,
/// unless the cell holds content of its own (its format is kept either way). The work is
/// bounded by the spilled values stored, not by the size of the range.
pub fn settle_spill(&mut self, anchor: CellRef) {
let Some(r) = self.spill_ranges.remove(&anchor) else { return };
let inside: Vec<CellRef> = self.spill.range(r.start..=r.end).map(|(c, _)| *c).filter(|c| r.contains(*c)).collect();
for c in inside {
let Some(v) = self.spill.remove(&c) else { continue };
if v.is_empty() || c == anchor {
continue;
}
match self.cells.get_mut(c) {
Some(cell) if cell.has_content() => {}
Some(cell) => cell.value = v,
None => {
let style = self.style_id(c);
self.cells.set(c, Cell::styled(v, style));
}
}
}
}
/// Displayed value of a cell: its own value, or a spilled value.
pub fn value(&self, c: CellRef) -> Value {
match self.cells.get(c) {