cat / 012
clone

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

Recompute a pivot when a cell in its way is cleared

Dami committed fbc938e
A pivot whose results would overwrite a typed cell shows #REF!; it now
remembers where its results would go, so clearing that cell makes room
again. A test reads the file example in docs/files.md.
commit
fbc938eff37337fbc4dd0506e41cc9743c914e9f
parent
5919132da81eacdbb4a9036992d40589eebd8307
author
Dami <dami.etoile@gmail.com>
4 files changed, +45 -7
Minternal/sheet/pivot.go3+++
Minternal/sheet/pivot_test.go26++++++++++++++++++++++++++
Minternal/sheet/pivotlayout.go21+++++++++++++++------
Minternal/sheet/sheet.go2+-
M internal/sheet/pivot.go +3 -0
M internal/sheet/pivot_test.go +26 -0
@@ -334,6 +334,12 @@ func TestPivotRefusesEdits(t *testing.T) {
334334 if got := show(t, w, "'Pivot Table 1'!A6"); got != "note" {335335 t.Errorf("A6 = %q, want the note kept", got)336336 }337+ // Clearing the note makes room again.338+ if err := s.Set(at("A6"), ""); err != nil {339+ t.Fatal(err)340+ }341+ checkGrid(t, s, "Region|SUM of Units", "East|16", "North|0", "South|0", "West|7", "Grand Total|23")342+ w.Undo()337343 // Copying results pastes their values.338344 w.Undo()339345 w.Undo()
@@ -444,6 +450,26 @@ func TestPivotFileRoundTrip(t *testing.T) {
444450 }445451 }446452 453+// The example in docs/files.md reads.454+func TestPivotFileExample(t *testing.T) {455+ file := `{"version": 5, "sheets": [456+ {"name": "Sales", "cells": {"A1": "Region", "B1": "Item", "C1": "Year", "D1": "Units", "A2": "East", "B2": "Pens", "C2": "2026", "D2": "3"}},457+ {"name": "Pivot Table 1", "cells": {},458+ "pivot": {"source":"Sales!A1:D200","rows":[{"column":"B"},{"column":"A","order":"desc","sortBy":1}],"columns":[{"column":"C"}],"values":[{"column":"D","summarize":"sum"},{"column":"D","summarize":"counta","showAs":"percent_of_total","name":"Share"}],"filters":[{"column":"A","hidden":["North"]}],"rowTotals":true,"columnTotals":false}}459+ ]}`460+ w, err := ReadBook(strings.NewReader(file))461+ if err != nil {462+ t.Fatal(err)463+ }464+ s := w.Lookup("Pivot Table 1")465+ checkGrid(t, s,466+ "|Year|2026",467+ "Item|Region|SUM of Units|Share",468+ "Pens|East|3|100.00%",469+ "Pens Total||3|100.00%",470+ "Grand Total||3|100.00%")471+}472+447473 func TestPivotDuplicate(t *testing.T) {448474 w := sales(t)449475 s := newPivot(t, w, func(p *Pivot) { p.Rows = []PivotGroup{{Col: 1}} })
M internal/sheet/pivotlayout.go +15 -6
@@ -268,18 +268,18 @@ func (w *Workbook) refreshPivot(s *Sheet) []loc {
268268 }269269 s.pivot.stale = false270270 want, calc, err := w.computePivot(s)271- s.pivot.err = ""271+ s.pivot.err, s.pivot.blocked = "", Rect{}272272 if err != nil {273+ // Where the results would go, so clearing a cell in their way274+ // has the pivot try again.275+ s.pivot.blocked = extent(want)273276 s.pivot.err = err.Error()274277 want = []pivotCell{{v: ErrRef, bold: true}}275278 if c := s.cells.get(Addr{}); c != nil && !c.derived && !c.Blank() {276279 want = nil // never write over what the user typed277280 }278281 }279- s.pivot.out = Rect{}280- for _, pc := range want {281- s.pivot.out = union(s.pivot.out, Rect{From: pc.a, To: pc.a})282- }282+ s.pivot.out = extent(want)283283 changed := s.writeDerived(want)284284 if s.pivot.fit {285285 s.fitPivot(want)
@@ -294,6 +294,15 @@ func (w *Workbook) refreshPivot(s *Sheet) []loc {
294294 return changed295295 }296296 297+// extent is the range from A1 covering cells.298+func extent(cells []pivotCell) Rect {299+ r := Rect{}300+ for _, pc := range cells {301+ r = union(r, Rect{From: pc.a, To: pc.a})302+ }303+ return r304+}305+297306 // groups counts the groups of the row fields, at every depth.298307 func (c *pivotCalc) groups() int {299308 n := 0
@@ -336,7 +345,7 @@ func (w *Workbook) computePivot(s *Sheet) ([]pivotCell, *pivotCalc, error) {
336345 }337346 for _, pc := range l.cells {338347 if old := s.cells.get(pc.a); old != nil && !old.derived && !old.Blank() {339- return nil, c, fmt.Errorf("The pivot table's results would overwrite data in %s", pc.a)348+ return l.cells, c, fmt.Errorf("The pivot table's results would overwrite data in %s", pc.a)340349 }341350 }342351 return l.cells, c, nil
M internal/sheet/sheet.go +1 -1