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 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 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.