Documentation
¶
Overview ¶
Package cliout renders styled CLI output for the spotnik command-line interface.
The package defines a small taxonomy of message types (Header, Step, KV, Steps, Hint, URL, Paragraph, Spinner, Prompt). Callers build []Message values or use the fluent Builder and call Write / WriteInline. Rendering is palette-aware and honours NO_COLOR and TTY detection automatically.
Before adding a new message type or glyph, read docs/system/cli.md — it is the canonical reference for the project's CLI output conventions.
Index ¶
- Variables
- func Ask(r io.Reader, w io.Writer, p Prompt) (string, error)
- func IsTTY(w io.Writer) bool
- func SetTestMode(enabled bool)
- func UninstallSIGINTHandler()
- func Use(p Palette)
- func Write(w io.Writer, msgs ...Message)
- func WriteInline(w io.Writer, msgs ...Message)
- type Builder
- func (b *Builder) Dim(text string) *Builder
- func (b *Builder) Header(s Status, subject, state string) *Builder
- func (b *Builder) Hint(verb, cmd, tail string) *Builder
- func (b *Builder) KV(pairs ...KVPair) *Builder
- func (b *Builder) Messages() []Message
- func (b *Builder) Paragraph(text string) *Builder
- func (b *Builder) Step(s Status, text string) *Builder
- func (b *Builder) Steps(items ...string) *Builder
- func (b *Builder) URL(label, href string) *Builder
- func (b *Builder) WriteTo(w io.Writer) (int64, error)
- type Header
- type Hint
- type KV
- type KVPair
- type Message
- type Palette
- type PaletteMode
- type Paragraph
- type Prompt
- type Recorder
- type Spinner
- type SpinnerHandle
- type Status
- type Step
- type Steps
- type URL
Constants ¶
This section is empty.
Variables ¶
var ErrAborted = errors.New("prompt aborted")
ErrAborted is returned from Ask when the user aborts (EOF, Ctrl+C, or exhausts all retry attempts).
var Fixed = Palette{ Accent: lipgloss.AdaptiveColor{Dark: "#1DB954", Light: "#1A8C41"}, Success: lipgloss.AdaptiveColor{Dark: "#1DB954", Light: "#1A8C41"}, Error: lipgloss.AdaptiveColor{Dark: "#FF5555", Light: "#CC0000"}, Warning: lipgloss.AdaptiveColor{Dark: "#F1C40F", Light: "#B8860B"}, Muted: lipgloss.AdaptiveColor{Dark: "#6C7083", Light: "#888888"}, Plain: lipgloss.AdaptiveColor{Dark: "", Light: ""}, }
Fixed is the built-in palette — safe on any terminal, matches story 145 hex values.
Functions ¶
func Ask ¶
Ask renders a Prompt and reads a validated value from r (typically os.Stdin). On validation failure it retries up to maxPromptAttempts times, printing a failure step after each bad attempt. After maxPromptAttempts failures it prints a "Giving up" step and returns ErrAborted.
If a Recorder is active (Capture mode), the Prompt message is recorded and Ask returns immediately with ("", nil) — no input is consumed.
func IsTTY ¶
IsTTY returns whether w is an *os.File pointing at a terminal. Exported shim over isTTY for use by cmd/.
func SetTestMode ¶
func SetTestMode(enabled bool)
SetTestMode enables or disables test mode. In test mode, pinASCII is called immediately, uikit is pinned to GlyphASCII mode so that glyph-role assertions are deterministic, and spinner animation is disabled. Tests call this in TestMain for deterministic output.
SetTestMode(true) snapshots the current uikit mode before pinning to GlyphASCII. SetTestMode(false) restores that snapshot, so nested test helpers that toggle test mode do not permanently alter the active glyph mode. Note: pinASCII is sync.Once-guarded and is not reversed by SetTestMode(false).
func UninstallSIGINTHandler ¶
func UninstallSIGINTHandler()
UninstallSIGINTHandler stops signal delivery to the cliout SIGINT handler. Call this before starting any program that owns its own terminal cleanup (e.g. Bubble Tea) to prevent the cliout handler from calling os.Exit(130) and bypassing the program's deferred terminal restore.
This is a one-shot teardown: the underlying sync.Once is already consumed, so SIGINT handling cannot be re-armed in the same process after this call. The handler goroutine remains blocked on the now-silent channel until the process exits.
func Use ¶
func Use(p Palette)
Use replaces the active palette. Called by cmd/root.go once config is loaded. Safe to call more than once; safe to skip (default is Fixed).
func Write ¶
Write renders each message with a leading blank line and standard padding. Safe for any io.Writer. If a Recorder is active (see testing.go), writes go to the recorder instead of the writer. On first call, pins ASCII profile when output is not a TTY or NO_COLOR is set.
func WriteInline ¶
WriteInline renders with no leading blank line — for compact step-by-step progress. If a Recorder is active, writes go to the recorder instead of the writer. On first call, pins ASCII profile when output is not a TTY or NO_COLOR is set.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder provides a fluent façade over []Message. All chain methods append to the same slice; WriteTo renders and flushes.
type KV ¶
type KV struct {
Pairs []KVPair
}
KV is an aligned key/value block. Labels are right-padded so values align.
type KVPair ¶
KVPair is one row of a KV block.
func PairWithCaption ¶
PairWithCaption constructs a KVPair with a trailing muted caption.
type Message ¶
type Message interface {
// contains filtered or unexported methods
}
Message is implemented by every CLI message type. External packages cannot implement this interface — the isMessage marker is unexported.
func Capture ¶
Capture runs fn with a package-level Recorder installed. All Write/WriteInline calls during fn are captured and returned. Spinner/Prompt dynamic types (Story 149) also append to the recorder when active, but their input/animation side effects are skipped — tests assert on structure, not on stdin consumption or TTY bytes. Not thread-safe — run tests sequentially.
type Palette ¶
type Palette struct {
Accent lipgloss.TerminalColor
Success lipgloss.TerminalColor
Error lipgloss.TerminalColor
Warning lipgloss.TerminalColor
Muted lipgloss.TerminalColor
Plain lipgloss.TerminalColor
}
Palette holds the six role colours used by all message types.
func CurrentForTest ¶
func CurrentForTest() Palette
CurrentForTest returns the currently active palette. Test-only helper that allows cmd/ tests to assert on the palette installed by resolveCLIPalette.
type PaletteMode ¶
type PaletteMode int
PaletteMode controls resolution strategy. Mirrors config.toml [cli] palette.
const ( // ModeAuto uses theme tokens on dark TTY, falls back to Fixed otherwise. ModeAuto PaletteMode = iota // ModeFixed always uses the built-in Fixed palette. ModeFixed // ModeTheme always uses the active TUI theme tokens. ModeTheme )
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder captures messages written via Write / WriteInline without rendering. Used by Capture and by test assertions on structure rather than styled strings.
type Spinner ¶
type Spinner struct {
Text string
}
Spinner displays an animated progress line during long-running operations.
type SpinnerHandle ¶
type SpinnerHandle struct {
// contains filtered or unexported fields
}
SpinnerHandle controls a running spinner. Obtain one via StartSpinner. Done, Fail, and Stop are safe to call from any goroutine and are idempotent.
func StartSpinner ¶
func StartSpinner(w io.Writer, text string) *SpinnerHandle
StartSpinner starts an animated spinner on TTY or writes a static pending line on non-TTY / test mode. Returns a SpinnerHandle to resolve via Done, Fail, or Stop.
If a Recorder is active (test capture via Capture()), the Spinner message is recorded and a no-op handle is returned.
func (*SpinnerHandle) Done ¶
func (h *SpinnerHandle) Done(text string)
Done resolves the spinner with a success step.
func (*SpinnerHandle) Fail ¶
func (h *SpinnerHandle) Fail(text string)
Fail resolves the spinner with a failure step.
func (*SpinnerHandle) Stop ¶
func (h *SpinnerHandle) Stop()
Stop cancels the spinner silently. Idempotent.
type Status ¶
type Status int
Status is used by Header and Step to indicate the current state of an operation.
const ( // Active indicates the operation is currently running. Active Status = iota // Inactive indicates the operation is not running. Inactive // StatusSuccess indicates a successful outcome. StatusSuccess // StatusFailure indicates a failed outcome. StatusFailure // StatusWarning indicates a warning state. StatusWarning // Pending indicates the operation is queued but not yet started. Pending )