cat / 012
clone

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

Re-infer formulas reading blanks of a newly formatted column, row or sheet at once

Dami committed 5f1f93d
commit
5f1f93d65828eb7bca4689925caf06c3387ef5fd
parent
23f0bf06ca18390900d605424164e381bd540711
author
Dami <dami.etoile@gmail.com>
4 files changed, +118 -2
Minternal/sheet/history.go2+-
Ainternal/sheet/linereaders.go70++++++++++++++++++++++++++++++
Ainternal/sheet/linereinfer_test.go39+++++++++++++++++
Minternal/sheet/lines.go9+++-
M internal/sheet/history.go +1 -1
A internal/sheet/linereaders.go +70 -0
@@ -0,0 +1,70 @@
1+package sheet2+3+// Formulas infer their format from the cells they read (=B5*2 shows4+// currency when B5 does), blank ones included. A blank cell has no entry5+// of its own to mark changed when its column, row or the sheet is6+// formatted, so the formulas reading anywhere in the line are marked7+// instead, found through the indexes recalculation uses: the cost is the8+// formulas, not the line's million cells.9+10+// readersIn returns the formulas, on any sheet, that read a cell of r on11+// s: by reference, through a range, a named range, or naming s.12+func (s *Sheet) readersIn(r Rect) []loc {13+ seen := map[loc]struct{}{}14+ add := func(l loc) { seen[l] = struct{}{} }15+ for a, users := range s.dependents {16+ if r.Contains(a) {17+ for u := range users {18+ add(loc{s, u})19+ }20+ }21+ }22+ s.rangeUsers.usersIn(r, func(u Addr) { add(loc{s, u}) })23+ w := s.wb24+ for _, nu := range w.namedInUse() {25+ if nu.s == s && overlaps(nu.r, r) {26+ for u := range nu.users {27+ add(u)28+ }29+ }30+ }31+ for u := range w.crossUsers {32+ if c := u.s.cells.get(u.a); c != nil {33+ for _, x := range c.xrefs {34+ if w.byKey[x.key] == s && overlaps(x.r, r) {35+ add(u)36+ }37+ }38+ }39+ }40+ out := make([]loc, 0, len(seen))41+ for l := range seen {42+ out = append(out, l)43+ }44+ return out45+}46+47+// usersIn calls fn with the formulas one of whose ranges overlaps r; a48+// formula may come more than once.49+func (x *rangeIndex) usersIn(r Rect, fn func(Addr)) {50+ each := func(iv *intervals) {51+ for rg, users := range iv.users {52+ if overlaps(rg, r) {53+ for u := range users {54+ fn(u)55+ }56+ }57+ }58+ }59+ for c, iv := range x.byCol {60+ if c >= r.From.Col && c <= r.To.Col {61+ each(iv)62+ }63+ }64+ each(&x.wide)65+}66+67+// overlaps reports whether two ranges share a cell.68+func overlaps(p, q Rect) bool {69+ return p.From.Col <= q.To.Col && q.From.Col <= p.To.Col && p.From.Row <= q.To.Row && q.From.Row <= p.To.Row70+}
A internal/sheet/linereinfer_test.go +39 -0
M internal/sheet/lines.go +8 -1