cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

Arrays: unmerging frees the arrays its merges blocked, and a cycle through an array gone is looked for again

Dami committed cbb411f
Unmerge and Merge had the arrays over the range asked about spill
again, but the merges they take away can reach past it, so an array
blocked by such a merge stayed blocked until something else touched
it. They now ask over the range and every merge taken away.

An array found blocked by a cycle through the cells of another array
that stops spilling in the same pass (deleting rows puts a plain
formula where an array's anchor was, and the anchor's old spill stays
until it's computed) stayed blocked, since nothing it reads changed.
An array that stops spilling or spills elsewhere now has the arrays
blocked by a cycle computed again; a count keeps this free when there
are none.

Found by TestRandomEdits with -randedit.seeds=20000 (seeds 9887,
10602, 13460, 14621).
commit
cbb411ffd26487c4c879c9063c2248f6831ba4c7
parent
85fd593027b2c8132193c416ff4403ea5ae894b4
author
Dami <dami.etoile@gmail.com>
kind
fix risk score 1.3 of 3, Jev's estimate
6 files changed, +83 -12
Minternal/sheet/merge.go28+++++++++++++++++-----------
Minternal/sheet/merge_undo_test.go17+++++++++++++++++
Minternal/sheet/spill.go11++++++++++-
Minternal/sheet/spill_test.go15+++++++++++++++
Minternal/sheet/spillblock.go21+++++++++++++++++++++
Minternal/sheet/workbook.go3+++
M internal/sheet/merge.go +17 -11
@@ -183,11 +183,8 @@ func (s *Sheet) Merge(r Rect, k MergeKind) error {
183183 s.place(a, c.leftover())184184 }185185 }186- next := slices.DeleteFunc(slices.Clone(s.view.merges), func(m Rect) bool {187- _, overlaps := intersectRect(m, r)188- return overlaps189- })190- s.setMerges(append(next, areas...), r)186+ next, span := s.mergesOutside(r)187+ s.setMerges(append(next, areas...), span)191188 })192189 return nil193190 }
@@ -211,18 +208,27 @@ func (s *Sheet) MergeAcross(rows bool, n int) (Rect, bool) {
211208 // Unmerge splits the merges overlapping r back into cells, as one undo212209 // step, and returns how many there were.213210 func (s *Sheet) Unmerge(r Rect) int {214- n := 0211+ next, span := s.mergesOutside(r)212+ n := len(s.view.merges) - len(next)213+ if n > 0 {214+ s.change("unmerge "+r.String(), r, func() { s.setMerges(next, span) })215+ }216+ return n217+}218+219+// mergesOutside returns the merges that don't overlap r, and the range220+// holding r and those that do: where arrays blocked by them may spill221+// once they go.222+func (s *Sheet) mergesOutside(r Rect) ([]Rect, Rect) {223+ span := r215224 next := slices.DeleteFunc(slices.Clone(s.view.merges), func(m Rect) bool {216225 _, overlaps := intersectRect(m, r)217226 if overlaps {218- n++227+ span = union(span, m)219228 }220229 return overlaps221230 })222- if n > 0 {223- s.change("unmerge "+r.String(), r, func() { s.setMerges(next, r) })224- }225- return n231+ return next, span226232 }227233 228234 // setMerges replaces the merges, recording them for undo, and has the
M internal/sheet/merge_undo_test.go +17 -0
M internal/sheet/spill.go +10 -1
M internal/sheet/spill_test.go +15 -0
M internal/sheet/spillblock.go +21 -0
M internal/sheet/workbook.go +3 -0