ui

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package ui provides common UI components for the miren CLI

Index

Examples

Constants

View Source
const (
	Checkmark = "\u2713"
	Play      = "\u25B6"
)
View Source
const Indent = "  │"

Variables

This section is empty.

Functions

func BriefId added in v0.7.0

func BriefId(e entity.AttrGetter) string

BriefId returns the shortest usable identifier for an entity: short-id > name > full id.

func CleanEntityID

func CleanEntityID(id string) string

CleanEntityID removes common entity type prefixes from entity IDs for cleaner display. For example: "sandbox/sb-ABC123" -> "sb-ABC123", "app_version/meet-vXYZ" -> "meet-vXYZ"

func CleanStatus

func CleanStatus(status string) string

CleanStatus removes the "status." prefix from a status string without applying color.

func Completed

func Completed(str string, args ...any) string

func Confirm

func Confirm(opts ...ConfirmOption) (bool, error)

Confirm displays a yes/no confirmation prompt

func DisplayAppVersion

func DisplayAppVersion(version string) string

DisplayAppVersion formats an app version string by removing prefixes and bolding the app name. For example: "app_version/meet-vXYZ123" -> "**meet**-vXYZ123" (where **meet** is bold)

func DisplayShortID added in v0.7.0

func DisplayShortID(shortID, fullID string) string

DisplayShortID returns the short ID if available, otherwise falls back to CleanEntityID.

func DisplayStatus

func DisplayStatus(status string) string

DisplayStatus returns a colored version of the status string based on common status values. It also removes the "status." prefix if present.

func FriendlyId added in v0.7.0

func FriendlyId(e entity.AttrGetter) string

FriendlyId returns the most human-readable identifier: name > short-id > full id.

func Hyperlink(url, text string) string

Hyperlink creates a clickable terminal hyperlink using the OSC 8 escape sequence with underline styling. Raw SGR sequences are used so the result can be safely combined with lipgloss-rendered text without interference.

