terminal

package
v0.17.2 Latest Latest
Warning

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

Go to latest
Published: Mar 9, 2026 License: MPL-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package terminal provides terminal UI abstractions for CLI applications.

Originally licensed under MPL-2.0 from HashiCorp Waypoint Plugin SDK: https://github.com/hashicorp/waypoint-plugin-sdk/tree/dcdb2a03f7144a6e9a552351aeadd1791564f70e/terminal

Modifications (not limited to):

  • Removed glint dependency, using direct stdout writes for Output
  • Added Successf, Errorf, ErrorWithSummary, Warnf, Infof, JSON, Close, Confirm methods to UI
  • Removed WAYPOINT_FORCE_EMOJI, using LANG env var for UTF-8 detection
  • Added RegisterStatus for custom status registration
  • Added shell command auto-highlighting in examples

Index

Constants

View Source
const (
	StatusOK      = "ok"
	StatusError   = "error"
	StatusWarn    = "warn"
	StatusTimeout = "timeout"
	StatusAbort   = "abort"
)

Status constants for step completion states.

View Source
const (
	TermRows    = 10
	TermColumns = 100
)

Terminal dimensions for step output.

View Source
const (
	Yellow = "yellow"
	Green  = "green"
	Red    = "red"
)

Color constants for table entries.

View Source
const (
	HeaderStyle      = "header"
	ErrorStyle       = "error"
	ErrorBoldStyle   = "error-bold"
	WarningStyle     = "warning"
	WarningBoldStyle = "warning-bold"
	InfoStyle        = "info"
	SuccessStyle     = "success"
	SuccessBoldStyle = "success-bold"
)

Style constants for output formatting.

Variables

View Source
var ErrNonInteractive = errors.New("noninteractive UI doesn't support this operation")

ErrNonInteractive is returned when Input is called on a non-Interactive UI.

Functions

func Interpret

func Interpret(msg string, raw ...interface{}) (string, string, io.Writer)

Interpret decomposes the msg and arguments into the message, style, and writer

func RegisterStatus

func RegisterStatus(name, emoji, text string, color aec.ANSI)

RegisterStatus registers a custom status with emoji, text fallback, and color. This allows packages to define their own status types.

Types

type Display

type Display struct {
	Entries []*DisplayEntry
	// contains filtered or unexported fields
}

Display manages terminal output with live updating capabilities.

func NewDisplay

func NewDisplay(ctx context.Context, w io.Writer) *Display

NewDisplay creates a new Display for the given writer.

func (*Display) Close

func (d *Display) Close() error

Close waits for the display to finish.

func (*Display) Display

func (d *Display) Display(ctx context.Context)

Display runs the display loop.

func (*Display) NewStatus

func (d *Display) NewStatus() *DisplayEntry

NewStatus creates a new status entry.

func (*Display) NewStatusWithBody

func (d *Display) NewStatusWithBody(lines int) *DisplayEntry

NewStatusWithBody creates a new status entry with body lines.

type DisplayEntry

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

DisplayEntry represents a single entry in the display.

func (*DisplayEntry) SetBody

func (e *DisplayEntry) SetBody(line int, data string)

SetBody sets a body line.

func (*DisplayEntry) SetStatus

func (e *DisplayEntry) SetStatus(status string)

SetStatus sets the status of the entry.

func (*DisplayEntry) StartSpinner

func (e *DisplayEntry) StartSpinner()

StartSpinner starts the spinner animation.

func (*DisplayEntry) StopSpinner

func (e *DisplayEntry) StopSpinner()

StopSpinner stops the spinner animation.

func (*DisplayEntry) Update

func (e *DisplayEntry) Update(str string, args ...interface{})

Update updates the entry text.

type Input

type Input struct {
	// Prompt is a single-line prompt to give the user such as "Continue?"
	// The user will input their answer after this prompt.
	Prompt string

	// Style is the style to apply to the input. If this is blank,
	// the output won't be colorized in any way.
	Style string

	// True if this input is a secret. The input will be masked.
	Secret bool
}

Input is the configuration for an input.

type NamedValue

type NamedValue struct {
	Name  string
	Value interface{}
}

NamedValue is passed to UI.NamedValues to provide a nicely formatted key: value output.

type Option

type Option func(*config)

Option controls output styling.

func WithErrorStyle

func WithErrorStyle() Option

WithErrorStyle styles the output as an error message.

func WithHeaderStyle

func WithHeaderStyle() Option

WithHeaderStyle styles the output like a header denoting a new section of execution. This should only be used with single-line output. Multi-line output will not look correct.

func WithInfoStyle

func WithInfoStyle() Option

WithInfoStyle styles the output like it's formatted information.

func WithStyle

func WithStyle(style string) Option

WithStyle sets a custom style for the output.

func WithSuccessStyle

func WithSuccessStyle() Option

WithSuccessStyle styles the output as a success message.

func WithWarningStyle

func WithWarningStyle() Option

WithWarningStyle styles the output as an error message.

func WithWriter

func WithWriter(w io.Writer) Option

WithWriter specifies the writer for the output.

type Status

type Status interface {
	// Update writes a new status. This should be a single line.
	Update(msg string)

	// Indicate that a step has finished, confering an ok, error, or warn upon
	// it's finishing state. If the status is not StatusOK, StatusError, or StatusWarn
	// then the status text is written directly to the output, allowing for custom
	// statuses.
	Step(status, msg string)

	// Close should be called when the live updating is complete. The
	// status will be cleared from the line.
	Close() error
}

