display

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: May 31, 2025 License: Apache-2.0 Imports: 11 Imported by: 0

README

Icebox Display Package

A modern, feature-rich CLI display system for the Icebox project that provides consistent, customizable, and accessible output across all commands.

Features

🎯 Core Features
  • Unified Display Interface - Single API for all CLI output needs
  • Progressive Enhancement - Automatically adapts to terminal capabilities
  • Multiple Output Formats - Table, CSV, JSON, Markdown
  • Theme Support - Default, Dark, Light, and Minimal themes
  • Configuration System - User preferences via YAML/JSON
  • Context Integration - Pass display through application layers
📊 Table Features
  • Sorting - Sort by any column, ascending or descending
  • Filtering - Filter rows with various operators (=, !=, >, <, contains, etc.)
  • Pagination - Automatic pagination with configurable page size
  • Row Numbers - Optional row numbering
  • Compact Mode - Condensed display without row separators
  • Titles & Footers - Add context to tables
  • Column Width Management - Automatic sizing with max width constraints
  • Text Wrapping - Intelligent text wrapping for long content
🎨 Display Features
  • Message Levels - Success, Error, Warning, Info with appropriate styling
  • Progress Indicators - Show progress for long-running operations
  • Interactive Prompts - Confirmations, selections, and input (when supported)
  • Terminal Detection - Color, Unicode, width, and interactivity detection
  • Graceful Degradation - Falls back to simple output in limited environments

Installation

import "github.com/TFMV/icebox/display"

Quick Start

Basic Usage
// Create a display instance
d := display.New()

// Show messages
d.Success("Operation completed successfully")
d.Error("Failed to process: %v", err)
d.Warning("This action cannot be undone")
d.Info("Processing %d records", count)

// Display a table
data := display.TableData{
    Headers: []string{"ID", "Name", "Status"},
    Rows: [][]interface{}{
        {1, "Alice", "Active"},
        {2, "Bob", "Inactive"},
        {3, "Carol", "Active"},
    },
}

table := d.Table(data)
table.Render()
Advanced Table Usage
// Create a table with all features
table := d.Table(data).
    WithTitle("User Management").
    WithSorting("Name", false).              // Sort by name ascending
    WithFiltering("Status", "=", "Active").  // Show only active users
    WithPagination(10).                      // Show 10 rows per page
    WithRowNumbers().                        // Add row numbers
    WithMaxWidth(120).                       // Limit table width
    WithTheme(display.DarkTheme)             // Use dark theme

table.Render()
Configuration

Create ~/.icebox/display.yaml:

theme: "dark"
format: "table"
table:
  max_width: 120
  pagination: 50
  unicode_borders: true
  show_row_numbers: false
  compact_mode: false
colors:
  enabled: "auto"  # auto, always, never
interactive:
  confirm_destructive: true
  show_hints: true
verbose: false
timing: true

Load and use configuration:

config, err := display.LoadConfig()
if err != nil {
    config = display.DefaultConfig()
}

d := display.NewWithConfig(config)
Context Integration

Pass display through your application:

// Add display to context
ctx := display.WithDisplay(context.Background(), d)

// Use in other functions
func processData(ctx context.Context) {
    // Get display from context
    if d := display.GetDisplay(ctx); d != nil {
        d.Info("Processing data...")
    }
    
    // Or use the helper
    display.LogOrDisplay(ctx, display.MessageLevelSuccess, "Data processed")
}

Output Formats

Table Format (Default)
┌────┬───────┬──────────┐
│ ID │ Name  │ Status   │
├────┼───────┼──────────┤
│ 1  │ Alice │ Active   │
│ 2  │ Bob   │ Inactive │
│ 3  │ Carol │ Active   │
└────┴───────┴──────────┘
CSV Format
ID,Name,Status
1,Alice,Active
2,Bob,Inactive
3,Carol,Active
JSON Format
[
  {"ID": "1", "Name": "Alice", "Status": "Active"},
  {"ID": "2", "Name": "Bob", "Status": "Inactive"},
  {"ID": "3", "Name": "Carol", "Status": "Active"}
]
Markdown Format
| ID | Name  | Status   |
| -- | ----- | -------- |
| 1  | Alice | Active   |
| 2  | Bob   | Inactive |
| 3  | Carol | Active   |

Themes

Default Theme
  • Balanced colors and Unicode borders
  • Works well in most terminals
Dark Theme
  • Optimized for dark terminal backgrounds
  • Higher contrast colors
