ui

package
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2026 License: GPL-3.0 Imports: 11 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AcceptsYes added in v0.9.1

func AcceptsYes(answer string, catalog *i18n.Catalog) bool

AcceptsYes reports whether `answer` is an affirmative response. The EN defaults ("y"/"yes") are always accepted. When catalog is non-nil, the catalog's `common.yes_short` / `common.yes_long` strings are added to the accepted set (Turkish: "e"/"evet").

`answer` is assumed already trimmed and lower-cased by the caller. Catalog values are normalised here so a catalog with mixed case still matches.

func AskYesNo

func AskYesNo(r io.Reader, w io.Writer, question string, opts AskOptions) (bool, error)

AskYesNo asks question on w and reads a yes/no response from r. AssumeYes short-circuits to true; NonInteractive (without AssumeYes) short-circuits to false. Default (empty answer) is no.

Accepted-yes vocabulary: case-insensitive, trimmed match against "y"/"yes" (always) plus the active catalog's `common.yes_short` / `common.yes_long` (Turkish: "e"/"evet"). See AskOptions.Catalog.

func ColorEnabled

func ColorEnabled(w io.Writer, mode ColorMode) bool

ColorEnabled reports whether color/ANSI escapes should be emitted to w.

  • ColorNever or NO_COLOR/COMMITBRIEF_NO_COLOR env set → false
  • ColorAlways → true (caller's choice, even when piped)
  • ColorAuto → true only if w is a TTY on a terminal that processes ANSI

TERM=dumb is treated as no-color even on a TTY: dumb terminals (emacs M-x shell, some IDE consoles, bare ptys) report as terminals but do NOT honor cursor-movement escapes. Letting the animated progress renderer run there makes every redraw append instead of overwrite — the spinner "floods" the screen with one repeated line per frame. Demoting to plain (one line per stage) keeps those terminals readable. An explicit `--color always` still overrides, for users who know their terminal.

func Confirm added in v1.5.0

func Confirm(r io.Reader, w io.Writer, question string, opts AskOptions) (bool, error)

Confirm asks a yes/no question, defaulting to No. On an interactive terminal (opts.Interactive) it renders an arrow-key-selectable Yes/No toggle via huh, read from the controlling terminal directly. Otherwise it falls back to the line-based AskYesNo over r/w — the path tests and non-TTY pipelines exercise. AssumeYes/NonInteractive short-circuit before either path, so the interactive toggle never appears in CI.

func EnableANSI

func EnableANSI(w io.Writer) error

EnableANSI applies platform-specific tweaks needed to render ANSI escapes (e.g. enabling VT processing on Windows 10+). No-op on POSIX.

func IsStdinTTY

func IsStdinTTY(r io.Reader) bool

IsStdinTTY reports whether the given reader is a TTY. Used by the CLI to decide whether to set AskOptions.NonInteractive automatically.

func PromptSuffix added in v0.9.1

func PromptSuffix(catalog *i18n.Catalog) string

PromptSuffix returns the y/N choice suffix for prompts ("y/N" or the catalog's localised form like "e/H"). Falls back to English when catalog is nil or the key is missing.

func Select added in v1.5.0

func Select(question string, labels []string) (int, error)

Select renders an arrow-key single-choice list on the controlling terminal (input os.Stdin, output os.Stderr so a captured stdout stays clean) and returns the index of the chosen item. labels[i] is shown for item i; the first item is pre-selected. It is interactive-only — callers must guarantee a TTY (the `commit` command errors on non-TTY before reaching the selector). Returns an error if labels is empty or the form is aborted (e.g. Ctrl-C).

Types

type AskOptions

type AskOptions struct {
	AssumeYes      bool
	NonInteractive bool

	// Interactive, when true, makes Confirm render an arrow-key
	// Yes/No toggle (huh) read from the controlling terminal instead
	// of the line-based fallback. Callers derive it from
	// IsStdinTTY(os.Stdin) — it is NOT inferred from the reader,
	// because the review-scoped shared reader is a *bufio.Reader, not
	// the *os.File the TTY check needs. AssumeYes and NonInteractive
	// still take precedence. Has no effect on AskYesNo (line-only).
	Interactive bool

	// Catalog, when non-nil, controls the prompt suffix ("[y/N]" vs
	// "[e/H]") and the accepted-affirmative vocabulary
	// (common.yes_short / common.yes_long). When nil, falls back to
	// English defaults so existing callers that don't have a catalog
	// handy keep working — but EVERY interactive caller in the CLI
	// should pass one so non-English locales actually get their
	// native input accepted (see UC-14 in PATCH_ROADMAP).
	//
	// The EN forms ("y"/"yes") are accepted unconditionally regardless
	// of catalog, so a user typing English in a Turkish session also
	// proceeds.
	Catalog *i18n.Catalog

	// DefaultYes flips the pre-selected answer to Yes. In the interactive
	// (huh) path the toggle starts on the affirmative button; in the
	// line-based path an empty answer is treated as yes. Off by default so
	// every existing caller keeps the safe default-to-No behaviour. Used by
	// the `commit` command, whose confirm defaults to Yes (ADR-0019).
	DefaultYes bool
}

type ColorMode

type ColorMode int
const (
	ColorAuto ColorMode = iota
	ColorAlways
	ColorNever
)

func ParseColorMode

func ParseColorMode(s string) ColorMode

type Progress added in v0.9.0

type Progress struct {
	// contains filtered or unexported fields
}

Progress is the staged-spinner driving the review pipeline's long-running operations. It renders a `tree` of stage lines on a single writer (typically stderr), animating the leading `⏺` glyph on the *currently active* stage and freezing prior stages with a terminal-state color (green for Finish, red for Fail, muted for Soft).

Three operating modes, decided at construction:

  • **Animated** — TTY writer + colors enabled. Full breathing-dot animation, ANSI cursor escapes to redraw the tree, multi-line output. The natural mode for interactive terminals.
  • **Plain** — non-TTY writer (CI, pipe) but not silent. One line per stage transition (`[start]`, `[done]`, `[info]`, `[fail]`). No animation. Useful for CI logs.
  • **Silent** — caller opts out (Quiet=true). No output at all.

The mode is fixed for the lifetime of the Progress; callers don't need to branch on TTY state at each call.

Concurrency: Start/Info/Finish/Fail/Soft are safe to call from a single goroutine driving the pipeline. The animation lives in its own goroutine that reads the stage list under a mutex.

func NewProgress added in v0.9.0

func NewProgress(w io.Writer, mode ColorMode, quiet bool) *Progress

NewProgress returns a Progress configured for the given writer. The Animated mode requires a TTY writer and colors enabled (ColorAuto + no NO_COLOR env, or ColorAlways). On non-TTY or NO_COLOR, falls back to Plain mode. Set Quiet=true to suppress every output mode.

func (*Progress) Clear added in v0.9.0

func (p *Progress) Clear()

Clear stops the animation and erases the rendered progress tree from the terminal. Use this when downstream output (cards / JSON / markdown body) is about to take over the screen and the per-stage breadcrumbs would be redundant clutter — the rendered output is itself proof the pipeline completed.

In plain mode (non-TTY) Clear is a no-op: those per-stage lines already shipped on each Start/Info/Finish call, are useful in CI logs, and aren't visually redundant the way a fixed-viewport tree is. In silent mode there is nothing to erase. Idempotent.

func (*Progress) Close added in v0.9.0

func (p *Progress) Close()

Close stops the animation goroutine, ensuring the final frame is rendered (so completed stages stay on screen) and the cursor is restored to a known column. Idempotent.

Use Close when the progress tree is the user's primary feedback (empty-diff `no_changes` path, provider-error path). Use Clear instead when downstream output — rendered cards, JSON, markdown — will take over the screen and the tree would just be clutter.

func (*Progress) Fail added in v0.9.0

func (p *Progress) Fail(err error)

Fail marks the current stage as failed (red ⏺) and emits the error indented below it on the next render.

func (*Progress) Finish added in v0.9.0

func (p *Progress) Finish()

Finish marks the current stage as completed (green ⏺).

func (*Progress) Info added in v0.9.0

func (p *Progress) Info(label string)

Info appends a static informational line (no animated glyph, no terminal state). Used for stats lines like "36 files +1233 -34".

func (*Progress) Pause added in v0.9.0

func (p *Progress) Pause()

Pause stops the animation loop and clears the in-progress render so the terminal is handed back to the caller (e.g. an interactive cost prompt). The recorded stage list is preserved; Resume continues from where it left off.

func (*Progress) Resume added in v0.9.0

func (p *Progress) Resume()

Resume restarts the animation after Pause. No-op if not paused.

func (*Progress) Soft added in v0.9.0

func (p *Progress) Soft()

Soft marks the current stage as completed with a neutral muted dot. Used when the operation produced a result that wasn't an outright success but isn't an error either — e.g. the first attempt of a retry-once pipeline.

func (*Progress) Start added in v0.9.0

func (p *Progress) Start(label string)

Start appends a new active stage, finalizing the previous stage with Done (green) state. If no animation goroutine is running yet, one is spawned.

Jump to

Keyboard shortcuts

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