output

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package output owns every byte flow writes to a terminal. It is the only package outside internal/ciwait permitted to import a Charm library: commands ask the renderer for output, they never construct a style themselves. That is what keeps a later theme change, or a full TUI, a single-file change.

Index

Constants

View Source
const (
	SymOK      = "✔"
	SymFail    = "✘"
	SymWarn    = "!"
	SymSkip    = "·"
	SymPending = "◦"
)

Symbols used across the CLI and the CI progress display.

Variables

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

ErrAborted is returned when the user declines a confirmation or presses ctrl-c at a prompt. Callers map it to exit code 6.

Functions

func FangColorScheme

func FangColorScheme(plain bool) func(lipgloss.LightDarkFunc) fang.ColorScheme

FangColorScheme derives fang's help and error styling from flow's own palette, so help pages and command output never disagree about color.

plain is decided by main before fang parses flags, because fang renders before any command's pre-run hook has looked at --no-color or --json.

func FangErrorHandler

func FangErrorHandler(aborted, alreadyReported func(error) bool) fang.ErrorHandler

FangErrorHandler builds fang's error handler. It lives here rather than in internal/cli because its signature names fang's own types, and internal/cli must not import a Charm library.

aborted and alreadyReported are injected so this file needs no knowledge of flow's error taxonomy.

func Truncate

func Truncate(s string, width int) string

Truncate shortens s to width runes, ending with an ellipsis.

Types

type ErrNotInteractive

type ErrNotInteractive struct {
	// Flag is the escape hatch, e.g. "--yes".
	Flag string
	// What describes the decision that could not be made.
	What string
}

ErrNotInteractive is returned when a prompt is required but stdin is not a terminal. The message always names the flag that would have avoided it.

func (*ErrNotInteractive) Error

func (e *ErrNotInteractive) Error() string

type Options

type Options struct {
	JSON    bool
	NoColor bool
	Verbose int

	// Writers default to the process's own when nil. Tests inject buffers.
	Stdout io.Writer
	Stderr io.Writer
	Stdin  io.Reader
}

Options describe how a Renderer should behave. They come straight from the global flags on the root command.

type Renderer

type Renderer struct {
	Theme Theme
	Log   *log.Logger
	// contains filtered or unexported fields
}

Renderer is the single sink for user-facing output. The primary result goes to stdout; progress, warnings and logs go to stderr, so that `cd $(flow path)` keeps working.

func New

func New(opts Options) *Renderer

New builds a Renderer, deciding the color profile exactly once. --no-color, NO_COLOR, --json and a non-TTY writer each force plain ASCII; because the decision is made here and shared with huh, charmbracelet/log and fang, all four can never disagree about whether color is on.

func (*Renderer) ColorEnabled

func (r *Renderer) ColorEnabled() bool

ColorEnabled reports whether the terminal can render color. It is false for --no-color, NO_COLOR, --json and every non-terminal writer, which together are exactly the cases where a live progress display must fall back to plain appended lines.

func (*Renderer) Confirm

func (r *Renderer) Confirm(title, description string, defaultYes, assumeYes bool) error

Confirm asks a yes/no question. assumeYes short-circuits it (--yes), and a non-interactive session fails with the flag that would have answered it.

func (*Renderer) ErrWriter

func (r *Renderer) ErrWriter() io.Writer

ErrWriter exposes the profile-aware stderr writer, for the CI progress display which drives its own bubbletea program.

func (*Renderer) Failure

func (r *Renderer) Failure(format string, a ...any)

Failure writes an error line to stderr without terminating the command.

func (*Renderer) Field

func (r *Renderer) Field(label, value string)

Field writes an aligned "label: value" line to stdout.

func (*Renderer) Heading

func (r *Renderer) Heading(s string)

Heading writes a section heading to stderr.

func (*Renderer) Input

func (r *Renderer) Input(title, def string) (string, error)

Input asks for a free-text value, pre-filled with def.

func (*Renderer) Interactive

func (r *Renderer) Interactive() bool

Interactive reports whether prompting the user is possible.

func (*Renderer) JSON

func (r *Renderer) JSON(v any) error

JSON writes v as the command's single JSON object on stdout.

func (*Renderer) JSONError

func (r *Renderer) JSONError(code, message string)

JSONError writes the error envelope required in --json mode.

func (*Renderer) JSONMode

func (r *Renderer) JSONMode() bool

JSONMode reports whether --json was given.

func (*Renderer) Line

func (r *Renderer) Line(s string)

Line writes one bare line to stdout with no styling. This is the contract for `flow path` and `flow assets`: exactly one line, nothing else.

func (*Renderer) Printf

func (r *Renderer) Printf(format string, a ...any)

Printf writes formatted, styled text to stdout.

func (*Renderer) Println

func (r *Renderer) Println(a ...any)

Println writes a styled line to stdout.

func (*Renderer) Profile

func (r *Renderer) Profile() colorprofile.Profile

Profile reports the resolved color profile, so nested programs (bubbletea, huh) render with the same capabilities as plain output.

func (*Renderer) Select

func (r *Renderer) Select(title string, options []SelectOption) (string, error)

Select asks the user to choose one of options.

func (*Renderer) Spin

func (r *Renderer) Spin(ctx context.Context, title string, fn func() error) error

Spin runs fn while showing a one-line indeterminate spinner on stderr. In JSON or non-interactive mode it just runs fn, so scripted output stays clean.

func (*Renderer) Status

func (r *Renderer) Status(format string, a ...any)

Status writes a progress line to stderr, keeping stdout pipe-clean.

func (*Renderer) Stdin

func (r *Renderer) Stdin() io.Reader

Stdin exposes the input stream for prompts.

func (*Renderer) Success

func (r *Renderer) Success(format string, a ...any)

Success writes a success line to stderr.

func (*Renderer) Table

func (r *Renderer) Table(headers []string, rows [][]string)

Table renders rows with lipgloss/table, which measures rendered width and so aligns correctly even when cells carry ANSI escapes.

func (*Renderer) Warn

func (r *Renderer) Warn(format string, a ...any)

Warn writes a warning line to stderr.

func (*Renderer) Width

func (r *Renderer) Width() int

Width is the usable terminal width, or a sane default when not a terminal.

type SelectOption

type SelectOption struct {
	Label string
	Value string
}

SelectOption is one choice in a Select prompt.

type Theme

type Theme struct {
	Success lipgloss.Style
	Warn    lipgloss.Style
	Error   lipgloss.Style
	Muted   lipgloss.Style
	Heading lipgloss.Style
	Ticket  lipgloss.Style
	Path    lipgloss.Style
	Bold    lipgloss.Style

	// Raw colors, for the widgets that take a color rather than a style.
	AccentColor  color.Color
	SuccessColor color.Color
	WarnColor    color.Color
	ErrorColor   color.Color
	MutedColor   color.Color
}

Theme holds every style flow uses. Construct it once, from a LightDarkFunc, and pass it around: lipgloss v2 dropped AdaptiveColor in favour of resolving light/dark up front, so styles cannot be package-level values any more.

func NewTheme

func NewTheme(darkBackground bool) Theme

NewTheme builds the theme for a terminal with the given background.

Jump to

Keyboard shortcuts

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