We use a plain underline (\x1b[4m) rather than the colon-style dotted underline (\x1b[4:4m): Terminal.app and other terminals don't understand colon SGR subparameters and misrender them as a stray background that bleeds across the line.

When stdout is not a TTY, returns just the text with no escape sequences.

func HyperlinkStyled added in v0.7.0

func HyperlinkStyled(url, text string, color lipgloss.TerminalColor) string

HyperlinkStyled is like Hyperlink but also applies a foreground color, which adapts to the terminal's profile and background via the theme's color roles.

When stdout is not a TTY, returns just the text with no escape sequences.

func IsInteractive

func IsInteractive() bool

IsInteractive checks if we're in an interactive terminal

func IsTTY added in v0.7.0

func IsTTY() bool

IsTTY reports whether stdout is connected to a terminal.

func PromptForInput

func PromptForInput(opts ...PromptOption) (string, error)

PromptForInput displays an interactive text input prompt and returns the user's input

func RenderMarkdownLink(s string, color lipgloss.TerminalColor) string

RenderMarkdownLink parses a markdown-style link "[text](url)" and renders it as a clickable terminal hyperlink in the given theme color.

When stdout is not a TTY, renders as "text (url)" for readability in pipes/logs. If the input isn't a valid markdown link, it's returned as-is.

func Run

func Run(prefix string, cmd *exec.Cmd) error

func TerminalWidth added in v0.7.0

func TerminalWidth() int

TerminalWidth returns the current terminal width, or 0 if stdout is not a TTY.

Types

type Action added in v0.13.0

type Action struct {
	Command string
	Note    string
}

Action is a command the reader can run next, with a short note on what it does. Commands are never wrapped, so they stay copy-pasteable.

type Column

type Column struct {
	Title      string
	Width      int
	NoTruncate bool // If true, this column won't be truncated when scaling
	WordWrap   bool // If true, text that exceeds Width is wrapped instead of truncated
}

Column defines a table column with title and width

func AutoSizeColumns

func AutoSizeColumns(headers []string, rows []Row, builder *ColumnBuilder) []Column

AutoSizeColumns calculates optimal column widths based on content, respecting terminal width and column configuration hints. Pass nil for builder to use default behavior.

type ColumnBuilder added in v0.0.2

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

ColumnBuilder helps configure column options using a fluent API

func Columns added in v0.0.2

func Columns() *ColumnBuilder

Columns creates a new ColumnBuilder for configuring column options

func (*ColumnBuilder) MaxWidth added in v0.0.2

func (b *ColumnBuilder) MaxWidth(index, width int) *ColumnBuilder

MaxWidth sets the maximum width for a specific column

func (*ColumnBuilder) MinWidth added in v0.0.2

func (b *ColumnBuilder) MinWidth(index, width int) *ColumnBuilder

MinWidth sets the minimum width for a specific column when scaling

func (*ColumnBuilder) NoTruncate added in v0.0.2

func (b *ColumnBuilder) NoTruncate(indices ...int) *ColumnBuilder

NoTruncate marks the specified column indices as non-truncatable

func (*ColumnBuilder) WordWrap added in v0.4.0

func (b *ColumnBuilder) WordWrap(indices ...int) *ColumnBuilder

WordWrap marks the specified column indices as word-wrapping. Wrapped columns split text across multiple lines at word boundaries instead of truncating with an ellipsis.

type ColumnHint added in v0.0.2

type ColumnHint struct {
	MaxWidth   int  // Maximum width (0 = no limit)
	NoTruncate bool // If true, this column won't be scaled down
	MinWidth   int  // Minimum width when scaling (0 = use default)
	WordWrap   bool // If true, wrap text instead of truncating
}

ColumnHint provides configuration hints for a specific column

type ConfirmOption

type ConfirmOption func(*confirmConfig)

ConfirmOption configures a confirmation prompt

func WithAffirmative

func WithAffirmative(text string) ConfirmOption

WithAffirmative sets the affirmative response text (default: "yes")

func WithDefault

func WithDefault(defaultYes bool) ConfirmOption

WithDefault sets the default response when user just presses enter

func WithIndent added in v0.0.2

func WithIndent(indent string) ConfirmOption

WithIndent sets the indentation prefix for the prompt

func WithMessage

func WithMessage(message string) ConfirmOption

WithMessage sets the confirmation message

func WithNegative

func WithNegative(text string) ConfirmOption

WithNegative sets the negative response text (default: "no")

type Definition added in v0.3.1

type Definition struct {
	Term        string
	Description string
	Details     []DefinitionDetail
}

Definition represents a single definition entry with a term, description, and optional details

type DefinitionDetail added in v0.3.1

type DefinitionDetail struct {
	Name     string
	Type     string
	Required bool
}

DefinitionDetail represents a child item in a definition (displayed as a tree)

type DefinitionList added in v0.3.1

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

DefinitionList renders a list of definitions with tree-style details

func NewDefinitionList added in v0.3.1

func NewDefinitionList(items []Definition, opts ...DefinitionListOption) *DefinitionList

NewDefinitionList creates a new definition list

func (*DefinitionList) Render added in v0.3.1

func (d *DefinitionList) Render() string

Render generates the string representation

type DefinitionListOption added in v0.3.1

type DefinitionListOption func(*DefinitionList)

DefinitionListOption is a function that configures a DefinitionList

func WithDefinitionListStyles added in v0.3.1

func WithDefinitionListStyles(styles DefinitionListStyles) DefinitionListOption

WithDefinitionListStyles sets custom styles

func WithDefinitionListTitle added in v0.3.1

func WithDefinitionListTitle(title string) DefinitionListOption

WithDefinitionListTitle sets the title

type DefinitionListStyles added in v0.3.1

type DefinitionListStyles struct {
	Title       lipgloss.Style
	Term        lipgloss.Style
	Description lipgloss.Style
	DetailName  lipgloss.Style
	DetailType  lipgloss.Style
	Required    lipgloss.Style
	TreeLine    lipgloss.Style
}

DefinitionListStyles contains the styling configuration

func DefaultDefinitionListStyles added in v0.3.1

func DefaultDefinitionListStyles() DefinitionListStyles

DefaultDefinitionListStyles returns the default styling

type Diagnostic added in v0.13.0

type Diagnostic struct {
	// Summary is the one-line headline: what failed, in the reader's terms.
	Summary string
	// Detail is prose explaining what was observed. Wrapped to terminal width.
	Detail string
	// Facts are label/value context pairs, rendered in an aligned column.
	Facts []Fact
	// Causes are possible explanations, most common first. This section only
	// appears when we genuinely don't know which one it is: a diagnosis we're
	// sure of states the cause outright in Detail instead.
	Causes []string
	// Actions are suggested next commands.
	Actions []Action
	// Cause is the underlying error. It is always reachable via errors.Unwrap
	// and included in Error(), but only displayed in the rich block when
	// ShowCause is set, since raw transport errors are noise for most readers.
	Cause error
	// ShowCause displays Cause in the rendered block (wire it to -v).
	ShowCause bool
}

Diagnostic is a structured, human-facing failure report. It implements TerminalError, so returning one from a command yields a rich block on a terminal while Error() stays a single line suitable for logs and wrapping.

Both renderers read the same fields, which is the point: a hand-written WriteForTerminal alongside a hand-written Error() drifts apart the first time someone edits one of them.

Only fill in what you actually know. Every section is omitted when empty, and per the doctor design rule, Causes should only list possibilities the reader can act on.

Example

ExampleDiagnostic pins the exact rendered layout. Output is plain here because go test's stdout isn't a terminal, which is also the pipe/CI shape.

d := &Diagnostic{
	Summary: `couldn't reach cluster "prod" at cluster.example.com:8443`,
	Detail:  "Nothing answered after 5s. The hostname resolved, so either the server isn't running or something between here and there is blocking it.",
	Facts: []Fact{
		{Label: "Cluster", Value: "prod"},
		{Label: "Address", Value: "cluster.example.com:8443"},
	},
	Causes: []string{"the server isn't running", "a firewall is blocking UDP"},
	Actions: []Action{
		{Command: "miren doctor", Note: "check what's reachable"},
		{Command: "miren cluster list", Note: "see configured clusters"},
	},
}
d.WriteForTerminal(os.Stdout)
Output:
ERROR: couldn't reach cluster "prod" at cluster.example.com:8443

  Nothing answered after 5s. The hostname resolved, so either the server isn't
  running or something between here and there is blocking it.

  Cluster  prod
  Address  cluster.example.com:8443

  Possible causes
    • the server isn't running
    • a firewall is blocking UDP

  Try
    miren doctor          check what's reachable
    miren cluster list    see configured clusters

func (*Diagnostic) Error added in v0.13.0

func (d *Diagnostic) Error() string

func (*Diagnostic) Unwrap added in v0.13.0

func (d *Diagnostic) Unwrap() error

Unwrap exposes the underlying error so errors.Is/As still reach it through the Diagnostic. Doctor relies on this to re-classify a failure it was handed.

func (*Diagnostic) WriteForTerminal added in v0.13.0

func (d *Diagnostic) WriteForTerminal(w io.Writer)

WriteForTerminal renders the diagnostic at error severity.

func (*Diagnostic) WriteWithSeverity added in v0.13.0

func (d *Diagnostic) WriteWithSeverity(w io.Writer, sev Severity)

WriteWithSeverity renders the diagnostic with an explicit severity, for callers that surface the same error type as a non-fatal warning.

type Fact added in v0.13.0

type Fact struct {
	Label string
	Value string
}

Fact is a label/value pair shown in an aligned column, for context the reader needs but shouldn't have to parse out of prose (cluster, address, elapsed).

type Hint added in v0.3.1

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

Hint renders a dimmed hint/tip message

func NewHint added in v0.3.1

func NewHint(text string) *Hint

NewHint creates a new hint with the given text

func (*Hint) Render added in v0.3.1

func (h *Hint) Render() string

Render generates the string representation

func (*Hint) WithStyle added in v0.3.1

func (h *Hint) WithStyle(style lipgloss.Style) *Hint

WithStyle sets a custom style for the hint

type List

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

func NewList

func NewList(w io.Writer) *List

type NamedValue added in v0.3.1

type NamedValue struct {
	Label     string
	Value     string
	ValueType ValueType
}

NamedValue represents a label-value pair for display

func NewNamedValue added in v0.3.1

func NewNamedValue(label string, value any) NamedValue

NewNamedValue creates a NamedValue with automatic type detection

type NamedValueList added in v0.3.1

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

NamedValueList renders a list of named values with right-aligned labels

func NewNamedValueList added in v0.3.1

func NewNamedValueList(items []NamedValue, opts ...NamedValueOption) *NamedValueList

NewNamedValueList creates a new named value list

func (*NamedValueList) Render added in v0.3.1

func (n *NamedValueList) Render() string

Render generates the string representation of the named value list

type NamedValueOption added in v0.3.1

type NamedValueOption func(*NamedValueList)

NamedValueOption is a function that configures a NamedValueList

func WithNamedValueStyles added in v0.3.1

func WithNamedValueStyles(styles NamedValueStyles) NamedValueOption

WithNamedValueStyles sets custom styles for the named value list

type NamedValueStyles added in v0.3.1

type NamedValueStyles struct {
	Label       lipgloss.Style
	Separator   string
	StringValue lipgloss.Style
	NumberValue lipgloss.Style
	BoolValue   lipgloss.Style
	NullValue   lipgloss.Style
	OtherValue  lipgloss.Style
}

NamedValueStyles contains the styling configuration for named values

func DefaultNamedValueStyles added in v0.3.1

func DefaultNamedValueStyles() NamedValueStyles

DefaultNamedValueStyles returns the default styling for named values

type PickerItem

type PickerItem interface {
	// Row returns the table row data for this item
	Row() []string
	// ID returns a unique identifier for this item
	ID() string
}

PickerItem represents an item that can be selected in the picker

func RunPicker

func RunPicker(items []PickerItem, opts ...PickerOption) (PickerItem, error)

RunPicker runs an interactive picker and returns the selected item

type PickerModel

type PickerModel struct {
	Title   string
	Headers []string
	Items   []PickerItem

	Selected  PickerItem
	Cancelled bool
	Footer    string

	// Optional filter function to disable certain items
	IsDisabled func(item PickerItem) bool
	// Optional message for disabled items
	DisabledMessage string
	// contains filtered or unexported fields
}

PickerModel is a table-based picker for selecting from a list of items

func NewPicker

func NewPicker(items []PickerItem, opts ...PickerOption) *PickerModel

NewPicker creates a new picker model with the given options

func (*PickerModel) Init

func (m *PickerModel) Init() tea.Cmd

func (*PickerModel) SetCursor

func (m *PickerModel) SetCursor(index int)

SetCursor sets the cursor to the specified index

func (*PickerModel) Update

func (m *PickerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

func (*PickerModel) View

func (m *PickerModel) View() string

type PickerOption

type PickerOption func(*PickerModel)

Picker configuration options

func WithDisabledCheck

func WithDisabledCheck(check func(PickerItem) bool, message string) PickerOption

WithDisabledCheck sets a function to determine if items are disabled

func WithFooter

func WithFooter(footer string) PickerOption

WithFooter sets the picker footer text

func WithHeaders

func WithHeaders(headers []string) PickerOption

WithHeaders sets the table headers for the picker

func WithTitle

func WithTitle(title string) PickerOption

WithTitle sets the picker title

type PromptOption

type PromptOption func(*promptConfig)

PromptOption configures a text input prompt

func WithCharLimit

func WithCharLimit(limit int) PromptOption

WithCharLimit sets the character limit (0 for unlimited)

func WithLabel

func WithLabel(label string) PromptOption

WithLabel sets the prompt label

func WithPlaceholder

func WithPlaceholder(placeholder string) PromptOption

WithPlaceholder sets the placeholder text

func WithSensitive

func WithSensitive(sensitive bool) PromptOption

WithSensitive makes the input masked (for passwords/secrets)

func WithWidth

func WithWidth(width int) PromptOption

WithWidth sets the input field width

type Row

type Row []string

Row represents a single row of data in the table

type Severity added in v0.13.0

type Severity int

Severity selects the label a Diagnostic leads with and the color it wears.

const (
	SeverityError Severity = iota
	SeverityWarning
)

type SeverityTerminalError added in v0.13.0

type SeverityTerminalError interface {
	TerminalError
	WriteWithSeverity(w io.Writer, sev Severity)
}

SeverityTerminalError is a TerminalError that renders its own severity label (an "ERROR:"/"WARNING:" prefix, colored to match). The display boundary must not add a prefix of its own to these, and should pass the severity it wants instead — the same error is an error in one place and a warning in another.

type SimplePickerItem

type SimplePickerItem struct {
	Text   string
	Active bool
}

SimplePickerItem is a basic implementation of PickerItem for single-column pickers

func (SimplePickerItem) ID

func (s SimplePickerItem) ID() string

func (SimplePickerItem) Row

func (s SimplePickerItem) Row() []string

type Table

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

Table represents a simple, non-interactive table for CLI output

func NewTable

func NewTable(opts ...TableOption) *Table

NewTable creates a new table with the given options

func (*Table) Render

func (t *Table) Render() string

Render generates the string representation of the table

type TableOption

type TableOption func(*Table)

TableOption is a function that configures a table

func WithColumns

func WithColumns(cols []Column) TableOption

WithColumns sets the columns for the table

func WithRows

func WithRows(rows []Row) TableOption

WithRows sets the rows for the table

func WithStyles

func WithStyles(styles TableStyles) TableOption

WithStyles sets custom styles for the table

func WithTableTitle added in v0.4.0

func WithTableTitle(title string) TableOption

WithTableTitle sets a title displayed above the table header

type TablePickerItem

type TablePickerItem struct {
	Columns []string
	ItemID  string
}

TablePickerItem is a multi-column implementation of PickerItem

func (TablePickerItem) ID

func (t TablePickerItem) ID() string

func (TablePickerItem) Row

func (t TablePickerItem) Row() []string

type TableStyles

type TableStyles struct {
	Header lipgloss.Style
	Cell   lipgloss.Style
	Title  lipgloss.Style
}

TableStyles contains the styling configuration for the table

func DefaultTableStyles

func DefaultTableStyles() TableStyles

DefaultTableStyles returns the default styling for tables

type TerminalError added in v0.7.0

type TerminalError interface {
	error
	WriteForTerminal(w io.Writer)
}

TerminalError is an optional interface for errors that can render a rich, human-friendly representation to a terminal. Errors that implement this interface get colorized, multi-line output with source context when displayed through the CLI.

The Error() method should still return a plain-text representation suitable for logging and wrapping. WriteForTerminal provides the enhanced version for interactive use.

This follows the same pattern as io.WriterTo and http.Flusher — a type assertion at the display boundary unlocks richer behavior.

Design note: this interface is rendering-only. The underlying error type should carry structured data (source locations, hints, etc.) as exported fields so that the data can be serialized over RPC. Client-side code can then reconstruct a TerminalError from the wire data for local rendering.

type ValueType added in v0.3.1

type ValueType int

ValueType represents the type of a value for styling purposes

const (
	ValueTypeString ValueType = iota
	ValueTypeNumber
	ValueTypeBool
	ValueTypeNull
	ValueTypeOther
)

Jump to

Keyboard shortcuts

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