Light Theme
  • Optimized for light terminal backgrounds
  • Softer colors
Minimal Theme
  • ASCII-only borders
  • No colors
  • Maximum compatibility

Terminal Capabilities

The display system automatically detects:

  • Color Support - Enables/disables colors based on terminal
  • Unicode Support - Falls back to ASCII borders when needed
  • Terminal Width - Adjusts table width accordingly
  • Interactive Mode - Enables/disables prompts
  • CI Environment - Simplified output for CI/CD

Helper Functions

// Format bytes into human-readable format
display.FormatBytes(1234567890) // "1.1 GB"

// Truncate strings with ellipsis
display.TruncateString("Long text", 10) // "Long te..."

// Wrap text to fit width
lines := display.WrapText("Long paragraph", 40)

Examples

See the example/ directory for complete examples:

  • main.go - Basic usage demonstration
  • advanced/main.go - Advanced features showcase

Run the examples:

cd example
go run main.go

cd advanced
go run main.go

Architecture

display/
├── display.go       # Main interface and simple fallback renderer
├── types.go         # Core types and table builder
├── capabilities.go  # Terminal capability detection
├── config.go        # Configuration system
├── context.go       # Context integration
├── helpers.go       # Utility functions
├── renderers/       # Pluggable renderer backends
│   ├── interface.go # Renderer interface
│   ├── fallback.go  # Zero-dependency renderer
│   └── pterm.go     # Rich terminal renderer
└── example/         # Usage examples

Best Practices

  1. Use Context - Pass display through context for better integration
  2. Check Capabilities - Respect terminal limitations
  3. Provide Fallbacks - Always have a simple output option
  4. Be Consistent - Use the same display instance throughout
  5. Configure Once - Load configuration at startup
  6. Test Output - Verify output in different environments

Migration Guide

Replace manual formatting:

// Before
fmt.Printf("┌─────┬─────┐\n")
fmt.Printf("│ %-3s │ %-3s │\n", "ID", "Name")
fmt.Printf("├─────┼─────┤\n")
// ... more manual formatting

// After
d := display.New()
table := d.Table(data)
table.Render()

Replace scattered print statements:

// Before
fmt.Printf("✅ Success: %s\n", message)
fmt.Printf("❌ Error: %s\n", err)

// After
d.Success(message)
d.Error("Operation failed: %v", err)

Contributing

When adding new features:

  1. Maintain backward compatibility
  2. Add tests for new functionality
  3. Update documentation
  4. Consider terminal limitations
  5. Follow existing patterns

License

Part of the Icebox project. See the main project LICENSE file.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	DefaultTheme = Theme{
		Name: "default",
		Colors: ColorScheme{
			Primary:   "#0066CC",
			Secondary: "#6C757D",
			Success:   "#28A745",
			Warning:   "#FFC107",
			Error:     "#DC3545",
			Info:      "#17A2B8",
			Muted:     "#6C757D",
		},
		TableStyle: TableStyle{
			HeaderStyle: "bold",
			RowStyle:    "normal",
			BorderStyle: "rounded",
		},
		Borders: BorderStyle{
			Horizontal:  "─",
			Vertical:    "│",
			TopLeft:     "┌",
			TopRight:    "┐",
			BottomLeft:  "└",
			BottomRight: "┘",
			Cross:       "┼",
		},
		Icons: IconSet{
			Success: "✅",
			Warning: "⚠️",
			Error:   "❌",
			Info:    "ℹ️",
		},
	}

	DarkTheme = Theme{
		Name: "dark",
		Colors: ColorScheme{
			Primary:   "#4A9EFF",
			Secondary: "#8E8E93",
			Success:   "#30D158",
			Warning:   "#FF9F0A",
			Error:     "#FF453A",
			Info:      "#64D2FF",
			Muted:     "#8E8E93",
		},
		TableStyle: TableStyle{
			HeaderStyle: "bold",
			RowStyle:    "normal",
			BorderStyle: "rounded",
		},
		Borders: BorderStyle{
			Horizontal:  "─",
			Vertical:    "│",
			TopLeft:     "┌",
			TopRight:    "┐",
			BottomLeft:  "└",
			BottomRight: "┘",
			Cross:       "┼",
		},
		Icons: IconSet{
			Success: "✅",
			Warning: "⚠️",
			Error:   "❌",
			Info:    "ℹ️",
		},
	}

	LightTheme = Theme{
		Name: "light",
		Colors: ColorScheme{
			Primary:   "#007AFF",
			Secondary: "#5E5CE6",
			Success:   "#34C759",
			Warning:   "#FF9500",
			Error:     "#FF3B30",
			Info:      "#5AC8FA",
			Muted:     "#C7C7CC",
		},
		TableStyle: TableStyle{
			HeaderStyle: "bold",
			RowStyle:    "normal",
			BorderStyle: "rounded",
		},
		Borders: BorderStyle{
			Horizontal:  "─",
			Vertical:    "│",
			TopLeft:     "┌",
			TopRight:    "┐",
			BottomLeft:  "└",
			BottomRight: "┘",
			Cross:       "┼",
		},
		Icons: IconSet{
			Success: "✓",
			Warning: "⚠",
			Error:   "✗",
			Info:    "i",
		},
	}

	MinimalTheme = Theme{
		Name: "minimal",
		Colors: ColorScheme{
			Primary:   "",
			Secondary: "",
			Success:   "",
			Warning:   "",
			Error:     "",
			Info:      "",
			Muted:     "",
		},
		TableStyle: TableStyle{
			HeaderStyle: "normal",
			RowStyle:    "normal",
			BorderStyle: "simple",
		},
		Borders: BorderStyle{
			Horizontal:  "-",
			Vertical:    "|",
			TopLeft:     "+",
			TopRight:    "+",
			BottomLeft:  "+",
			BottomRight: "+",
			Cross:       "+",
		},
		Icons: IconSet{
			Success: "[OK]",
			Warning: "[WARN]",
			Error:   "[ERROR]",
			Info:    "[INFO]",
		},
	}
)

