Help us shape the future of Go! Take the 2026 Go Developer Survey

ui

package
v0.17.1 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package ui provides consistent terminal output primitives for the obol CLI.

Pass a *UI through your call chain instead of using fmt directly. Output adapts to the environment: colors and spinners in interactive terminals, plain text when piped or in CI.

When OutputJSON mode is active, human-readable output (Info, Success, Print, etc.) is redirected to stderr so that stdout contains only clean JSON. Use the JSON() method to emit structured data.

Index

Constants

View Source
const (
	ColorObolGreen     = "#2FE4AB" // Primary brand green
	ColorObolDarkGreen = "#0F7C76" // Dark green (success)
	ColorObolCyan      = "#3CD2DD" // Light blue / info
	ColorObolPurple    = "#9167E4" // Accent purple
	ColorObolAmber     = "#FABA5A" // Warning amber
	ColorObolRed       = "#DD603C" // Error red-orange
	ColorObolAcid      = "#B6EA5C" // Highlight acid green
	ColorObolMuted     = "#667A80" // Muted gray
	ColorObolLight     = "#97B2B8" // Light muted
)

Obol brand colors — from blog.obol.org/branding.

View Source
const (
	GlyphOK      = "✓"
	GlyphCurrent = "▸"
	GlyphFail    = "✗"
	GlyphBusy    = "◐"
	GlyphStopped = "◼"
	GlyphBullet  = "●"
	GlyphPending = "·"
)

Status glyphs for multi-line status views (network status). The glyph is always printed; NO_COLOR (or a non-terminal stdout) only drops the color.

Variables

This section is empty.

Functions

func Banner() string

Banner returns the Obol Stack ASCII art rendered in brand colors.

func ColorDisabled added in v0.15.0

func ColorDisabled() bool

ColorDisabled reports whether the user opted out of colored output via NO_COLOR (any non-empty value).

func Heading added in v0.17.0

func Heading(title string) string

Heading renders a section heading in the same style as Info ("==> title"), for callers that build a frame as a string instead of printing directly.

func Paint added in v0.17.0

func Paint(kind, s string) string

Paint styles s for a status kind: "ok", "warn", "fail", "info", "dim", "bold" or "accent". Unknown kinds return s unchanged. Use it to compose lines that are written in one go (e.g. a redrawn --watch frame).

func StdinPromptable added in v0.15.0

func StdinPromptable() bool

