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 / paged / job.go
job.go 2.5K
1package paged23import (4 "context"5 "fmt"6 "os"78 "src.rest/cat/012/internal/fileio"9 "src.rest/cat/012/internal/functions"10 "src.rest/cat/012/internal/sheet"11)1213type jobKind uint81415const (16 jobOpen jobKind = iota17 jobAnswer18)1920// A Job is work the host queued: opening a source, or answering a21// question by reading the sources it names. Run it on any goroutine,22// once, then give it back to Host.Store on the owner's.23type Job struct {24 kind jobKind2526 // Opening a source.27 name string28 spec fileio.SourceSpec29 gen int30 open Opener31 h fileio.Source32 shape sheet.SourceShape33 stamp stamp34 err error3536 // Answering a question.37 q sheet.SourceQuestion38 key string39 srcs map[string]snapshot // the sources it reads, by name key40 budget int41 ans sheet.SourceAnswer42}4344// snapshot is a source as a job reads it: opened, with what it is.45type snapshot struct {46 name string47 h fileio.Source48 shape sheet.SourceShape49 gen int50 dir string // where sorting spills, "" for the system's temporary files51}5253// String says what the job does, for telemetry.54func (j *Job) String() string {55 if j.kind == jobOpen {56 return "open " + j.name57 }58 return j.key59}6061// Run does the job.62func (j *Job) Run(ctx context.Context) {63 if j.kind == jobOpen {64 j.runOpen(ctx)65 return66 }67 j.ans = j.answer(ctx)68}6970func (j *Job) runOpen(ctx context.Context) {71 if st, err := os.Stat(j.spec.Path); err == nil {72 j.stamp = stamp{st.Size(), st.ModTime()}73 }74 h, err := j.open(ctx, j.spec)75 if err != nil {76 j.err = err77 return78 }79 j.h, j.shape = h, ShapeOf(h)80}8182// ShapeOf is what the engine keeps of a source.83func ShapeOf(h fileio.Source) sheet.SourceShape {84 cols := h.Columns()85 sh := sheet.SourceShape{Rows: int(h.Rows())}86 for _, c := range cols {87 sh.Cols = append(sh.Cols, c.Name)88 sh.Formats = append(sh.Formats, c.Format)89 sh.Numeric = append(sh.Numeric, c.Numeric)90 }91 return sh92}9394// answer works out the job's question.95func (j *Job) answer(ctx context.Context) sheet.SourceAnswer {96 b := &book{ctx: ctx, srcs: j.srcs}97 defer b.close()98 var ans sheet.SourceAnswer99 switch j.q.Kind {100 case sheet.AskCell:101 ans.V = b.Cell(j.q.Source, j.q.At)102 case sheet.AskRange:103 ans = b.rangeValues(j.q.Source, j.q.R, j.budget)104 case sheet.AskCall:105 sa := functions.EvalStream(j.q.Call, b, j.budget)106 ans = sheet.SourceAnswer{V: sa.V, A: sa.A, Why: sa.Why}107 case sheet.AskPivot:108 ans = b.pivot(j.q.Source, j.q.Pivot)109 }110 if b.err != nil {111 return sheet.SourceAnswer{V: sheet.ErrRef, Why: fmt.Sprintf("%s: %s", j.q.Source, describe(b.err))}112 }113 return ans114}