Documentation
¶
Overview ¶
Package output renders command results as human-readable text or JSON. Commands build explicit DTOs for their output — never genqlient-generated structs — so the --json contract stays stable across schema regenerations.
Index ¶
- func Dash(s *string) string
- func SafeBlock(s string, maxRunes int, indent string) string
- func SafeCell(s string) string
- func SafeLine(s string, maxRunes int) string
- func Tracked(w io.Writer) io.Writer
- func Write(s *IOStreams, asJSON bool, v any, table func(w io.Writer) error) error
- func WriteJSON(w io.Writer, v any) error
- type IOStreams
- type Table
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Dash ¶ added in v0.6.0
Dash renders an optional string cell: the value, or an em-dash placeholder when the pointer is nil or empty. Keeps "no value" columns consistent across the table-rendering commands.
func SafeBlock ¶ added in v0.34.0
SafeBlock bounds server-authored multiline text without flattening its lines. Escape sequences are removed before counting runes. CRLF becomes LF; every other control/format/separator becomes a space. Continuation indentation is CLI-owned. JSON callers must retain the original value. Like SafeCell, a cut may split a combining sequence; there is no separate byte bound.
func SafeCell ¶ added in v0.29.0
SafeCell makes a server-supplied string safe to print as one table cell (#1065). Every control character (C0, C1, DEL, ESC, tab, CR, LF) and every Unicode format or line/paragraph separator (Cf, Zl, Zp: bidi overrides, zero-width characters, BOM, U+2028/2029) becomes a single space, so a value can neither forge a row nor recolor or reorder the terminal. Ordinary Unicode passes unchanged. The text is cut by rune at cellMaxRunes, which can split a combining sequence. ZWJ (U+200D) is Cf, so a ZWJ emoji sequence renders as separate emoji; that is the accepted cost of the stricter rule.
Text mode only: --json carries the original value. Other commands' tables are unchanged (roster, automation and member keep their own guards).
func SafeLine ¶ added in v0.32.0
SafeLine is SafeCell with the caller's rune bound, for one-line messages (an error refusal) that need more room than a table cell.
func Tracked ¶ added in v0.14.0
Tracked wraps w so an IOStreams built around it can answer Wrote(). Exported so a test factory can give commands the same stdout they get in production — an untracked stream always reports "clean", which would let a test pass on a path the binary handles differently (review:a-test-double-must-satisfy-the-real-access-pattern).
Types ¶
type IOStreams ¶
type IOStreams struct {
In io.Reader
Out io.Writer
ErrOut io.Writer
// contains filtered or unexported fields
}
IOStreams bundles the CLI's input/output handles so commands never touch os.Stdin/Stdout directly, keeping them testable.
func Test ¶
Test returns IOStreams backed by buffers, plus the stdout and stderr buffers for assertions.
func TestTTY ¶ added in v0.13.0
TestTTY returns IOStreams whose stdin is an answerable terminal (#525), with `answers` standing in for what a person types — one line per prompt, in order. Stdout is left non-terminal. Returns the stdout and stderr buffers; a prompt renders on stderr.
Why it exists: cmdutil.Confirm and ConfirmDeletion refuse as non-interactive BEFORE composing their prompt, and Test() has no way to say otherwise, so every confirmation in the CLI was beyond the reach of a command-level test — a door with no handle that each new confirmation inherits.
Three properties, each load-bearing:
- The answers are a CONSTRUCTOR argument, not a field set afterwards. Test()'s In is an empty buffer, so flipping the TTY bit alone makes scanner.Scan() return false and Confirm returns Cancelled — a different unreachable branch, indistinguishable from a person answering "no". A seam that can be half-used yields a green test proving nothing.
- One line PER READ, via lineReader rather than strings.NewReader. See lineReader for why; a command that prompts twice is the case.
- Stdout stays non-terminal. Confirm reads stdin only, and interactive stdin with redirected stdout is a real process state (`hadron … | less`), so this is an honest configuration rather than a test-only shape. Widen it when something needs the stdout branch, not before.
func (*IOStreams) IsInputTerminal ¶
IsInputTerminal reports whether stdin is a TTY (i.e. a prompt can actually be answered).
func (*IOStreams) IsTerminal ¶
IsTerminal reports whether stdout is a TTY.
func (*IOStreams) Wrote ¶ added in v0.14.0
Wrote reports whether anything has been written to stdout yet.
FALSE for an untracked stream, deliberately: "nothing has been written" is the state in which the envelope goes to stdout, which is the behaviour this change is for. A stream nobody wrapped therefore degrades to the new behaviour rather than silently keeping the old one.