Predefined themes

Functions

func FormatBytes

func FormatBytes(bytes int64) string

formatBytes formats bytes into human-readable format

func LogOrDisplay

func LogOrDisplay(ctx context.Context, level MessageLevel, format string, args ...interface{})

LogOrDisplay logs a message using the display if available, otherwise uses the logger

func SaveConfig

func SaveConfig(config *Config) error

SaveConfig saves configuration to the default location

func SaveConfigToFile

func SaveConfigToFile(config *Config, path string) error

SaveConfigToFile saves configuration to a specific file

func TruncateString

func TruncateString(s string, maxLen int) string

TruncateString truncates a string to maxLen with ellipsis

func WithDisplay

func WithDisplay(ctx context.Context, display Display) context.Context

WithDisplay adds a display instance to the context

func WithDisplayContext

func WithDisplayContext(ctx context.Context, dc *DisplayContext) context.Context

WithDisplayContext adds a full display context to the context

func WrapText

func WrapText(text string, maxWidth int) []string

WrapText wraps text to fit within maxWidth

Types

type BorderStyle

type BorderStyle struct {
	Horizontal  string
	Vertical    string
	TopLeft     string
	TopRight    string
	BottomLeft  string
	BottomRight string
	Cross       string
}

BorderStyle defines border characters

type Color

type Color string

Color represents a color value

type ColorConfig

type ColorConfig struct {
	Enabled string `yaml:"enabled" json:"enabled"` // auto, always, never
}

ColorConfig represents color configuration

type ColorScheme

type ColorScheme struct {
	Primary   Color
	Secondary Color
	Success   Color
	Warning   Color
	Error     Color
	Info      Color
	Muted     Color
}

ColorScheme defines colors for different message types

type Config

type Config struct {
	Theme       string            `yaml:"theme" json:"theme"`
	Format      string            `yaml:"format" json:"format"`
	Table       TableConfig       `yaml:"table" json:"table"`
	Colors      ColorConfig       `yaml:"colors" json:"colors"`
	Interactive InteractiveConfig `yaml:"interactive" json:"interactive"`
	Verbose     bool              `yaml:"verbose" json:"verbose"`
	Timing      bool              `yaml:"timing" json:"timing"`
}

Config represents the display configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns the default configuration

func LoadConfig

func LoadConfig() (*Config, error)

LoadConfig loads configuration from the default location

func LoadConfigFromFile

func LoadConfigFromFile(path string) (*Config, error)

LoadConfigFromFile loads configuration from a specific file

type Display

type Display interface {
	// Table operations
	Table(data TableData) *TableBuilder

	// Message operations
	Success(message string, args ...interface{})
	Error(message string, args ...interface{})
	Warning(message string, args ...interface{})
	Info(message string, args ...interface{})

	// Progress operations
	Progress(title string) *ProgressBuilder

	// Interactive operations
	Confirm(message string) bool
	Select(message string, options []string) (int, error)
	Input(message string) (string, error)

	// Output format control
	SetFormat(format OutputFormat) Display
	SetTheme(theme Theme) Display
}

