Documentation
¶
Overview ¶
Package output provides structured output formatting, table rendering, and progress indicators for CLI commands.
Output Formats ¶
Commands can produce output in multiple formats controlled by the --output flag. The Format type defines the supported formats: text (default), json, yaml, csv, tsv, and markdown.
The Response type provides a standard JSON envelope for all command output, and the Emit/EmitError helpers handle format-aware serialisation.
Table Rendering ¶
TableWriter renders tabular data with automatic column sizing, sorting, and format-aware output. Use struct tags to define columns:
type Row struct {
Name string `table:"NAME,sortable"`
Status string `table:"STATUS"`
}
tw := output.NewTableWriter(os.Stdout, output.FormatText)
tw.WriteRows(rows)
Progress Indicators ¶
Three components handle long-running operation feedback:
- Spin/SpinWithResult — animated spinner for indeterminate operations
- Progress — progress bar for operations with known total
- Status — multi-step status display with success/warn/fail icons
All three detect interactive mode (TTY + CI check) and fall back to plain text logging in non-interactive environments.
// Spinner
output.Spin(ctx, "Checking for updates", func(ctx context.Context) error {
return updater.Check(ctx)
})
// Progress bar
bar := output.NewProgress(len(files), "Processing")
for _, f := range files {
processFile(f)
bar.Increment()
}
bar.Done()
// Status display
s := output.NewStatus()
s.Update("Loading config")
s.Success("Config loaded")
s.Done()
Package output provides structured output formatting for CLI commands. It supports text (default) and JSON output modes, allowing commands to produce machine-readable output for CI/CD pipelines and scripting.
Index ¶
- Constants
- func Emit(cmd *cobra.Command, resp Response) error
- func EmitError(cmd *cobra.Command, commandName string, err error) error
- func IsInteractive() bool
- func IsJSONOutput(cmd *cobra.Command) bool
- func RenderMarkdown(content string) string
- func Spin(ctx context.Context, msg string, fn func(ctx context.Context) error) error
- func SpinWithResult[T any](ctx context.Context, msg string, fn func(ctx context.Context) (T, error)) (T, error)
- type Column
- type Format
- type Progress
- type Response
- type Status
- type TableOption
- type TableWriter
- type Writer
Examples ¶
Constants ¶
const ( StatusSuccess = "success" StatusError = "error" StatusWarning = "warning" )
Status constants for the Response envelope.
Variables ¶
This section is empty.
Functions ¶
func Emit ¶ added in v1.7.0
Emit writes a Response to cmd.OutOrStdout() when --output is "json". It is a no-op when the output format is text or the flag is absent.
func IsInteractive ¶ added in v1.9.6
func IsInteractive() bool
IsInteractive returns true if stdout is a TTY and CI mode is not active. Used by progress helpers to decide between animated TUI output and plain text fallback.
func IsJSONOutput ¶ added in v1.7.0
IsJSONOutput returns true if the --output flag on the command is set to "json".
func RenderMarkdown ¶ added in v1.7.0
RenderMarkdown renders markdown content to styled ANSI terminal output via glamour. It detects the terminal width automatically, falling back to 80 columns. If glamour fails for any reason, the original content is returned unchanged.
func Spin ¶ added in v1.9.6
Spin shows a spinner with a message while fn executes. In interactive terminals, displays an animated spinner. In non-interactive environments (CI, piped output), prints plain text. The context is passed to fn and used for cancellation.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/phpboyscout/go-tool-base/pkg/output"
)
func main() {
// Spin shows a spinner while the function executes.
// In non-interactive environments (CI), it prints plain text instead.
err := output.Spin(context.Background(), "Loading data", func(ctx context.Context) error {
time.Sleep(10 * time.Millisecond)
return nil
})
if err != nil {
fmt.Println("Error:", err)
}
}
Output:
func SpinWithResult ¶ added in v1.9.6
func SpinWithResult[T any](ctx context.Context, msg string, fn func(ctx context.Context) (T, error)) (T, error)
SpinWithResult is like Spin but returns a value alongside the error.
Example ¶
package main
import (
"context"
"fmt"
"github.com/phpboyscout/go-tool-base/pkg/output"
)
func main() {
result, err := output.SpinWithResult(context.Background(), "Fetching version", func(ctx context.Context) (string, error) {
return "v1.2.3", nil
})
if err == nil {
fmt.Println("Version:", result)
}
}
Output:
Types ¶
type Column ¶ added in v1.8.0
type Column struct {
// Header is the display name shown in the table header row.
Header string
// Field is the struct field name or map key to extract the value from.
Field string
// Width is the fixed column width. Zero means auto-sized to content.
Width int
// Sortable indicates this column can be used as a sort key.
Sortable bool
// Formatter is an optional function to format the cell value.
Formatter func(any) string
}
Column defines a single table column.
type Format ¶
type Format string
Format represents the output format for commands.
const ( // FormatText is the default human-readable output format. FormatText Format = "text" // FormatJSON produces machine-readable JSON output. FormatJSON Format = "json" // FormatYAML produces machine-readable YAML output. FormatYAML Format = "yaml" // FormatCSV produces comma-separated values output. FormatCSV Format = "csv" // FormatMarkdown produces a pipe-delimited markdown table with header separators. FormatMarkdown Format = "markdown" // FormatTSV produces tab-separated values output for shell pipelines. FormatTSV Format = "tsv" )
type Progress ¶ added in v1.9.6
type Progress struct {
// contains filtered or unexported fields
}
Progress tracks progress of a known-total operation. In interactive terminals, displays an animated progress bar. In non-interactive environments, logs periodic status lines. Safe for concurrent use from multiple goroutines.
func NewProgress ¶ added in v1.9.6
NewProgress creates a progress indicator with the given total and description.
Example ¶
package main
import (
"github.com/phpboyscout/go-tool-base/pkg/output"
)
func main() {
// Progress tracks a known-total operation.
bar := &output.Progress{}
_ = bar // In real usage: bar = output.NewProgress(100, "Processing files")
// bar.Increment() // advance by 1
// bar.IncrementBy(5) // advance by 5
// bar.Done() // mark complete
}
Output:
func (*Progress) Done ¶ added in v1.9.6
func (p *Progress) Done()
Done marks the progress as complete and cleans up the display.
func (*Progress) Increment ¶ added in v1.9.6
func (p *Progress) Increment()
Increment advances the progress by one unit.
func (*Progress) IncrementBy ¶ added in v1.9.6
IncrementBy advances the progress by n units.
type Response ¶ added in v1.7.0
type Response struct {
Status string `json:"status"`
Command string `json:"command"`
Data any `json:"data,omitempty"`
Error string `json:"error,omitempty"`
}
Response is the standard JSON envelope for all command output.
type Status ¶ added in v1.9.6
type Status struct {
// contains filtered or unexported fields
}
Status displays a live-updating status message for multi-step operations. In interactive terminals, updates the current line in place. In non-interactive environments, prints sequential lines. Safe for concurrent use from multiple goroutines.
func NewStatus ¶ added in v1.9.6
func NewStatus() *Status
NewStatus creates a status display.
Example ¶
package main
import (
"bytes"
"github.com/phpboyscout/go-tool-base/pkg/output"
)
func main() {
var buf bytes.Buffer
s := &output.Status{}
_ = s
_ = buf
// In real usage:
// s := output.NewStatus()
// s.Update("Loading configuration")
// s.Success("Configuration loaded")
// s.Update("Connecting to API")
// s.Warn("Connection slow")
// s.Done()
}
Output:
func (*Status) Fail ¶ added in v1.9.6
Fail marks the current step as failed and moves to the next line.
func (*Status) Success ¶ added in v1.9.6
Success marks the current step as successful and moves to the next line.
type TableOption ¶ added in v1.8.0
type TableOption func(*tableConfig)
TableOption configures the TableWriter.
func WithColumns ¶ added in v1.8.0
func WithColumns(cols ...Column) TableOption
WithColumns explicitly defines the table columns. When not provided, columns are derived from struct tags on the row data type.
func WithMaxWidth ¶ added in v1.8.0
func WithMaxWidth(width int) TableOption
WithMaxWidth overrides automatic terminal width detection.
func WithNoHeader ¶ added in v1.8.0
func WithNoHeader() TableOption
WithNoHeader suppresses the header row in text table output.
func WithNoTruncation ¶ added in v1.8.0
func WithNoTruncation() TableOption
WithNoTruncation disables terminal-width truncation. Useful when output is piped to a file or another process.
func WithSortBy ¶ added in v1.8.0
func WithSortBy(field string) TableOption
WithSortBy sets the column to sort rows by. The column must be marked Sortable.
func WithSortDescending ¶ added in v1.8.0
func WithSortDescending() TableOption
WithSortDescending reverses the sort order.
type TableWriter ¶ added in v1.8.0
type TableWriter struct {
// contains filtered or unexported fields
}
TableWriter renders structured data as an aligned table or machine-readable format.
func NewTableWriter ¶ added in v1.8.0
func NewTableWriter(w io.Writer, format Format, opts ...TableOption) *TableWriter
NewTableWriter creates a TableWriter that writes to the given io.Writer.
Example ¶
package main
import (
"bytes"
"fmt"
"github.com/phpboyscout/go-tool-base/pkg/output"
)
func main() {
type release struct {
Name string `table:"NAME,sortable"`
Version string `table:"VERSION"`
Status string `table:"STATUS"`
}
rows := []release{
{Name: "my-tool", Version: "v1.2.3", Status: "up to date"},
{Name: "other", Version: "v0.9.1", Status: "update available"},
}
var buf bytes.Buffer
tw := output.NewTableWriter(&buf, output.FormatText, output.WithNoTruncation())
if err := tw.WriteRows(rows); err != nil {
fmt.Println("Error:", err)
return
}
fmt.Print(buf.String())
}
Output: NAME VERSION STATUS my-tool v1.2.3 up to date other v0.9.1 update available
func (*TableWriter) WriteRows ¶ added in v1.8.0
func (t *TableWriter) WriteRows(rows any) error
WriteRows renders the provided slice as a table. The input must be a slice of structs (for tag-based columns) or []map[string]any. For JSON/YAML formats, the raw data is marshalled directly. For CSV format, columns are used as the header row. For text format, an aligned table with padding is produced.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer handles formatted output based on the configured format.