Documentation
¶
Overview ¶
Package tsvsheet is the engine for the tsvsheet single-file spreadsheet: a .tsvt is a single TAB-separated grid whose cells are literal values or =formulas that address other cells in A1 notation (B2, D2:D5), computed in place.
The package parses a grid (Parse, ReadTSV), computes it with an Excel- and Google-Sheets-faithful expression evaluator that carries error values (#REF!, #DIV/0!, #CIRC!, …) through a dependency-ordered, memoized pass (Compute, ComputeWith), and inspects the result (Check diagnostics, Explain traces) before rendering it back to TSV (WriteTSV). A bare expression — the text after a formula cell's `=` — also compiles standalone (CompileExpr) into an immutable Expr that evaluates against any Grid with formula-cell semantics (Expr.Eval) and formats canonically (FormatValue). Formula compilation reuses the grammar repo's ANTLR-generated expression parser through the internal/tsvt seam; no ANTLR type escapes into the public surface.
The engine is filesystem- and network-free by construction: cross-sheet embedding (SHEET/INPUT/OUTPUT) and imports (IMPORT*) resolve only through the Loader and Fetcher a caller injects, and every allocation is bounded by an injected Limits ceiling. Errors returned to callers are the errs.Const sentinels re-exported from errors.go, matchable with errors.Is.
This package is a thin facade: every type, function, and constant it exposes re-exports the implementation in internal/engine unchanged, so the public surface is documented here while the engine stays an internal package.
Package tsvsheet's document facade: a parsed .tsvt with its physical line layout retained, and the view its own directives declare.
The sheet edit language facade (work order 011): parse an edits document, content-address a document, and apply the deterministic fold.
Package tsvsheet's expression facade: one compiled bare expression, detached from any sheet.
Index ¶
- Constants
- func FormatValue(v Value) string
- func IsCommentLine(at LineNumber, text SourceLine) bool
- func OpenSheet(src ByteSource, limits Limits) (Sheet, *WindowedSheet, error)
- func WriteTSV(w io.Writer, g Grid) error
- type Address
- type AddressText
- type BlockText
- type ByteSource
- type CellInfo
- type ComputeOptions
- type Diagnostic
- type Directive
- type Document
- type Edits
- type ErrorValue
- type Expr
- type Extent
- type FetchResult
- type Fetcher
- type Grid
- type ImportURL
- type Key
- type Limits
- type LineNumber
- type Loader
- type MediaType
- type Path
- type RevisionHex
- type Selection
- type Sheet
- type SheetCensus
- type SourceLine
- type Span
- type Tick
- type Trace
- type TraceImport
- type TraceInput
- type Value
- type View
- type WindowedSheet
Examples ¶
Constants ¶
const ( ErrSyntax = constants.ErrSyntax ErrDocTooLarge = constants.ErrDocTooLarge ErrInvalidValue = constants.ErrInvalidValue ErrNotFound = constants.ErrNotFound ErrReadInput = constants.ErrReadInput ErrWriteFile = constants.ErrWriteFile ErrEditsAddress = constants.ErrEditsAddress ErrEditsApply = constants.ErrEditsApply ErrEditsArity = constants.ErrEditsArity ErrEditsBase = constants.ErrEditsBase ErrEditsBlock = constants.ErrEditsBlock ErrEditsOp = constants.ErrEditsOp )
Engine error sentinels returned to callers, matchable with errors.Is.
const ( KeyHide = engine.KeyHide KeyHeader = engine.KeyHeader KeyFreeze = engine.KeyFreeze )
The view-directive keys, one per class — a projection, a structure declaration, and a viewport hint.
Variables ¶
This section is empty.
Functions ¶
func FormatValue ¶ added in v0.5.0
FormatValue is the canonical computed-cell text for v — byte-identical to what WriteTSV emits for that value in a computed grid. A 2-D array value reduces to its scalar-context (top-left) value before formatting.
func IsCommentLine ¶ added in v0.14.0
func IsCommentLine(at LineNumber, text SourceLine) bool
IsCommentLine reports whether the line at 1-based position at is one the grid skips rather than treating as a row: a first-line `#!` shebang, a `#.` directive-or-comment line, or a legacy `# ` hash-space comment. Everything else is data, including `#N/A` and a hash followed by a TAB.
Frontends that map document lines to grid rows — an LSP, an editor gutter — call this instead of testing the prefixes themselves, so the language has one definition of what a comment is.
func OpenSheet ¶ added in v0.27.3
func OpenSheet(src ByteSource, limits Limits) (Sheet, *WindowedSheet, error)
OpenSheet loads a source of any size under limits: one scan builds the census, and the resident cell budget decides the capability — at or under it, a fully resident Sheet identical to Parse's; over it, a WindowedSheet serving bounded viewport reads while the source stays on disk (SPECIFICATION §6 budgets; raise the budget to make any size resident).
Types ¶
type Address ¶
Address is a cell coordinate in spreadsheet notation (`F4`): column letters plus a 1-based row. It carries 0-based indices internally.
func ParseAddress ¶
func ParseAddress(s AddressText) (Address, error)
ParseAddress parses spreadsheet notation (`A1`, `F4`, `AA10`) into an Address. The column is one or more ASCII uppercase letters, the row a positive integer; anything else is constants.ErrInvalidValue.
type AddressText ¶
type AddressText = engine.AddressText
AddressText is spreadsheet-address source text (`A1`, `F4`) accepted by ParseAddress. It is exported so callers in other packages can convert their string input at the call site.
type BlockText ¶ added in v0.24.0
BlockText is clipboard-block source text: TAB-separated cells on newline-separated rows, as a copied range travels through a clipboard.
type ByteSource ¶ added in v0.27.3
type ByteSource = engine.ByteSource
ByteSource is an any-size byte source — a file, a spooled stream, or in-memory bytes — with its length.
type CellInfo ¶
CellInfo describes one non-empty cell: its address, source text, and whether it is a formula — the projection the parse command emits.
type ComputeOptions ¶
type ComputeOptions = engine.ComputeOptions
ComputeOptions configures a compute pass. Loader and Base enable embedded sub-sheets; a zero Loader disables SHEET (it resolves to #REF!). Tick is the recompute-pass ordinal a refreshing frontend increments so TICK()/FRAME() advance across passes.
type Diagnostic ¶
type Diagnostic = engine.Diagnostic
Diagnostic is an advisory finding about a sheet: an unknown function call in a formula cell (which computes to #NAME?), or a view directive the parser rejects. A cell finding carries Cell; a directive finding carries Line, since a directive occupies a physical line and no grid row.
func Check ¶
func Check(s Sheet) []Diagnostic
Check reports the static diagnostics of a parsed sheet: each unknown function call. Syntax errors are already rejected by Parse, and every reference the narrowed grammar admits is a valid A1 form, so Check never reports those.
Example ¶
Check reports static diagnostics — unknown functions, provable arity errors, non-A1 references — without computing.
package main
import (
"fmt"
tsvsheet "github.com/tsvsheet/go-tsvsheet"
)
func main() {
sheet, _ := tsvsheet.Parse([]byte("=BOGUS(1)\n"))
for _, d := range tsvsheet.Check(sheet) {
fmt.Printf("%s: %s\n", d.Cell, d.Message)
}
}
Output: A1: unknown function: BOGUS
type Directive ¶ added in v0.20.0
Directive is one key/value pair read from a `#.` line, with the physical line it came from.
type Document ¶ added in v0.6.0
Document is a parsed .tsvt file with its physical line layout retained, so comment and shebang lines — which the grid drops — survive editing and are written back in position by Text. Document is immutable: every editing operation returns a new Document. It is the one sanctioned way to serialize a .tsvt; frontends must never rebuild a file from a grid.
func Apply ¶ added in v0.25.0
Apply left-folds e's ops over d: atomic (a refused op rejects the whole batch), base-checked (ErrEditsBase when e names a revision that is not d's), and deterministic — nothing outside (d, e, limits) influences the result.
func ParseDocument ¶ added in v0.6.0
ParseDocument reads a .tsvt file like Parse, additionally recording the physical line layout so comment and shebang lines are preserved by Text.
type Edits ¶ added in v0.25.0
Edits is a parsed edits document (application/vnd.tsvsheet.edits+tsv): a TSV stream of semantic operations. Immutable; Text returns the exact bytes parsed.
func ParseEdits ¶ added in v0.25.0
ParseEdits reads an edits document; any malformed line is a specific ErrEdits* sentinel carrying its 1-based line number.
func ParseEditsWith ¶ added in v0.27.5
ParseEditsWith is ParseEdits under a residency budget (spec 018): a batch whose line count (each line is at most one op) exceeds the effective resident ceiling refuses with ErrDocTooLarge before any op parses.
type ErrorValue ¶
type ErrorValue = engine.ErrorValue
ErrorValue is a spreadsheet error value — a cell value, not a Go error. It propagates through expressions per ADR 0003 (rules 3, 8, 12, 14).
const ( ErrRef ErrorValue = engine.ErrRef ErrValue ErrorValue = engine.ErrValue ErrName ErrorValue = engine.ErrName ErrDiv ErrorValue = engine.ErrDiv ErrCirc ErrorValue = engine.ErrCirc ErrNA ErrorValue = engine.ErrNA ErrNum ErrorValue = engine.ErrNum ErrNull ErrorValue = engine.ErrNull ErrSpill ErrorValue = engine.ErrSpill ErrImport ErrorValue = engine.ErrImport ErrLimit ErrorValue = engine.ErrLimit )
The error values. #REF! (out-of-grid), #VALUE! (type), #NAME? (unknown function), #DIV/0! (division by zero), #CIRC! (a formula whose evaluation depends on itself), #N/A (lookup miss / NA()), #NUM! (numeric domain), #NULL! (empty range intersection), #SPILL! (blocked dynamic-array spill), #IMPORT! (a content-typed import failed — disabled, denied, or a bad handshake), #LIMIT! (a reference or result larger than the configured cell budget).
type Expr ¶ added in v0.5.0
Expr is one compiled bare expression — the text that would follow `=` in a formula cell — detached from any sheet: compile once with CompileExpr, then evaluate against any number of grids, including concurrently.
func CompileExpr ¶ added in v0.5.0
CompileExpr parses and compiles one bare expression — the text that would follow `=` in a formula cell. A malformed expression is ErrSyntax carrying line/column detail via With. The compiled Expr is an immutable value, safe for concurrent reuse; its Eval(g, opts) evaluates against a Grid with the exact semantics of a formula cell in a sheet over that grid — reference resolution, literal coercion, ranges, dynamic arrays, error-value propagation, volatile functions from opts.At, Limits enforcement, and Loader/Fetcher gating — returning error values, never Go errors.
type Extent ¶ added in v0.20.0
Extent is a grid's size in rows and columns; edge-anchored directive items resolve against it.
type FetchResult ¶
type FetchResult = engine.FetchResult
FetchResult is a Fetcher's response: the raw body and the media type the server declared, which must match the requested Accept for the handshake to succeed (ADR 0006 §2).
type Fetcher ¶
Fetcher retrieves the content-typed import at url, sending accept as the requested media type. The engine holds only this interface; the concrete net/http fetcher, allowlist, and caching are injected by a frontend. A nil Fetcher disables imports (every IMPORT* is #IMPORT!).
Example ¶
The engine is network-free: IMPORT* cells resolve only through a Fetcher injected via ComputeOptions. With none, they are #IMPORT!; with one, they resolve to the fetched value.
package main
import (
"fmt"
tsvsheet "github.com/tsvsheet/go-tsvsheet"
)
// stubFetcher is a trivial Fetcher for the example below: it answers every
// request with the value 42, echoing the requested media type so the handshake
// succeeds.
type stubFetcher struct{}
func (stubFetcher) Fetch(_ tsvsheet.ImportURL, accept tsvsheet.MediaType) (tsvsheet.FetchResult, error) {
return tsvsheet.FetchResult{ContentType: accept, Body: []byte("42")}, nil
}
func main() {
sheet, _ := tsvsheet.Parse([]byte(`=IMPORTCELL("https://example/v")` + "\n"))
fmt.Println(sheet.Compute()[0][0])
fmt.Println(sheet.ComputeWith(tsvsheet.ComputeOptions{Fetcher: stubFetcher{}})[0][0])
}
Output: #IMPORT! 42
type Grid ¶
Grid is a rectangular value grid indexed [row][col], 0-based. Cells are raw strings: a literal's own text on input, or a formula cell's computed value after ComputeAt.
func ParseBlock ¶ added in v0.24.0
ParseBlock reads a clipboard block: CRLF and lone CR normalize to LF, exactly one trailing newline is ignored, rows split on LF and cells on TAB. Every line is data — a clipboard block has no comment or directive semantics, unlike a .tsvt file — so this is the one definition every frontend uses to turn pasted text back into a grid for Document.Paste. An empty text decodes to a single empty cell (its exact TSV serialization), which is how a paste clears one cell.
func ReadTSV ¶
ReadTSV reads a tab-separated value grid. Rows are newline-separated; a trailing newline does not add an empty row. Full-line comments are skipped and do not occupy a grid row, per IsCommentLine: a leading `#!` on the first line (a shebang, so a .tsvt can be `chmod +x` and run via `#!/usr/bin/env tsvsheet`), any `#.` directive-or-comment line, and any legacy `# ` hash-space line. An error-value cell like `#N/A` is data, not a comment. A read failure surfaces as ErrReadInput.
type ImportURL ¶
ImportURL is the location an IMPORT* function fetches — the (already evaluated) string value of its single argument.
type Limits ¶
Limits bounds the sizes an untrusted sheet may drive an allocation to.
func BrowserLimits ¶
func BrowserLimits() Limits
BrowserLimits are the tighter ceilings the WASM build applies, sized for a browser tab rather than a workstation.
func DefaultLimits ¶
func DefaultLimits() Limits
DefaultLimits are generous for real spreadsheets while still bounding OOM.
type LineNumber ¶ added in v0.14.0
type LineNumber = engine.LineNumber
LineNumber is a 1-based physical line position in a .tsvt source file, as opposed to a grid row: comment lines occupy a line but no row.
type Loader ¶
Loader resolves the sheet referenced by ref, relative to the embedding sheet's own path base, returning the parsed sub-sheet and its resolved path (used for cycle detection and as the base for the sub-sheet's own SHEET calls). The frontend injects it, keeping the engine filesystem-free; a resolution or containment failure is reported as an error and surfaces as #REF!.
type MediaType ¶
MediaType is a content-typed import's RFC 6838 media type — the Accept header an IMPORT* function requests, which the response Content-Type must match.
type Path ¶
Path identifies a sheet to a Loader: the reference written in a SHEET(...) call, and (as the loader's result) the sheet's own resolved path.
type RevisionHex ¶ added in v0.25.0
type RevisionHex = engine.RevisionHex
RevisionHex is a document's content address: the lowercase-hex SHA-256 of its canonical Text bytes. Equal revision ⇔ byte-equal document.
func Revision ¶ added in v0.25.0
func Revision(d Document) RevisionHex
Revision content-addresses d.
type Sheet ¶
Sheet is a parsed spreadsheet grid of literal and formula cells.
func Parse ¶
Parse reads a .tsvt grid: each TAB-separated field is a literal, or — when it begins with `=` — a formula compiled from the expression that follows. A malformed formula is a syntax error naming its cell.
Example ¶
Parse compiles a .tsvt grid; Compute evaluates every =formula in dependency order and returns the value grid ([][]string), literals passing through.
package main
import (
"fmt"
tsvsheet "github.com/tsvsheet/go-tsvsheet"
)
func main() {
sheet, err := tsvsheet.Parse([]byte("2\t3\n=A1*B1\t=A1+B1\n"))
if err != nil {
fmt.Println(err)
return
}
grid := sheet.Compute()
fmt.Println(grid[1][0], grid[1][1])
}
Output: 6 5
Example (ErrorValues) ¶
A cell that fails to evaluate carries a spreadsheet error value, which propagates through the formulas that read it — it is data, not a Go error.
package main
import (
"fmt"
tsvsheet "github.com/tsvsheet/go-tsvsheet"
)
func main() {
sheet, _ := tsvsheet.Parse([]byte("=1/0\t=A1+1\n"))
grid := sheet.Compute()
fmt.Println(grid[0][0], grid[0][1])
}
Output: #DIV/0! #DIV/0!
Example (SyntaxError) ¶
A malformed formula is reported as ErrSyntax, matchable with errors.Is.
package main
import (
"fmt"
tsvsheet "github.com/tsvsheet/go-tsvsheet"
)
func main() {
_, err := tsvsheet.Parse([]byte("=1 +\n"))
fmt.Println(err != nil)
}
Output: true
func ParseWith ¶ added in v0.27.4
ParseWith is Parse under a residency budget (spec 018): a document whose census exceeds Limits.ResidentCells (single-ceiling fallback like its siblings) refuses with ErrDocTooLarge before anything materializes; an in-budget document parses identically to Parse (FuzzParseWith is the parity oracle). Parse stays unbounded for embedders that pre-vet their sources.
type SheetCensus ¶ added in v0.27.3
type SheetCensus = engine.SheetCensus
SheetCensus is what one open-time scan learned about a document.
func Census ¶ added in v0.27.5
func Census(src ByteSource) (SheetCensus, error)
Census reports a source's totals from one index scan — O(index) memory, nothing materialized: the cheap pre-flight a frontend runs to decide or refuse before buffering or parsing anything (spec 018).
type SourceLine ¶ added in v0.14.0
type SourceLine = engine.SourceLine
SourceLine is one physical line of .tsvt source, newline already stripped.
type Span ¶
Span is a rectangular reference target resolved to 0-based addresses: a single cell (From == To) or a range (From is the top-left, To the bottom-right as written). It is the projection a frontend highlights.
type Tick ¶ added in v0.10.0
Tick is a recompute-pass ordinal read by TICK()/FRAME(); a frontend that re-renders a volatile sheet passes an incrementing value each pass.
type Trace ¶
Trace explains how one cell was produced: its value, the formula (empty for a literal), and the resolved value of each cell the formula reads.
func Explain ¶
Explain computes the sheet and describes the cell at at: its value, and — when the cell is a formula — that formula and each reference it reads. Imports and embedded sheets are disabled on this path; use ExplainWith to trace a sheet that uses them.
Example ¶
Explain traces how a cell was produced: its value, formula, and the inputs the formula read.
package main
import (
"fmt"
tsvsheet "github.com/tsvsheet/go-tsvsheet"
)
func main() {
sheet, _ := tsvsheet.Parse([]byte("2\t3\n=A1+B1\t\n"))
trace, _ := tsvsheet.Explain(sheet, tsvsheet.Address{Row: 1, Col: 0})
fmt.Printf("%s = %s (from %s, %d inputs)\n", trace.Cell, trace.Value, trace.Formula, len(trace.Inputs))
}
Output: A2 = 5 (from A1 + B1, 2 inputs)
func ExplainWith ¶ added in v0.22.0
func ExplainWith(s Sheet, at Address, opts ComputeOptions) (Trace, error)
ExplainWith is Explain with an injected compute environment (Loader, Fetcher, Limits), so a sheet whose cells embed sub-sheets or import external data traces with those resolved. The Trace's Imports report where each IMPORT* actually went and why it failed — the only place that is visible, since every import failure is the same opaque #IMPORT! in the grid.
type TraceImport ¶ added in v0.22.0
type TraceImport = engine.TraceImport
TraceImport is one IMPORT* call a traced formula performs: the source the sheet wrote, the URL it resolved to, and the reason it failed.
type TraceInput ¶
type TraceInput = engine.TraceInput
TraceInput is one reference a formula reads, with its resolved value.
type Value ¶
Value is an evaluated cell value: empty, number, string, boolean, date, error, or a 2-D array (a dynamic-array result that spills, or reduces to its top-left value in a scalar context).
type View ¶ added in v0.20.0
View is what a viewport does with a grid, as the sheet's own `#.` directives declare it: which rows and columns are hidden, carry headers, or stay anchored while the rest scrolls. Every field is a set of 1-based positions, resolved against the sheet's extent, so a host renders it without deriving anything itself.
type WindowedSheet ¶ added in v0.27.3
type WindowedSheet = engine.WindowedSheet
WindowedSheet is the over-budget capability: view/compute-only, serving bounded row windows through the index's block cache.
Directories
¶
| Path | Synopsis |
|---|---|
|
Command browser exposes the tsvsheet engine to the browser as a set of STATELESS functions: the caller holds the .tsvt source, and each call parses it, applies one immutable engine operation, and returns the result as a JSON string.
|
Command browser exposes the tsvsheet engine to the browser as a set of STATELESS functions: the caller holds the .tsvt source, and each call parses it, applies one immutable engine operation, and returns the result as a JSON string. |
|
internal
|
|
|
constants
Package constants declares the tsvsheet engine's sentinel error values.
|
Package constants declares the tsvsheet engine's sentinel error values. |
|
engine
Package engine's argument-shaping layer: how a call's operands are reduced to the values a builtin receives — a scalar slot, a flattened range, or the mixed shapes the recurring parameter specs describe.
|
Package engine's argument-shaping layer: how a call's operands are reduced to the values a builtin receives — a scalar slot, a flattened range, or the mixed shapes the recurring parameter specs describe. |
|
index
The reader's block cache: an LRU bounded in cells, block-granular.
|
The reader's block cache: an LRU bounded in cells, block-granular. |
|
tsvt
Package tsvt is the covered seam over the ANTLR-generated formula parser: it turns a cell's formula source (the text after its leading `=`) into an immutable typed AST — an Expr over A1 references and literals — or a sentinel syntax error, and hides every ANTLR type from the rest of the program.
|
Package tsvt is the covered seam over the ANTLR-generated formula parser: it turns a cell's formula source (the text after its leading `=`) into an immutable typed AST — an Expr over A1 references and literals — or a sentinel syntax error, and hides every ANTLR type from the rest of the program. |