Display is the main interface for all display operations

func GetDisplay

func GetDisplay(ctx context.Context) Display

GetDisplay retrieves the display instance from context

func GetDisplayOrDefault

func GetDisplayOrDefault(ctx context.Context) Display

GetDisplayOrDefault retrieves the display instance from context or returns a default

type DisplayContext

type DisplayContext struct {
	Display Display
	Logger  *log.Logger
	Verbose bool
	Format  OutputFormat
}

DisplayContext holds display-related context information

func GetDisplayContext

func GetDisplayContext(ctx context.Context) *DisplayContext

GetDisplayContext retrieves the full display context

type DisplayImpl

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

DisplayImpl is the concrete implementation of Display

func New

func New() *DisplayImpl

New creates a new Display instance with automatic capability detection

func NewWithConfig

func NewWithConfig(config *Config) *DisplayImpl

NewWithConfig creates a new display instance with configuration

func NewWithRenderer

func NewWithRenderer(renderer Renderer) *DisplayImpl

NewWithRenderer creates a new Display instance with a specific renderer

func (*DisplayImpl) ApplyConfig

func (d *DisplayImpl) ApplyConfig(config *Config)

ApplyConfig applies configuration to a display instance

func (*DisplayImpl) Confirm

func (d *DisplayImpl) Confirm(message string) bool

Confirm shows a confirmation prompt

func (*DisplayImpl) Error

func (d *DisplayImpl) Error(message string, args ...interface{})

Error displays an error message

func (*DisplayImpl) Info

func (d *DisplayImpl) Info(message string, args ...interface{})

Info displays an info message

func (*DisplayImpl) Input

func (d *DisplayImpl) Input(message string) (string, error)

Input shows an input prompt

func (*DisplayImpl) Progress

func (d *DisplayImpl) Progress(title string) *ProgressBuilder

Progress creates a new progress builder

func (*DisplayImpl) Select

func (d *DisplayImpl) Select(message string, options []string) (int, error)

Select shows a selection menu

func (*DisplayImpl) SetFormat

func (d *DisplayImpl) SetFormat(format OutputFormat) Display

SetFormat sets the output format

func (*DisplayImpl) SetTheme

func (d *DisplayImpl) SetTheme(theme Theme) Display

SetTheme sets the display theme

func (*DisplayImpl) Success

func (d *DisplayImpl) Success(message string, args ...interface{})

Success displays a success message

func (*DisplayImpl) Table

func (d *DisplayImpl) Table(data TableData) *TableBuilder

Table creates a new table builder

func (*DisplayImpl) Warning

func (d *DisplayImpl) Warning(message string, args ...interface{})

Warning displays a warning message

type FilterOptions

type FilterOptions struct {
	Column   string
	Operator string // =, !=, <, >, <=, >=, contains, starts_with, ends_with
	Value    interface{}
}

FilterOptions represents filtering configuration

type IconSet

type IconSet struct {
	Success string
	Warning string
	Error   string
	Info    string
}

IconSet defines icons for different message types

type InteractiveConfig

type InteractiveConfig struct {
	ConfirmDestructive bool `yaml:"confirm_destructive" json:"confirm_destructive"`
	ShowHints          bool `yaml:"show_hints" json:"show_hints"`
}

InteractiveConfig represents interactive feature configuration

type MessageLevel

type MessageLevel int

MessageLevel represents different message types

const (
	MessageLevelInfo MessageLevel = iota
	MessageLevelSuccess
	MessageLevelWarning
	MessageLevelError
)

type OutputFormat

type OutputFormat int

OutputFormat represents different output formats

const (
	FormatTable OutputFormat = iota
	FormatCSV
	FormatJSON
	FormatMarkdown
)

type PaginationOptions

type PaginationOptions struct {
	PageSize int
	ShowAll  bool
}

PaginationOptions represents pagination configuration

type ProgressBuilder

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

ProgressBuilder for building progress indicators

func (*ProgressBuilder) Start

func (pb *ProgressBuilder) Start() *ProgressIndicator

Start starts the progress indicator

type ProgressIndicator

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

ProgressIndicator represents an active progress indicator

func (*ProgressIndicator) Finish

func (pi *ProgressIndicator) Finish(message string)

