Documentation
¶
Overview ¶
Package table renders typed iterators of struct values as styled CLI tables.
Each column is derived by reflection from an exported struct field of the type parameter T: the header from the field's name (CamelCase split and uppercased, or overridden via a `table:"NAME"` struct tag), and the cell formatter from the field's type. Numeric fields are right-aligned; time.Time and time.Duration get dedicated human-friendly formats; any type implementing encoding.TextMarshaler, fmt.Formatter, or fmt.Stringer is honoured. Tag modifiers (`table:",bytes"`, `table:",%"`, `table:",%%"`) pin a specific formatter and alignment for cases the type system can't infer.
The API mirrors what callers usually want: Write for streaming an iter.Seq2 of values + errors to an io.Writer, Format for a quick string, and NewWriter / NewFormatter for the precomputed-schema forms used in hot loops.
Index ¶
- func Format[T any](seq iter.Seq[T], opts ...Option) string
- func Write[T any](w io.Writer, seq iter.Seq2[T, error], opts ...Option) error
- type Column
- type Formatter
- type Option
- func WithBorder(b lipgloss.Border) Option
- func WithColumnStyle(fn func(col int, val string) lipgloss.Style) Option
- func WithColumns(cols ...Column) Option
- func WithHeaderStyle(fn func(col int, val string) lipgloss.Style) Option
- func WithHeaders(names ...string) Option
- func WithNow(now func() time.Time) Option
- func WithRowSelector(fn func(row int) bool) Option
- func WithRowStyle(fn func(row int) lipgloss.Style) Option
- func WithSelectedIndicator(s string) Option
- func WithStyles(s *stripes.Styles) Option
- func WithViewport(height, top int) Option
- type Options
- type Writer
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Column ¶
type Column struct {
// Header is the column heading. It is rendered as-is; no case
// transformation is applied (unlike struct-field-derived headers).
Header string
// Modifier optionally pins a formatter, mirroring the struct-tag
// modifiers: "bytes", "count", "{min}-{max}%" (e.g. "0-100%" identity,
// "0-1%" ratio-to-percent), or "" to use the element type's default
// formatter.
Modifier string
// Suffix is appended to every non-empty formatted cell, mirroring the
// optional literal suffix in struct tags (e.g. `table:",count,/s"`).
// Empty cells are left empty so column alignment is preserved.
Suffix string
}
Column describes one column when the row type isn't a struct. Each non-struct row (e.g. []string, []float64, []any) needs the caller to provide the column count and headers up front; cell formatters are otherwise derived from the element type or — for []any — from the dynamic type of each cell.
type Formatter ¶
Formatter renders an iter.Seq of T-values into a string.
func NewFormatter ¶
NewFormatter precomputes the column schema for T and returns a Formatter that reuses it across calls. If the schema is invalid (non-struct T, unknown tag modifier, ...), the error message is returned as the table body — the Formatter signature has no other channel.
type Option ¶
type Option func(*Options)
Option configures Options.
func WithBorder ¶
WithBorder enables a border around and within the table using the supplied lipgloss.Border (e.g. lipgloss.NormalBorder(), lipgloss.RoundedBorder()). Tables are borderless by default.
func WithColumnStyle ¶
WithColumnStyle registers a per-cell style callback for data rows. fn is invoked for every data cell with its zero-based column index and rendered text; the returned style composes with Styles.Rows (and any RowStyle) via Inherit, so fields the caller sets win and unset fields fall back to the defaults.
func WithColumns ¶
WithColumns sets explicit column metadata, required when the row type T is a slice or array (untyped rows). It is rejected at schema-build time when T is a struct.
func WithHeaderStyle ¶
WithHeaderStyle registers a per-cell style callback for header cells. fn is invoked for every header cell with its zero-based column index and header text; the returned style composes with Styles.Columns via Inherit.
func WithHeaders ¶
WithHeaders is sugar for WithColumns when only headers are needed — every cell's formatter is then derived from the row element type.
func WithNow ¶
WithNow enables relative-time rendering for time.Time fields, using the supplied clock as "now". Pass time.Now in production; pin a fixed time.Time in tests.
func WithRowSelector ¶
WithRowSelector sets the row-selection predicate. When non-nil it enables the one-cell left gutter: matching rows render the indicator (default "❯", overridable via WithSelectedIndicator), the header and non-matching rows render a single space.
The `row` argument is the absolute index into the input sequence, unaffected by WithViewport's top offset. Compose multiple conditions inside the predicate when needed.
func WithRowStyle ¶
WithRowStyle registers a per-row style callback. fn is invoked once per data row with its zero-based index (the header is not counted); the returned style composes with Styles.Rows via Inherit and runs before any ColumnStyle.
func WithSelectedIndicator ¶
WithSelectedIndicator sets the gutter glyph for rows matched by the WithRowSelector predicate. Defaults to "❯". Must be a single visual cell (e.g. "❯", "▶", "→"); multi-cell strings will misalign columns.
func WithStyles ¶
WithStyles overrides the rendering styles.
func WithViewport ¶
WithViewport restricts rendering to `height` rows starting at row `top` (0-indexed, absolute). When totalRows > height a one-cell scrollbar is drawn on the right of every line (track "│", thumb "▌") with the thumb's position computed from (top, height, totalRows). When the data fits, no scrollbar is drawn. height must be >= 1; top is clamped to [0, max(0, totalRows-height)].
type Options ¶
type Options struct {
// Styles supplies colours and padding used by the underlying lipgloss
// table. Defaults to stripes.DefaultStyles.
Styles *stripes.Styles
// Now, when non-nil, switches time.Time fields to relative rendering
// ("5m ago", "3h ago", "5d ago") anchored at the returned instant.
// When nil (the default) time.Time renders as an absolute timestamp.
Now func() time.Time
// Border draws table borders using the supplied lipgloss.Border
// (e.g. lipgloss.NormalBorder(), lipgloss.RoundedBorder()). The zero
// value renders borderless — only padding separates cells.
Border lipgloss.Border
// Columns supplies explicit column metadata. Required when T is a
// slice or array (untyped rows); rejected when T is a struct, where
// the schema is derived from struct fields and tags instead.
Columns []Column
// ColumnStyle, when non-nil, is called once per data cell. The
// returned lipgloss.Style is composed with Styles.Rows via Inherit:
// fields set on the returned style win, defaults fill the rest. col
// is the zero-based column index; val is the post-width-fit,
// post-internal-colorize cell text.
ColumnStyle func(col int, val string) lipgloss.Style
// HeaderStyle, when non-nil, is called once per header cell. The
// returned lipgloss.Style is composed with Styles.Columns via
// Inherit: fields set on the returned style win, defaults (e.g.
// bold) fill the rest. col is the zero-based column index; val is
// the header text.
HeaderStyle func(col int, val string) lipgloss.Style
// RowStyle, when non-nil, is called once per data row before any
// per-cell ColumnStyle is applied. The returned lipgloss.Style is
// composed with Styles.Rows via Inherit. row is the zero-based data
// row index (the header row is not counted).
RowStyle func(row int) lipgloss.Style
// RowSelector, when non-nil, draws a one-cell gutter on the left:
// rows for which the predicate returns true render
// SelectedIndicator, other rows and the header render a single
// space. The `row` argument is the absolute row index (unaffected
// by ViewportTop).
RowSelector func(row int) bool
// SelectedIndicator is the gutter glyph drawn for rows matched by
// RowSelector. Empty means use the package default ("❯").
SelectedIndicator string
// ViewportHeight, when > 0, restricts rendering to that many rows
// starting at ViewportTop. When totalRows > ViewportHeight a
// one-cell scrollbar is drawn on the right. Zero disables the
// viewport — all rows render.
ViewportHeight int
// ViewportTop is the absolute row index of the first visible row
// when ViewportHeight > 0. Clamped to [0, max(0, totalRows-height)].
ViewportTop int
}
Options controls table rendering.