cliout

package
v0.1.0-rc3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT Imports: 17 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
var ErrAborted = errors.New("prompt aborted")

ErrAborted is returned from Ask when the user aborts (EOF, Ctrl+C, or exhausts all retry attempts).

View Source
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

func Ask(r io.Reader, w io.Writer, p Prompt) (string, error)

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

func IsTTY(w io.Writer) bool

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

func Write(w io.Writer, msgs ...Message)

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

func WriteInline(w io.Writer, msgs ...Message)

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.

func New

func New() *Builder

New returns an empty Builder.

func (*Builder) Dim

func (b *Builder) Dim(text string) *Builder

Dim appends a dimmed Paragraph (Dim: true).

func (*Builder) Header

func (b *Builder) Header(s Status, subject, state string) *Builder

Header appends a Header message.

func (*Builder) Hint

func (b *Builder) Hint(verb, cmd, tail string) *Builder

Hint appends a Hint message.

func (*Builder) KV

func (b *Builder) KV(pairs ...KVPair) *Builder

KV appends a KV message with the given pairs.

func (*Builder) Messages

func (b *Builder) Messages() []Message

Messages returns the accumulated message slice for test assertions.

func (*Builder) Paragraph

func (b *Builder) Paragraph(text string) *Builder

Paragraph appends a plain Paragraph message.

func (*Builder) Step

func (b *Builder) Step(s Status, text string) *Builder

Step appends a Step message.

func (*Builder) Steps

func (b *Builder) Steps(items ...string) *Builder

Steps appends a Steps message with the given instruction items.

func (*Builder) URL

func (b *Builder) URL(label, href string) *Builder

URL appends a URL message.

func (*Builder) WriteTo

func (b *Builder) WriteTo(w io.Writer) (int64, error)

WriteTo renders and flushes to w using Write. Implements io.WriterTo.

type Header struct {
	Status  Status
	Subject string
	State   string
}

Header is a primary status line rendered as "<status-glyph> Subject State".

type Hint

type Hint struct {
	Verb string
	Cmd  string
	Tail string
}

Hint is an action suggestion rendered as "<info-arrow> Verb Cmd Tail".

type KV

type KV struct {
	Pairs []KVPair
}

KV is an aligned key/value block. Labels are right-padded so values align.

type KVPair

type KVPair struct {
	Label   string
	Value   string
	Caption string // optional trailing muted context
}

KVPair is one row of a KV block.

func Pair

func Pair(label, value string) KVPair

Pair is a shorthand constructor for KVPair with no caption.

func PairWithCaption

func PairWithCaption(label, value, caption string) KVPair

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

func Capture(fn func(w io.Writer)) []Message

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

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.

func Resolve

func Resolve(mode PaletteMode, tty bool, noColor bool, t theme.Theme) Palette

Resolve picks a Palette given mode, TTY status, NO_COLOR flag, and an optional TUI theme. Exported so cmd/ can compose resolution without reimplementing it. A nil theme falls back to Fixed.

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 Paragraph

type Paragraph struct {
	Text string
	Dim  bool
}

Paragraph is free prose. Dim=true renders in Muted; otherwise Plain.

type Prompt

type Prompt struct {
	Label       string
	Placeholder string
	Validate    func(string) error
}

Prompt displays an interactive input prompt with validation.

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.

func (*Recorder) Messages

func (r *Recorder) Messages() []Message

Messages returns a snapshot copy of the recorded slice.

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
)

type Step

type Step struct {
	Status Status
	Text   string
}

Step is an inline progress event rendered as "<status-glyph> Text".

type Steps

type Steps struct {
	Items []string
}

Steps is a numbered instruction list. Numbers are 1..N automatic.

type URL

type URL struct {
	Label string // optional muted precursor, e.g. "Visit this URL to authorize:"
	Href  string
}

URL is a bare URL with an optional preceding label.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL