cat / 012
clone

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

cat/module-path
012 / internal / sheet / storederived.go
storederived.go 3.7K
1package sheet23import (4 "iter"5 "slices"6)78// The store's side of derived cells (slot.go): finding the pivot's9// results, reading what a derived cell shows without making a Cell, and10// writing a spilled value straight into its slot.1112// isPivot reports whether sl holds a pivot's result.13func (st *cellStore) isPivot(sl slot) bool {14 if sl.kind == slotRich {15 return st.rich[sl.ref].c.derived16 }17 return sl.kind&slotPivot != 018}1920// countPivot counts the cell at a, which was a pivot's result or not and21// becomes one or not.22func (st *cellStore) countPivot(a Addr, was, is bool) {23 switch {24 case is && !was:25 if st.pivots++; st.pivots == 1 {26 st.pivotArea = Rect{From: a, To: a}27 } else {28 st.pivotArea = union(st.pivotArea, Rect{From: a, To: a})29 }30 case was && !is:31 st.pivots--32 }33}3435// pivotKeys yields the addresses of the pivot's results stored.36func (st *cellStore) pivotKeys() iter.Seq[Addr] {37 return func(yield func(Addr) bool) {38 if st.pivots == 0 {39 return40 }41 for a := range st.anyKeysIn(st.pivotArea) {42 if b, i := st.find(a); b != nil && st.isPivot(b.vals[i]) && !yield(a) {43 return44 }45 }46 }47}4849// derivedOf returns what the cell at a holds as a derived cell would:50// its value, format, style and inferred format, and slotPivot or51// slotSpill for a pivot's result or a spilled cell, 0 for any other52// cell (none included). It makes no Cell, so the derived cells being53// rewritten are compared cheaply; the look mustn't be changed.54func (st *cellStore) derivedOf(a Addr) (v Value, l *look, kind uint8) {55 b, i := st.find(a)56 if b == nil {57 return Value{}, &noLook, 058 }59 sl := b.vals[i]60 if sl.kind != slotRich {61 return st.slotValue(sl), st.lookOf(sl), sl.kind & slotDerived62 }63 c := st.rich[sl.ref].c64 return c.Value, &look{c.Format, c.Style, c.auto}, richDerived(c)65}6667// richDerived is derivedOf's kind for a rich cell.68func richDerived(c *Cell) uint8 {69 switch {70 case c.derived:71 return slotPivot72 case c.spilled:73 return slotSpill74 }75 return 076}7778// derivedAt is derivedOf's kind alone.79func (st *cellStore) derivedAt(a Addr) uint8 {80 b, i := st.find(a)81 switch {82 case b == nil:83 return 084 case b.vals[i].kind == slotRich:85 return richDerived(st.rich[b.vals[i].ref].c)86 }87 return b.vals[i].kind & slotDerived88}8990// autoAt is the format the cell at a infers: a formula's or a spilled91// cell's.92func (st *cellStore) autoAt(a Addr) Format {93 b, i := st.find(a)94 if b == nil {95 return Format{}96 }97 if sl := b.vals[i]; sl.kind == slotRich {98 return st.rich[sl.ref].c.auto99 } else {100 return st.lookOf(sl).auto101 }102}103104// setSpilled makes the cell at a, blank, formatting only or spilled, a105// spilled cell showing v with the inferred format auto, keeping its106// formatting, straight in its slot. It reports false, changing nothing,107// for a cell a slot can't hold (one with a note), which the caller108// stores as a Cell.109func (st *cellStore) setSpilled(a Addr, v Value, auto Format) bool {110 b, i := st.find(a)111 var old slot112 if b != nil {113 old = b.vals[i]114 }115 if old.kind == slotRich {116 return false117 }118 lk := old.look119 if l := st.lookOf(old); l.auto != auto {120 var ok bool121 if lk, ok = st.lookID(look{l.f, l.st, auto}); !ok {122 return false123 }124 }125 if b == nil {126 b = st.stored.mark(a)127 i, _ = b.index(a.Row & (blockRows - 1))128 b.vals = slices.Insert(b.vals, i, slot{kind: slotBlank})129 }130 st.countPivot(a, st.isPivot(old), false)131 sl := st.derivedValue(v, lk, false) // before releasing old, which may share its string132 st.releaseSlot(old)133 b.vals[i] = sl134 st.filledAs(a, st.filled.has(a), !derivedBlank(v))135 st.touch(a)136 return true137}138139// derivedBlank reports whether a derived cell showing v is blank: its140// entry, the value's text, is empty.141func derivedBlank(v Value) bool {142 return v.Kind == Empty || v.Kind == Text && v.Str == ""143}