Finish completes the progress

func (*ProgressIndicator) Update

func (pi *ProgressIndicator) Update(message string)

Update updates the progress

type Renderer

type Renderer interface {
	// Table rendering
	RenderTable(data TableData, options TableOptions) error

	// Message rendering
	RenderMessage(level MessageLevel, message string)

	// Interactive rendering
	RenderConfirm(message string) bool
	RenderSelect(message string, options []string) (int, error)
	RenderInput(message string) (string, error)

	// Progress rendering
	RenderProgress(title string, current, total int) error
}

Renderer interface that all display renderers must implement

func NewFallbackRenderer

func NewFallbackRenderer() Renderer

NewFallbackRenderer creates a new fallback renderer

func NewPTermRenderer

func NewPTermRenderer() Renderer

NewPTermRenderer creates a new PTerm renderer (placeholder)

type SortOptions

type SortOptions struct {
	Column     string
	Descending bool
}

SortOptions represents sorting configuration

type TableBuilder

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

TableBuilder for building tables with fluent API

func (*TableBuilder) Render

func (tb *TableBuilder) Render() error

Render renders the table

func (*TableBuilder) WithCompactMode

func (tb *TableBuilder) WithCompactMode() *TableBuilder

WithCompactMode enables compact display mode

func (*TableBuilder) WithFiltering

func (tb *TableBuilder) WithFiltering(column, operator string, value interface{}) *TableBuilder

WithFiltering sets filtering options

func (*TableBuilder) WithFormat

func (tb *TableBuilder) WithFormat(format OutputFormat) *TableBuilder

WithFormat sets the output format

func (*TableBuilder) WithMaxWidth

func (tb *TableBuilder) WithMaxWidth(width int) *TableBuilder

WithMaxWidth sets the maximum table width

func (*TableBuilder) WithPagination

func (tb *TableBuilder) WithPagination(pageSize int) *TableBuilder

WithPagination sets pagination options

func (*TableBuilder) WithRowNumbers

func (tb *TableBuilder) WithRowNumbers() *TableBuilder

WithRowNumbers enables row number display

func (*TableBuilder) WithSorting

func (tb *TableBuilder) WithSorting(column string, descending bool) *TableBuilder

WithSorting sets sorting options

func (*TableBuilder) WithTheme

func (tb *TableBuilder) WithTheme(theme Theme) *TableBuilder

WithTheme sets the theme

func (*TableBuilder) WithTitle

func (tb *TableBuilder) WithTitle(title string) *TableBuilder

WithTitle sets the table title

type TableConfig

type TableConfig struct {
	MaxWidth       int  `yaml:"max_width" json:"max_width"`
	Pagination     int  `yaml:"pagination" json:"pagination"`
	UnicodeBorders bool `yaml:"unicode_borders" json:"unicode_borders"`
	ShowRowNumbers bool `yaml:"show_row_numbers" json:"show_row_numbers"`
	CompactMode    bool `yaml:"compact_mode" json:"compact_mode"`
}

TableConfig represents table-specific configuration

type TableData

type TableData struct {
	Headers []string
	Rows    [][]interface{}
	Footer  []string
}

TableData represents the data for a table

type TableOptions

type TableOptions struct {
	Format         OutputFormat
	MaxWidth       int
	Pagination     *PaginationOptions
	Sorting        *SortOptions
	Filtering      *FilterOptions
	Theme          *Theme
	ShowRowNumbers bool
	CompactMode    bool
	Title          string
}

TableOptions represents configuration options for table rendering

func DefaultTableOptions

func DefaultTableOptions() TableOptions

DefaultTableOptions returns default table options

type TableStyle

type TableStyle struct {
	HeaderStyle string
	RowStyle    string
	BorderStyle string
}

TableStyle defines table appearance

type TerminalCapabilities

type TerminalCapabilities struct {
	SupportsColor   bool
	SupportsUnicode bool
	Width           int
	Height          int
	IsInteractive   bool
	IsPiped         bool
}

TerminalCapabilities represents what the terminal supports

func DetectCapabilities

func DetectCapabilities() TerminalCapabilities

DetectCapabilities automatically detects terminal capabilities

type Theme

type Theme struct {
	Name       string
	Colors     ColorScheme
	TableStyle TableStyle
	Borders    BorderStyle
	Icons      IconSet
}

Theme represents a visual theme for the display system

Directories

Path Synopsis
example
advanced command
simple command

Jump to

Keyboard shortcuts

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