Documentation
¶
Index ¶
- Constants
- Variables
- func BuildTheme(entries ThemeEntries) (*chroma.Style, error)
- func ColorEnabled(w io.Writer) bool
- func DefaultFormatters() map[string]Formatter
- func FormatterNames(fmts map[string]Formatter) string
- func Header(headers map[string][]string, name string) string
- func HeaderValues(headers map[string][]string, name string) []string
- func HighlightWithLexer(lexer chroma.Lexer, data []byte) ([]byte, error)
- func IsLineScalar(value any) bool
- func IsTerminal(w io.Writer) bool
- func IsTerminalReader(r io.Reader) bool
- func MarkdownStyle() ansi.StyleConfig
- func NewMarkdownRenderer(width int) (*glamour.TermRenderer, error)
- func ResponseHasNoBody(resp *http.Response) bool
- func SetTheme(entries ThemeEntries) error
- func StatusToExitCode(status int) int
- func StyleText(tokenName, text string) string
- func ThemeTokenColor(tokenName string) string
- func WriteLinesValue(w io.Writer, value any) error
- type AutoFormatter
- func (f *AutoFormatter) Format(w io.Writer, resp *Response, color bool) error
- func (f *AutoFormatter) StartFramedValueStream(w io.Writer, base *Response, color bool, frame FramedValueTemplate) (ValueStream, error)
- func (f *AutoFormatter) StartValueStream(w io.Writer, base *Response, color bool) (ValueStream, error)
- type CBORFormatter
- type Formatter
- type FramedValueStreamFormatter
- type FramedValueTemplate
- type GronFormatter
- type ImageFormatter
- type JSONFormatter
- type LinesFormatter
- type NDJSONFormatter
- type PluginFormatter
- type Response
- type TOONFormatter
- type TableFormatter
- type ThemeEntries
- type ValueFormatter
- type ValueStream
- type ValueStreamFormatter
- type YAMLFormatter
Constants ¶
const DefaultMaxBodyBytes int64 = 100 * 1024 * 1024
DefaultMaxBodyBytes is the default cap on response body reads (100 MiB). A server cannot allocate more than this per response.
Variables ¶
var HTTPPreambleLexer = lexers.Register(chroma.MustNewLexer( &chroma.Config{ Name: "Restish HTTP Preamble", Aliases: []string{"restish-http"}, }, func() chroma.Rules { return chroma.Rules{ "statusline": { {Pattern: `HTTP/\S+`, Type: chroma.NameNamespace}, {Pattern: `[ \t]+`, Type: chroma.Text}, {Pattern: `2\d\d`, Type: chroma.GenericInserted}, {Pattern: `3\d\d`, Type: chroma.GenericOutput}, {Pattern: `[45]\d\d`, Type: chroma.GenericError}, {Pattern: `[^\n]+`, Type: chroma.Text}, {Pattern: `\n`, Type: chroma.Text, Mutator: chroma.Push("headers")}, }, "headers": { {Pattern: `([\w][\w-]*)(:)`, Type: chroma.ByGroups(httpHeaderKey, chroma.Punctuation), Mutator: chroma.Push("headervalue")}, {Pattern: `\n`, Type: chroma.Text}, }, "headervalue": { {Pattern: `[ \t]+`, Type: chroma.Text}, {Pattern: `[^\n]+`, Type: chroma.Text}, {Pattern: `\n`, Type: chroma.Text, Mutator: chroma.Pop(1)}, }, "root": {chroma.Include("statusline")}, } }, ))
HTTPPreambleLexer tokenizes the status line and headers section of an HTTP response so they can be colored via restishStyle just like the body.
Token mapping (all defined in style.go):
HTTP/x.x → NameNamespace (gray) 2xx → GenericInserted (green) 3xx → GenericOutput (amber) 4xx / 5xx → GenericError (pink) header name → httpHeaderKey (sky blue) : separator → Punctuation (gray) everything else → Text
var ReadableLexer = lexers.Register(chroma.MustNewLexer( &chroma.Config{ Name: "Restish Readable", Aliases: []string{"restish-readable"}, }, func() chroma.Rules { return chroma.Rules{ "whitespace": { {Pattern: `\s+`, Type: chroma.Text}, }, "scalar": { {Pattern: `(true|false|null)\b`, Type: chroma.KeywordConstant}, {Pattern: `"?0x[0-9a-f]+(\\.\\.\\.)?"?`, Type: chroma.LiteralNumberHex}, {Pattern: `"?[0-9]{4}-[0-9]{2}-[0-9]{2}(T[0-9:+\-.]+Z?)?"?`, Type: chroma.LiteralDate}, {Pattern: `"?[A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} GMT"?`, Type: chroma.LiteralDate}, {Pattern: `-?(0|[1-9]\d*)(\.\d+[eE](\+|-)?\d+|[eE](\+|-)?\d+|\.\d+)`, Type: chroma.LiteralNumberFloat}, {Pattern: `-?(0|[1-9]\d*)`, Type: chroma.LiteralNumberInteger}, {Pattern: `"([a-z]+://|/)(\\\\|\\"|[^"])+"`, Type: chroma.LiteralStringSymbol}, {Pattern: `"(\\\\|\\"|[^"])*"`, Type: chroma.LiteralStringDouble}, }, "objectrow": { {Pattern: `:`, Type: chroma.Punctuation}, {Pattern: `,`, Type: chroma.Punctuation}, {Pattern: `\n`, Type: chroma.Punctuation, Mutator: chroma.Pop(1)}, {Pattern: `\}`, Type: chroma.Punctuation, Mutator: chroma.Pop(2)}, chroma.Include("value"), }, "object": { chroma.Include("whitespace"), {Pattern: `\}`, Type: chroma.EmitterFunc(readableIndentEnd), Mutator: chroma.Pop(1)}, {Pattern: `(\\\\|\\:|[^:])+`, Type: chroma.NameTag, Mutator: chroma.Push("objectrow")}, }, "arrayvalue": { {Pattern: `,`, Type: chroma.Punctuation}, {Pattern: `\]`, Type: chroma.EmitterFunc(readableIndentEnd), Mutator: chroma.Pop(1)}, chroma.Include("value"), }, "value": { chroma.Include("whitespace"), {Pattern: `\{`, Type: chroma.EmitterFunc(readableIndentStart), Mutator: chroma.Push("object")}, {Pattern: `\[`, Type: chroma.EmitterFunc(readableIndentStart), Mutator: chroma.Push("arrayvalue")}, chroma.Include("scalar"), }, "root": {chroma.Include("value")}, } }, ))
ReadableLexer is a custom chroma lexer for Restish terminal output. It extends JSON tokenization with special-case patterns for:
- ISO 8601 / HTTP dates → LiteralDate
- URLs → LiteralStringSymbol
- Hex binary ("0x…") → LiteralNumberHex
- Nested bracket pairs → alternating bracket-depth token types
Ported from v1's cli/lexer.go and adapted for chroma v2 + valid JSON output (quoted keys, commas between items).
var SchemaLexer = lexers.Register(chroma.MustNewLexer( &chroma.Config{ Name: "Restish Schema", Aliases: []string{"schema", "restish-schema", "openapi-schema"}, }, func() chroma.Rules { return chroma.Rules{ "whitespace": { {Pattern: `\s+`, Type: chroma.Text}, }, "scalar": { {Pattern: `(true|false|null)\b`, Type: chroma.KeywordConstant}, {Pattern: `-?(0|[1-9]\d*)(\.\d+[eE](\+|-)?\d+|[eE](\+|-)?\d+|\.\d+)`, Type: chroma.LiteralNumberFloat}, {Pattern: `-?(0|[1-9]\d*)`, Type: chroma.LiteralNumberInteger}, {Pattern: `"([a-z]+://|/)(\\\\|\\"|[^"])+"`, Type: chroma.LiteralStringSymbol}, {Pattern: `"(\\\\|\\"|[^"])*"`, Type: chroma.LiteralStringDouble}, {Pattern: `<[^>\n]+>`, Type: chroma.Comment}, {Pattern: `(allOf|oneOf|anyOf)\b`, Type: chroma.Keyword}, {Pattern: `\(`, Type: chroma.Punctuation, Mutator: chroma.Push("annotation")}, {Pattern: `[^{}\[\]:,\n]+`, Type: chroma.Text}, }, "annotation": { {Pattern: `\)`, Type: chroma.Punctuation, Mutator: chroma.Pop(1)}, {Pattern: `\s+`, Type: chroma.Text}, {Pattern: `\|`, Type: chroma.Operator}, {Pattern: `(boolean|integer|number|string|array|object|any)\b`, Type: chroma.KeywordType}, {Pattern: `(format|default|enum|pattern|minLen|maxLen):`, Type: chroma.NameBuiltin}, {Pattern: `-?(0|[1-9]\d*)(\.\d+[eE](\+|-)?\d+|[eE](\+|-)?\d+|\.\d+)`, Type: chroma.LiteralNumberFloat}, {Pattern: `-?(0|[1-9]\d*)`, Type: chroma.LiteralNumberInteger}, {Pattern: `true|false|null\b`, Type: chroma.KeywordConstant}, {Pattern: `[^)\s|]+`, Type: chroma.LiteralString}, }, "schema-key": { {Pattern: `\*`, Type: chroma.Operator}, {Pattern: `[^\*:]+`, Type: chroma.NameTag}, }, "objectrow": { {Pattern: `:`, Type: chroma.Punctuation}, {Pattern: `,`, Type: chroma.Punctuation}, {Pattern: `\n`, Type: chroma.Punctuation, Mutator: chroma.Pop(1)}, {Pattern: `\}`, Type: chroma.EmitterFunc(readableIndentEnd), Mutator: chroma.Pop(2)}, chroma.Include("value"), }, "object": { chroma.Include("whitespace"), {Pattern: `\}`, Type: chroma.EmitterFunc(readableIndentEnd), Mutator: chroma.Pop(1)}, {Pattern: `([^:\n{}\[\]]+)(:)`, Type: chroma.ByGroups(chroma.UsingSelf("schema-key"), chroma.Punctuation), Mutator: chroma.Push("objectrow")}, }, "arrayvalue": { {Pattern: `,`, Type: chroma.Punctuation}, {Pattern: `\]`, Type: chroma.EmitterFunc(readableIndentEnd), Mutator: chroma.Pop(1)}, chroma.Include("value"), }, "value": { chroma.Include("whitespace"), {Pattern: `\{`, Type: chroma.EmitterFunc(readableIndentStart), Mutator: chroma.Push("object")}, {Pattern: `\[`, Type: chroma.EmitterFunc(readableIndentStart), Mutator: chroma.Push("arrayvalue")}, chroma.Include("scalar"), }, "root": {chroma.Include("value")}, } }, ))
SchemaLexer tokenizes the compact schema language used in generated OpenAPI command help. It intentionally shares theme tokens with readable output so schema blocks embedded in Glamour-rendered help are colored like response bodies.
Functions ¶
func BuildTheme ¶
func BuildTheme(entries ThemeEntries) (*chroma.Style, error)
BuildTheme validates user theme entries and returns a Chroma style.
func ColorEnabled ¶
ColorEnabled reports whether ANSI color output should be used for w. Rules (in priority order):
- NOCOLOR or NO_COLOR env var → off
- COLOR env var → on
- w is a TTY → on; otherwise off
func DefaultFormatters ¶
DefaultFormatters returns the built-in set of formatters. The "table" entry here uses default (zero-value) column settings; callers that need --rsh-columns / --rsh-sort-by should replace it.
func FormatterNames ¶
FormatterNames returns the sorted list of registered formatter names, suitable for use in help text and error messages.
func Header ¶
Header returns the first value for name from headers, matching http.Header.Get's case-insensitive lookup semantics.
func HeaderValues ¶
HeaderValues returns all values for name from headers.
func HighlightWithLexer ¶
HighlightWithLexer renders data with the provided chroma lexer and the shared Restish terminal style. It falls back to the original data if highlighting fails.
func IsLineScalar ¶
IsLineScalar reports whether value can be rendered as one unquoted line.
func IsTerminal ¶
IsTerminal reports whether w is a real terminal (TTY).
func IsTerminalReader ¶
IsTerminalReader reports whether r is a real terminal (TTY). Used to detect whether stdin is interactive.
func MarkdownStyle ¶
func MarkdownStyle() ansi.StyleConfig
MarkdownStyle returns the Restish Glamour style, with colors derived from the active user theme so Markdown bodies and help match auto terminal output.
func NewMarkdownRenderer ¶
func NewMarkdownRenderer(width int) (*glamour.TermRenderer, error)
NewMarkdownRenderer returns a Glamour renderer that respects GLAMOUR_STYLE when explicitly configured, otherwise falling back to the active Restish theme-backed Markdown style.
func ResponseHasNoBody ¶ added in v2.1.0
ResponseHasNoBody reports whether HTTP semantics forbid a response body. Some servers still send Content-Encoding on these responses; callers should ignore the body instead of attempting to decompress or decode it.
func SetTheme ¶
func SetTheme(entries ThemeEntries) error
SetTheme overlays user-supplied theme entries onto the built-in Restish theme. Passing nil or an empty map restores the default style.
func StatusToExitCode ¶
StatusToExitCode maps an HTTP status code to Restish's script-friendly status-family exit code.
2xx → 0 (success) 3xx → 3 (redirect status) 4xx → 4 (client error) 5xx → 5 (server error) other → 1 (runtime or unexpected status failure)
func StyleText ¶
StyleText renders text with the named Restish theme token. It returns the original text if the token is unknown or terminal formatting is unavailable.
func ThemeTokenColor ¶ added in v2.1.0
ThemeTokenColor returns the active theme's foreground color for tokenName. It returns an empty string when the token is unknown or has no color.
Types ¶
type AutoFormatter ¶
type AutoFormatter struct{}
AutoFormatter writes the response body in the default human-friendly format. It does not write status or headers; callers that want interactive HTTP context should print those parts explicitly before rendering the body.
func (*AutoFormatter) StartFramedValueStream ¶
func (f *AutoFormatter) StartFramedValueStream(w io.Writer, base *Response, color bool, frame FramedValueTemplate) (ValueStream, error)
StartFramedValueStream renders streamed values into a JSON-shaped frame
func (*AutoFormatter) StartValueStream ¶
func (f *AutoFormatter) StartValueStream(w io.Writer, base *Response, color bool) (ValueStream, error)
StartValueStream renders each streamed value as a pretty-printed JSON block for fast human feedback on TTYs.
type CBORFormatter ¶
type CBORFormatter struct{}
CBORFormatter encodes the response body as CBOR and writes the raw bytes to stdout. Useful for feeding binary-safe pipelines.
type Formatter ¶
Formatter renders a normalized Response to a writer. color indicates whether ANSI escape sequences are appropriate.
type FramedValueStreamFormatter ¶
type FramedValueStreamFormatter interface {
StartFramedValueStream(w io.Writer, base *Response, color bool, frame FramedValueTemplate) (ValueStream, error)
}
FramedValueStreamFormatter can render a sequence of body/sub-values into a larger framed document shape such as a JSON array inside an object.
type FramedValueTemplate ¶
type FramedValueTemplate struct {
Prefix string
Suffix string
ItemIndent string
CloseIndent string
}
FramedValueTemplate describes how a streamed sequence of values should be embedded into a larger JSON document shape.
type GronFormatter ¶
type GronFormatter struct{}
GronFormatter renders the body as "gron" format: each leaf value on its own line as `json.<path> = <value>;`. Useful for grep-friendly output.
type ImageFormatter ¶
type ImageFormatter struct{}
ImageFormatter renders image/* responses inline on a TTY using the best available terminal graphics protocol.
Protocol is selected in order:
- $RSH_IMAGE_PROTOCOL env var (kitty | iterm2 | halfblock)
- Terminal env vars ($KITTY_WINDOW_ID / $TERM=xterm-kitty → Kitty; $TERM_PROGRAM ∈ {iTerm.app, WezTerm, Hyper} → iTerm2)
- Unicode half-block fallback
When color is false (non-TTY), raw bytes are written unchanged.
type JSONFormatter ¶
type JSONFormatter struct{}
JSONFormatter writes only the response body as indented JSON. This is the default format in non-interactive (pipe/file) mode.
type LinesFormatter ¶
type LinesFormatter struct{}
LinesFormatter renders scalar values as shell-friendly text, one value per line. Structured values are rejected so callers do not accidentally lose object or array shape.
func (*LinesFormatter) FormatValue ¶
func (*LinesFormatter) StartValueStream ¶
func (f *LinesFormatter) StartValueStream(w io.Writer, base *Response, color bool) (ValueStream, error)
type NDJSONFormatter ¶
type NDJSONFormatter struct{}
NDJSONFormatter renders one JSON value per line. This is the explicit record-oriented formatter for paginated item streams and event streams.
func (*NDJSONFormatter) FormatValue ¶
func (*NDJSONFormatter) StartValueStream ¶
func (f *NDJSONFormatter) StartValueStream(w io.Writer, base *Response, color bool) (ValueStream, error)
type PluginFormatter ¶
PluginFormatter is an output.Formatter backed by a hook plugin. The plugin receives a short formatter session over CBOR on stdin and writes its formatted output directly to stdout (raw bytes, no CBOR reply framing).
func (*PluginFormatter) Format ¶
Format sends the response to the plugin using the formatter session protocol and copies the plugin's raw output to w.
func (*PluginFormatter) FormatValue ¶
FormatValue renders a body/sub-value through a short formatter session, without implying that the value is a full HTTP response.
func (*PluginFormatter) StartValueStream ¶
func (f *PluginFormatter) StartValueStream(w io.Writer, base *Response, color bool) (ValueStream, error)
StartValueStream starts a long-lived formatter plugin session.
type Response ¶
type Response struct {
Proto string `json:"proto"`
Status int `json:"status"`
Headers map[string][]string `json:"headers"`
// URL is the final response URL. It is used for presentation concerns such
// as syntax highlighting file-like text responses by extension.
URL string `json:"-"`
// Links is populated by hypermedia parsers; empty until then.
Links map[string]any `json:"links,omitempty"`
Body any `json:"body"`
// Raw holds the unformatted response body after Content-Encoding
// decompression. Used by raw CLI output and binary/content-aware formatters
// to write body bytes without formatter re-encoding.
Raw []byte `json:"-"`
}
Response is the normalized form of every HTTP response before formatting. All formatters receive this struct; nothing downstream touches *http.Response.
type TOONFormatter ¶ added in v2.2.0
type TOONFormatter struct{}
TOONFormatter renders the response body as Token-Oriented Object Notation (TOON), a compact, indentation-based encoding of the JSON data model designed to reduce token usage when structured data is fed to large language models.
This is an output-only encoder pinned to TOON spec v3.3 (https://github.com/toon-format/spec). It uses the default comma delimiter and two-space indentation. Map-backed object keys, including tabular field names derived from maps, are emitted in sorted order so normal Restish output is deterministic.
TOON's largest savings come from uniform arrays of flat, primitive-valued objects, which collapse into a tabular form that declares field names once and then streams rows. Non-uniform or nested arrays fall back to an expanded dash-marked list, and deeply nested or irregular data saves little versus JSON.
func (*TOONFormatter) Format ¶ added in v2.2.0
Format encodes the response body as TOON. Like the JSON and gron formatters it renders only resp.Body; status and headers are not part of structured body output.
func (*TOONFormatter) FormatValue ¶ added in v2.2.0
FormatValue encodes an arbitrary body/sub-value as TOON. Implementing ValueFormatter lets filtered (-f) and paginated item values render as TOON, which is where the tabular form is most valuable.
type TableFormatter ¶
type TableFormatter struct {
// Columns is the ordered list of column names to display. When empty,
// all keys found in the first row are used.
Columns []string
// SortBy is an optional column name to sort rows by ascending value.
// Numeric cells sort numerically; other cells sort by display string.
SortBy string
}
TableFormatter renders an array of objects as a Unicode box-drawing table. Non-array or non-object body values are formatted as plain JSON.
type ThemeEntries ¶
ThemeEntries maps token names to Chroma style descriptors. Token names may be Chroma token type names (for example, "NameTag") or Restish aliases such as "key", "header_key", "keyword", "url", and "status_2xx".
func ParseThemeJSON ¶
func ParseThemeJSON(data []byte) (ThemeEntries, error)
ParseThemeJSON parses a direct JSON or JSONC token map and validates it by building a style.
type ValueFormatter ¶
ValueFormatter renders a body/sub-value without implying that it is a full HTTP response. This is used for filtered values, paginated item streams, and event streams where status/header preambles would be misleading.
type ValueStream ¶
ValueStream receives a sequence of body/sub-values for a single logical output session.
type ValueStreamFormatter ¶
type ValueStreamFormatter interface {
StartValueStream(w io.Writer, base *Response, color bool) (ValueStream, error)
}
ValueStreamFormatter can hold formatter-specific state across a stream of body/sub-values, such as writing one CSV header followed by many rows.
type YAMLFormatter ¶
type YAMLFormatter struct{}
YAMLFormatter serialises the response body as YAML.
func (*YAMLFormatter) FormatValue ¶
FormatValue writes a body/sub-value as YAML.