cat / 012
clone

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

main
012 / internal / sheet / sourceread.go
sourceread.go 4.3K
1package sheet23import "src.rest/cat/012/internal/functions"45// How the engine's reader reads a linked source's tab (source.go),6// which holds no cells: its header row from what the host found, and7// every other cell from the host (sourceask.go). A function given a8// source's range is asked whole (functions.StreamCall); what reads a9// range some other way (an operator over it, a function whose other10// arguments are arrays) is given its values read whole, as long as the11// host's budget allows.1213// pagedRegion is the paged region of t, if t is a source's tab.14func (t *Sheet) pagedRegion() (Region, bool) {15 for _, r := range t.regions.list {16 if r.File.Paged {17 return r, true18 }19 }20 return Region{}, false21}2223// notOpen is what a source's cells read before its host has opened it:24// Loading…, or #REF! when it can't.25func (t *Sheet) notOpen(r Region) Value {26 if t.sourceErr(r) != "" {27 return ErrRef28 }29 return Pending30}3132// pagedCell is the value of the cell at a of t, the tab of the source33// r: a column's name in the header row, or what the host answers.34func (rd *reader) pagedCell(t *Sheet, r Region, a Addr) Value {35 tbl, shape, ok := t.sourceTable(r)36 switch {37 case !ok:38 if l := rd.w.evaluating; l.s != nil {39 addLoc(&rd.w.src.users, nameKey(r.Name), l)40 }41 return t.notOpen(r)42 case !tbl.Contains(a):43 return Value{}44 case a.Row == 0:45 return Value{Kind: Text, Str: shape.Cols[a.Col]}46 }47 ans, ok := rd.w.ask(SourceQuestion{Kind: AskCell, Source: r.Name, At: a})48 if !ok {49 return Pending50 }51 return ans.V52}5354// pagedRange is the part of r on t, the tab of the source reg, that its55// table holds, and its values as an array: nil with an error when they56// can't be had (yet), nil without one when the part is empty.57func (rd *reader) pagedRange(t *Sheet, reg Region, r Rect) (Rect, *functions.Array, *Value) {58 tbl, _, ok := t.sourceTable(reg)59 if !ok {60 v := t.notOpen(reg)61 return Rect{}, nil, &v62 }63 part, ok := intersectRect(tbl, r)64 if !ok {65 return Rect{}, nil, nil66 }67 ans, known := rd.w.ask(SourceQuestion{Kind: AskRange, Source: reg.Name, R: part})68 switch {69 case !known:70 return Rect{}, nil, &Pending71 case ans.A == nil:72 v := ans.V73 if v.Kind != Error {74 v = ErrValue75 }76 return Rect{}, nil, &v77 }78 return part, ans.A, nil79}8081// pagedScan is Scan over a source's tab: the cells of r holding82// something, from from on, read from the range's values.83func (rd *reader) pagedScan(t *Sheet, reg Region, r Rect, from Addr, addrs []Addr, vals []Value) int {84 part, arr, err := rd.pagedRange(t, reg, r)85 if err != nil {86 if len(addrs) == 0 || from != r.From {87 return 0 // the error was the range's first cell88 }89 addrs[0] = r.From90 if vals != nil {91 vals[0] = *err92 }93 return 194 }95 if arr == nil {96 return 097 }98 if from.Row < part.From.Row {99 from = part.From100 }101 n := 0102 for row := from.Row; row <= part.To.Row && n < len(addrs); row++ {103 col := part.From.Col104 if row == from.Row {105 col = max(col, from.Col)106 }107 for ; col <= part.To.Col && n < len(addrs); col++ {108 v := arr.At(row-part.From.Row, col-part.From.Col)109 if v.Kind == Empty {110 continue111 }112 addrs[n] = Addr{Col: col, Row: row}113 if vals != nil {114 vals[n] = v115 if v.Kind == Error {116 return n + 1117 }118 }119 n++120 }121 }122 return n123}124125// pagedFold is Fold over a source's tab.126func (rd *reader) pagedFold(t *Sheet, reg Region, r Rect, s functions.Agg) (functions.Agg, *Value) {127 part, arr, err := rd.pagedRange(t, reg, r)128 if err != nil {129 return s, s.Add(*err, false)130 }131 if arr == nil {132 return s, nil133 }134 for i := range part.To.Row - part.From.Row + 1 {135 for j := range part.To.Col - part.From.Col + 1 {136 if v := arr.At(i, j); v.Kind != Empty {137 if e := s.Add(v, false); e != nil {138 return s, e139 }140 }141 }142 }143 return s, nil144}145146// sourceFormat is the format the cell at a of t, the tab of the source147// reg, shows in: its column's, as the source's type says, below the148// header.149func (t *Sheet) sourceFormat(reg Region, a Addr) Format {150 tbl, shape, ok := t.sourceTable(reg)151 if !ok || a.Row == 0 || !tbl.Contains(a) || a.Col >= len(shape.Formats) {152 return Format{}153 }154 return shape.Formats[a.Col]155}156157// pagedBounds is Bounds over a source's tab: the part of r its table158// holds.159func (t *Sheet) pagedBounds(reg Region, r Rect) (Rect, bool) {160 tbl, _, ok := t.sourceTable(reg)161 if !ok {162 return Rect{}, false163 }164 return intersectRect(tbl, r)165}