Status is used to provide an updating status to the user. The status usually has some animated element along with it such as a spinner.

type Step

type Step interface {
	// The Writer has data written to it as though it was a terminal. This will appear
	// as body text under the Step's message and status.
	TermOutput() io.Writer

	// Change the Steps displayed message
	Update(string, ...interface{})

	// Update the status of the message. Supported values are in status.go.
	Status(status string)

	// Called when the step has finished. This must be done otherwise the StepGroup
	// will wait forever for it's Steps to finish.
	Done()

	// Sets the status to Error and finishes the Step if it's not already done.
	// This is usually done in a defer so that any return before the Done() shows
	// the Step didn't completely properly.
	Abort()
}

A Step is the unit of work within a StepGroup. This can be driven by concurrent goroutines safely.

type StepGroup

type StepGroup interface {
	// Start a step in the output with the arguments making up the initial message
	Add(string, ...interface{}) Step

	// Wait for all steps to finish. This allows a StepGroup to be used like
	// a sync.WaitGroup with each step being run in a separate goroutine.
	// This must be called to properly clean up the step group.
	Wait()
}

StepGroup is a group of steps (that may be concurrent).

type Table

type Table struct {
	Headers []string
	Rows    [][]TableEntry
}

Table is passed to UI.Table to provide a nicely formatted table.

func NewTable

func NewTable(headers ...string) *Table

NewTable creates a new Table structure that can be used with UI.Table.

func (*Table) Rich

func (t *Table) Rich(cols []string, colors []string)

Rich adds a row to the table.

type TableEntry

type TableEntry struct {
	Value string
	Color string
}

TableEntry is a single entry for a table.

type Term

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

Term provides terminal emulation for step output.

func NewTerm

func NewTerm(ctx context.Context, d *DisplayEntry, height, width int) (*Term, error)

NewTerm creates a new terminal emulator.

func (*Term) Close

func (t *Term) Close() error

Close closes the terminal.

func (*Term) DamageDone

func (t *Term) DamageDone(r state.Rect, cr screen.CellReader) error

DamageDone handles screen damage events.

func (*Term) MoveCursor

func (t *Term) MoveCursor(_ state.Pos) error

MoveCursor handles cursor movement (ignored).

func (*Term) Output

func (t *Term) Output(_ []byte) error

Output handles output events (ignored).

func (*Term) SetTermProp

func (t *Term) SetTermProp(_ state.TermAttr, _ interface{}) error

SetTermProp handles terminal property changes (ignored).

func (*Term) StringEvent

func (t *Term) StringEvent(_ string, _ []byte) error

StringEvent handles string events (ignored).

func (*Term) Write

func (t *Term) Write(b []byte) (int, error)

Write writes to the terminal.

type UI

type UI interface {
	// Input asks the user for input. This will immediately return an error
	// if the UI doesn't support interaction. You can test for interaction
	// ahead of time with Interactive().
	Input(*Input) (string, error)

	// Interactive returns true if this prompt supports user interaction.
	// If this is false, Input will always error.
	Interactive() bool

	// Confirm asks the user for a yes/no confirmation. Returns true if confirmed.
	// Returns an error if the UI doesn't support interaction.
	Confirm(prompt string) (bool, error)

	// Output outputs a message directly to the terminal. The remaining
	// arguments should be interpolations for the format string. After the
	// interpolations you may add Options.
	Output(string, ...interface{})

	// NamedValues outputs data as a table of data. Each entry is a row which
	// will be output with the columns lined up nicely.
	NamedValues([]NamedValue, ...Option)

	// OutputWriters returns stdout and stderr writers. These are usually
	// but not always TTYs. This is useful for subprocesses, network requests,
	// etc. Note that writing to these is not thread-safe by default so
	// you must take care that there is only ever one writer.
	OutputWriters() (stdout, stderr io.Writer, err error)

	// Status returns a live-updating status that can be used for single-line
	// status updates that typically have a spinner or some similar style.
	// While a Status is live (Close isn't called), other methods on UI should
	// NOT be called.
	Status() Status

	// Table outputs the information formatted into a Table structure.
	Table(*Table, ...Option)

	// StepGroup returns a value that can be used to output individual (possibly
	// parallel) steps that have their own message, status indicator, spinner, and
	// body. No other output mechanism (Output, Input, Status, etc.) may be
	// called until the StepGroup is complete.
	StepGroup() StepGroup

	// Successf outputs a success message.
	Successf(format string, a ...any)

	// Errorf outputs an error message.
	Errorf(format string, a ...any)

	// ErrorWithSummary outputs an error message with a wrapped error.
	ErrorWithSummary(err error, summary string, a ...any)

	// Warnf outputs a warning message.
	Warnf(format string, a ...any)

	// Infof outputs an info message.
	Infof(format string, a ...any)

	// JSON outputs a value as indented JSON.
	JSON(v any) error

	// Close cleans up any resources used by the UI.
	Close() error
}

UI is the primary interface for interacting with a user via the CLI.

Some of the methods on this interface return values that have a lifetime such as Status and StepGroup. While these are still active (haven't called the close or equivalent method on these values), no other method on the UI should be called.

func ConsoleUI

func ConsoleUI(ctx context.Context) UI

ConsoleUI returns a UI which will write to the current processes stdout/stderr.

func NonInteractiveUI

func NonInteractiveUI(_ context.Context) UI

NonInteractiveUI returns a UI for non-interactive environments.

Directories

Path Synopsis
Package spinner provides terminal spinner animations.
Package spinner provides terminal spinner animations.

Jump to

Keyboard shortcuts

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