cat / 012
clone

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

main
012 / internal / headless / runcell.go
runcell.go 1.8K
1package headless23import (4 "context"5 "fmt"67 "src.rest/cat/012/internal/notebook"8 "src.rest/cat/012/internal/sheet"9)1011// CellRun is what running a notebook cell gave: its state, its output12// as NUON (cut at maxShownOutput), or why it failed.13type CellRun struct {14 Notebook string `json:"notebook"`15 Cell int `json:"cell"`16 Name string `json:"name"`17 State string `json:"state"` // "ran" or "failed"18 Error string `json:"error"`19 Output string `json:"output"` // NUON20 Cut bool `json:"cut"` // Output was longer and is cut21}2223// maxShownOutput is the most of an output CellRun returns.24const maxShownOutput = 64 << 102526// RunCell runs cell n (1 for the first) of the notebook tab named, as27// Run does on the screen: its output replaces the one kept and goes on28// to the sheet it was sent to. Whether it may run at all (trust, the29// shell setting) is the caller's to decide first.30func RunCell(ctx context.Context, w *sheet.Workbook, name string, n int, o NotebookOptions) (CellRun, error) {31 s := w.Lookup(name)32 if s == nil || !s.IsNotebook() {33 return CellRun{}, fmt.Errorf("no notebook named %q", name)34 }35 cells := s.NotebookCells()36 if n < 1 || n > len(cells) {37 return CellRun{}, fmt.Errorf("%s has %d cells: cell %d isn't one", name, len(cells), n)38 }39 c := cells[n-1]40 if c.Kind != notebook.Code {41 return CellRun{}, fmt.Errorf("%s cell %d is a note, which doesn't run", name, n)42 }43 out := CellRun{Notebook: s.Name(), Cell: n, Name: c.Name(), State: "ran"}44 if err := runCell(ctx, w, cells, n-1, 1, o); err != nil {45 out.State, out.Error = "failed", err.Error()46 return out, nil47 }48 if res := w.Output(c.ID); res != nil {49 out.Output = string(res.NUON)50 if len(out.Output) > maxShownOutput {51 out.Output, out.Cut = out.Output[:maxShownOutput], true52 }53 }54 return out, nil55}