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
- Variables
- func Interpret(msg string, raw ...interface{}) (string, string, io.Writer)
- func RegisterStatus(name, emoji, text string, color aec.ANSI)
- type Display
- type DisplayEntry
- type Input
- type NamedValue
- type Option
- type Status
- type Step
- type StepGroup
- type Table
- type TableEntry
- type Term
- func (t *Term) Close() error
- func (t *Term) DamageDone(r state.Rect, cr screen.CellReader) error
- func (t *Term) MoveCursor(_ state.Pos) error
- func (t *Term) Output(_ []byte) error
- func (t *Term) SetTermProp(_ state.TermAttr, _ interface{}) error
- func (t *Term) StringEvent(_ string, _ []byte) error
- func (t *Term) Write(b []byte) (int, error)
- type UI
Constants ¶
const ( StatusOK = "ok" StatusError = "error" StatusWarn = "warn" StatusTimeout = "timeout" StatusAbort = "abort" )
Status constants for step completion states.
const ( TermRows = 10 TermColumns = 100 )
Terminal dimensions for step output.
const ( Yellow = "yellow" Green = "green" Red = "red" )
Color constants for table entries.
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 ¶
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 RegisterStatus ¶
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 ¶
NewDisplay creates a new Display for the given writer.
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 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 ¶
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.
type TableEntry ¶
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 (*Term) DamageDone ¶
DamageDone handles screen damage events.
func (*Term) MoveCursor ¶
MoveCursor handles cursor movement (ignored).
func (*Term) SetTermProp ¶
SetTermProp handles terminal property changes (ignored).
func (*Term) StringEvent ¶
StringEvent handles string events (ignored).
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 NonInteractiveUI ¶
NonInteractiveUI returns a UI for non-interactive environments.