StdinPromptable reports whether a raw prompt on stdin (sudo -v, legacy readers that don't go through UI) can be answered: stdin is a terminal and OBOL_NONINTERACTIVE is unset.

Types

type BrowserEnv added in v0.15.0

type BrowserEnv struct {
	// GOOS is runtime.GOOS (or a test override).
	GOOS string
	// Getenv reads an environment variable.
	Getenv func(string) string
	// LookPath reports whether a binary is on PATH (exec.LookPath shape).
	LookPath func(string) (string, error)
	// ProcVersion is the contents of /proc/version (Linux only; "" elsewhere).
	ProcVersion string
	// Interactive is true when stdout is a TTY, output is human (not JSON)
	// and OBOL_NONINTERACTIVE is not "true".
	Interactive bool
	// Disabled is true when the operator passed the global --no-open flag.
	Disabled bool
}

BrowserEnv is everything the open-a-browser decision depends on. It is a plain struct so the decision (PlanBrowserOpen) is a pure, table-testable function; DefaultBrowserEnv fills it from the real process.

func (BrowserEnv) IsWSL added in v0.15.0

func (e BrowserEnv) IsWSL() bool

IsWSL reports whether the environment looks like Windows Subsystem for Linux.

type BrowserPlan added in v0.15.0

type BrowserPlan struct {
	Open   bool
	Argv   []string
	Reason string
}

BrowserPlan is the outcome of PlanBrowserOpen: either a command to start (Open == true) or the reason the browser is left alone.

func PlanBrowserOpen added in v0.15.0

func PlanBrowserOpen(env BrowserEnv, url string) BrowserPlan

PlanBrowserOpen decides whether (and how) to open url in a browser. It never opens anything itself. Rules, in order:

  • --no-open / OBOL_NO_BROWSER → skip
  • non-interactive (no TTY, JSON output, OBOL_NONINTERACTIVE=true) → skip
  • CI → skip
  • over SSH (SSH_CONNECTION / SSH_TTY) → skip (the browser would open on the remote host, not in front of the operator)
  • WSL → wslview when on PATH, else explorer.exe
  • macOS → open
  • Windows → rundll32 url.dll,FileProtocolHandler
  • other Unix → xdg-open, only when DISPLAY or WAYLAND_DISPLAY is set

type ExecConfig

type ExecConfig struct {
	// Name is the display name shown in the spinner (e.g., "Deploying with helmfile").
	Name string

	// Cmd is the command to run.
	Cmd *exec.Cmd

	// Interactive runs the command with stdin/stdout/stderr connected directly
	// to the terminal. Use this for commands that may prompt for input (e.g. sudo).
	// Disables spinner and output capture.
	Interactive bool
}

ExecConfig configures how a subprocess is run.

type OutputMode added in v0.8.0

type OutputMode int

OutputMode controls the format of command output.

const (
	// OutputHuman is the default human-readable output mode.
	OutputHuman OutputMode = iota
	// OutputJSON produces machine-readable JSON on stdout.
	OutputJSON
)

func ParseOutputMode added in v0.8.0

func ParseOutputMode(s string) (OutputMode, error)

ParseOutputMode converts a string to an OutputMode.

type UI

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

UI provides consistent terminal output primitives.

func New

func New(verbose bool) *UI

New creates a UI instance. When verbose is true, subprocess output is streamed live instead of captured behind a spinner.

func NewForTest added in v0.10.0

func NewForTest(stdout, stderr io.Writer) *UI

NewForTest creates a UI instance that writes to the supplied writers. Use bytes.Buffer for stdout/stderr to capture output in unit tests.

func NewForTestTTY added in v0.17.0

func NewForTestTTY(stdout, stderr io.Writer) *UI

NewForTestTTY is NewForTest with prompts enabled, for exercising interactive pickers in unit tests (answers are read from os.Stdin).

func NewWithAllOptions added in v0.8.0

func NewWithAllOptions(verbose, quiet bool, output OutputMode) *UI

NewWithAllOptions creates a UI instance with full control over all modes.

func NewWithOptions

func NewWithOptions(verbose, quiet bool) *UI

NewWithOptions creates a UI instance with full control over verbose and quiet modes. Quiet mode suppresses all output except errors.

func (*UI) Blank

func (u *UI) Blank()

Blank prints an empty line.

func (*UI) Bold

func (u *UI) Bold(msg string)

Bold prints bold text.

func (*UI) CanPrompt added in v0.15.0

func (u *UI) CanPrompt() bool

CanPrompt reports whether prompts reach a person: a TTY, not JSON mode, and OBOL_NONINTERACTIVE unset.

func (*UI) Check added in v0.16.0

func (u *UI) Check(kind, title string, width int, msg, fix string)

Check prints one diagnostic line, " ✓ title message", with the symbol coloured by kind (ok, info, skip, warn, fail) and an optional dimmed "→ fix" line under it. title is padded to width. Warn and fail lines are shown even in quiet mode.

func (*UI) Confirm

func (u *UI) Confirm(msg string, defaultYes bool) bool

Confirm asks a yes/no question, returns true for "y"/"yes". In non-interactive mode, returns the default without prompting.

func (*UI) ConfirmOrFlag added in v0.15.0

func (u *UI) ConfirmOrFlag(msg, flag string) (bool, error)

ConfirmOrFlag asks a destructive yes/no question (default No). When no one can answer it, it returns an error naming the flag that skips it, rather than silently declining and exiting 0 as if the action had run.

func (*UI) DefaultBrowserEnv added in v0.15.0

func (u *UI) DefaultBrowserEnv() BrowserEnv

DefaultBrowserEnv builds a BrowserEnv from the real process and this UI's output mode.

func (*UI) Detail

func (u *UI) Detail(key, value string)

Detail prints an indented key-value pair: " key: value".

func (*UI) Dim

func (u *UI) Dim(msg string)

Dim prints dimmed/gray text for secondary information.

func (*UI) Error

func (u *UI) Error(msg string)

Error prints: ✗ message (red x, matching obolup.sh log_error). Not suppressed by quiet mode.

func (*UI) Errorf

func (u *UI) Errorf(format string, args ...any)

Errorf prints a formatted error message.

func (*UI) Exec

func (u *UI) Exec(cfg ExecConfig) error

Exec runs a subprocess with output capture and spinner.

Default mode (TTY, not verbose):

  • Shows spinner with config.Name
  • Captures stdout+stderr to buffer
  • On success: "✓ Name (Xs)"
  • On failure: "✗ Name" + dumps captured output to stderr

Verbose mode:

  • Shows "==> Name"
  • Streams stdout+stderr live, each line indented with dim "│" prefix

Non-TTY (pipe/CI):

  • Shows "Name..."
  • Streams live (no spinner)

func (*UI) ExecOutput

func (u *UI) ExecOutput(cfg ExecConfig) ([]byte, error)

ExecOutput runs a subprocess, captures stdout, and returns it. Stderr is captured and shown on error.

func (*UI) FormatActionableError

func (u *UI) FormatActionableError(err error, action string)

FormatActionableError renders an error with a concrete next-step command.

✗ Stack not running
  Run: obol stack up

func (*UI) FormatError

func (u *UI) FormatError(err error, hint string)

FormatError renders a structured error with an optional hint.

✗ something went wrong
  Hint: check your configuration

func (*UI) Info

func (u *UI) Info(msg string)

Info prints: ==> message (blue arrow, matching obolup.sh log_info).

func (*UI) Infof

func (u *UI) Infof(format string, args ...any)

Infof prints a formatted info message.

func (*UI) Input

func (u *UI) Input(msg string, defaultVal string) (string, error)

Input reads a single line of text input with an optional default. In non-interactive mode, returns the default or an error if no default is set.

func (*UI) InputWithSuffix added in v0.10.0

func (u *UI) InputWithSuffix(msg, defaultVal, suffix string) (string, error)

InputWithSuffix reads input like Input but renders an extra dimmed suffix between the default brace and the colon. Use this for hints that aren't part of the question itself — e.g. "[5] (5 OBOL ceiling):". The suffix is shown only when defaultVal is non-empty (so it stays adjacent to the "[default]" chip).

func (*UI) IsJSON added in v0.8.0

func (u *UI) IsJSON() bool

IsJSON returns whether JSON output mode is active.

func (*UI) IsQuiet

func (u *UI) IsQuiet() bool

IsQuiet returns whether quiet mode is enabled.

func (*UI) IsTTY

func (u *UI) IsTTY() bool

IsTTY returns whether stdout is an interactive terminal.

func (*UI) IsVerbose

func (u *UI) IsVerbose() bool

IsVerbose returns whether verbose mode is enabled.

func (*UI) JSON added in v0.8.0

func (u *UI) JSON(v any) error

JSON writes v as indented JSON to the real stdout (os.Stdout). This bypasses the stderr redirect so agents always get JSON on stdout.

func (*UI) OpenBrowser added in v0.15.0

func (u *UI) OpenBrowser(url string) bool

OpenBrowser opens url in the operator's browser when PlanBrowserOpen allows it and reports whether it did. It prints nothing: callers always print the URL themselves (see OpenURL for the print-and-maybe-open helper).

func (*UI) OpenURL added in v0.15.0

func (u *UI) OpenURL(label, url string, autoOpen bool) bool

OpenURL always prints "label: url" and, when autoOpen is set and the environment allows it, opens the URL in a browser. Reports whether a browser was opened. Human output only — in JSON mode it lands on stderr like every other UI line, so stdout stays clean.

func (*UI) Print

func (u *UI) Print(msg string)

Print writes a plain message to stdout (no prefix, no color).

func (*UI) Printf

func (u *UI) Printf(format string, args ...any)

Printf writes a formatted message to stdout.

func (*UI) RunWithSpinner

func (u *UI) RunWithSpinner(msg string, fn func() error) error

RunWithSpinner executes fn while displaying a spinner with msg.

On success: replaces spinner with "✓ msg (duration)". On failure: replaces spinner with "✗ msg", caller handles error display. In verbose mode or non-TTY: prints the message and runs fn without animation.

func (*UI) SecretInput

func (u *UI) SecretInput(msg string) (string, error)

SecretInput reads input without echoing (for API keys, passwords). In non-interactive mode, returns an error directing the user to use a flag.

func (*UI) Select

func (u *UI) Select(msg string, options []string, defaultIdx int) (int, error)

Select presents a numbered list and returns the selected index. In non-interactive mode, returns the default index without prompting.

func (*UI) SetNoBrowser added in v0.15.0

func (u *UI) SetNoBrowser(v bool)

SetNoBrowser disables every automatic browser open for this UI (the global --no-open flag).

func (*UI) Success

func (u *UI) Success(msg string)

Success prints: ✓ message (green check, matching obolup.sh log_success).

func (*UI) Successf

func (u *UI) Successf(format string, args ...any)

Successf prints a formatted success message.

func (*UI) SuggestCommand

func (u *UI) SuggestCommand(parent *cli.Command, command string)

SuggestCommand prints an error for an unknown subcommand of parent and suggests similarly named sibling commands (Levenshtein distance <= 2).

func (*UI) Warn

func (u *UI) Warn(msg string)

Warn prints: ! message (yellow bang, matching obolup.sh log_warn). Not suppressed by quiet mode.

func (*UI) WarnCount added in v0.15.0

func (u *UI) WarnCount() int64

WarnCount returns the number of warnings printed through u so far.

func (*UI) Warnf

func (u *UI) Warnf(format string, args ...any)

Warnf prints a formatted warning message.

Jump to

Keyboard shortcuts

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