devtui

package module
v0.0.189 Latest Latest
Warning

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

Go to latest
Published: Sep 15, 2025 License: MIT Imports: 15 Imported by: 0

README

DevTUI

Project Badges

Reusable message presentation system for Go development tools. DevTUI is a pure display layer built on bubbletea that formats and organizes messages from your business logic handlers.

What DevTUI does: Takes messages from your handlers via progress() callbacks and displays them in a clean, organized terminal interface with tabs, navigation, and automatic formatting.

What DevTUI doesn't do: Validate data, handle errors, or manage business logic. Your handlers are responsible for their own state and decisions - DevTUI just shows whatever they tell it to show.

devtui

→ Why DevTUI? - Complete purpose and functionality description

Quick Start

Special Case: HandlerEdit with Content() (No new messages, only refresh)

If your handler implements both the HandlerEdit interface and a Content() method, DevTUI will only refresh the display when the value changes, and will not create a new timestamped message. This is ideal for cases like language selectors, dashboards, or any field where the content is always shown in a custom format.

Example:

type LanguageHandler struct {
    lang string
}

func (h *LanguageHandler) Name() string  { return "Language" }
func (h *LanguageHandler) Label() string { return "Language" }
func (h *LanguageHandler) Value() string { return h.lang }
func (h *LanguageHandler) Change(newValue string, progress func(msgs ...any)) {
    h.lang = newValue
    progress("Language changed to", newValue) // Will only refresh, not create a message
}
func (h *LanguageHandler) Content() string {
    return "Current language: " + h.lang
}

When the user changes the value, the UI will update the content, but no new message will appear in the message area. This behavior is now fully tested and guaranteed by the DevTUI test suite.


DevTUI uses specialized handler interfaces that require minimal implementation. Here is a complete example using the new simplified API:

// HandlerExecution with MessageTracker - Action buttons with progress tracking
type BackupHandler struct {
    lastOpID string
}

func (h *BackupHandler) Name() string  { return "SystemBackup" }
func (h *BackupHandler) Label() string { return "Create System Backup" }
func (h *BackupHandler) Execute(progress func(msgs ...any)) {
    progress("Preparing backup...")
    time.Sleep(200 * time.Millisecond)
    progress("Backing up database...")
    time.Sleep(500 * time.Millisecond)
    progress("Backup completed successfully")
}

// MessageTracker implementation for operation tracking
func (h *BackupHandler) GetLastOperationID() string   { return h.lastOpID }
func (h *BackupHandler) SetLastOperationID(id string) { h.lastOpID = id }

func main() {
    tui := devtui.NewTUI(&devtui.TuiConfig{
        AppName:  "Demo",
        ExitChan: make(chan bool),
        Color: &devtui.ColorPalette{
            Foreground: "#F4F4F4",
            Background: "#000000",
            Primary:  "#FF6600",
            Secondary:   "#666666",
        },
        Logger: func(messages ...any) {
            // Replace with actual logging implementation
        },
    })

    // Operations tab with ExecutionHandlers (action buttons)
    ops := tui.NewTabSection("Operations", "System Operations")
    ops.AddExecutionHandler(&BackupHandler{}, 5*time.Second) // Automatic MessageTracker detection

    var wg sync.WaitGroup
    wg.Add(1)
    go tui.Start(&wg)
    wg.Wait()
}

👉 See complete example with all handler types

Handler Interfaces

DevTUI provides 6 specialized handler types, each requiring minimal implementation:

1. HandlerDisplay - Read-only Information (2 methods)
type HandlerDisplay interface {
    Name() string    // Full text to display in footer
    Content() string // Content shown immediately
}

→ See complete implementation example

2. HandlerEdit - Interactive Input Fields (4 methods)
type HandlerEdit interface {
    Name() string    // Unique identifier for logging
    Label() string   // Field label
    Value() string   // Current/initial value
    Change(newValue string, progress func(msgs ...any))
}

Optional Shortcut Support: Add Shortcuts() map[string]string method to enable global keyboard shortcuts. The map key is the keyboard shortcut and the value passed to Change(). The map value is only for display/description:

// Shortcuts work from any tab and automatically navigate to this field
func (h *DatabaseHandler) Shortcuts() map[string]string {
    return map[string]string{
        "t": "test connection",  // Pressing 't' calls Change("t", progress)
        "b": "backup database",  // Pressing 'b' calls Change("b", progress)
    }
}

→ See complete implementation example

3. HandlerExecution - Action Buttons (3 methods)
type HandlerExecution interface {
    Name() string  // Unique identifier for logging
    Label() string // Button label
    Execute(progress func(msgs ...any))
}

→ See complete implementation example

4. HandlerInteractive - Interactive Content Management (5 methods)
type HandlerInteractive interface {
    Name() string                                       // Identifier for logging
    Label() string                                      // Field label (updates dynamically)
    Value() string                                      // Current input value
    Change(newValue string, progress func(msgs ...any)) // Handle user input + content display
    WaitingForUser() bool                               // Should edit mode be auto-activated?
}

Key Features:

  • Dynamic Content: All content updates through progress() for consistency
  • Auto Edit Mode: WaitingForUser() controls when edit mode is activated
  • Content Display: Use empty newValue + WaitingForUser() == false to trigger content display
  • Perfect for: Chat interfaces, configuration wizards, interactive help systems

→ See complete implementation example

5. HandlerLogger - Simple Logging (1 method)
type HandlerLogger interface {
    Name() string // Writer identifier
}

→ See complete HandlerLogger implementation example

→ See complete HandlerLoggerTracker implementation example

Registration Methods

DevTUI uses automatic MessageTracker detection - simply implement the MessageTracker interface and DevTUI will automatically detect and use it for operation tracking:

// Display handlers (no timeout needed)
tab.AddDisplayHandler(handler)

// Edit handlers (timeout mandatory)
tab.AddEditHandler(handler, 5*time.Second) // Automatic MessageTracker detection

// Execution handlers (timeout mandatory)
tab.AddExecutionHandler(handler, 10*time.Second) // Automatic MessageTracker detection

// Interactive handlers (timeout mandatory)
tab.AddInteractiveHandler(handler, 5*time.Second) // Automatic MessageTracker detection

// Writers (returns func(message ...any))
logger := tab.NewLogger("LogWriter", false)        // Basic writer (new lines)
loggerWithTracker := tab.NewLogger("TrackedWriter", true) // Advanced writer (tracking)
logger("Log message 1")
logger("Another log entry")
Optional MessageTracker Implementation

To enable operation tracking (updating existing messages instead of creating new ones), simply implement the MessageTracker interface:

type MessageTracker interface {
    GetLastOperationID() string
    SetLastOperationID(id string)
}

DevTUI automatically detects when a handler implements MessageTracker and enables operation tracking without any additional registration steps.

Key Features

  • Minimal Implementation: 1-4 methods per handler
  • Specialized Interfaces: Clear separation by purpose (Display, Edit, Execution, Writing)
  • Progress Callbacks: Real-time feedback for long-running operations
  • Automatic MessageTracker Detection: Optionally implement MessageTracker interface for operation tracking
  • Simple Registration: Single method per handler type with automatic tracking detection
  • Method Chaining: All handler registration methods return *tabSection for chaining
  • Thread-Safe: Concurrent handler registration and execution

Navigation

  • Tab/Shift+Tab: Switch between tabs
  • Left/Right: Navigate fields within tab
  • Up/Down: Scroll viewport line by line
  • Page Up/Page Down: Scroll viewport page by page
  • Mouse Wheel: Scroll viewport (when available)
  • Enter: Edit/Execute
  • Esc: Cancel edit
  • Ctrl+C: Exit
  • Global Shortcuts: Single key shortcuts (e.g., "t", "b") work from any tab when defined in handlers

Shortcut System: Handlers implementing Shortcuts() map[string]string automatically register global keyboard shortcuts. When pressed, shortcuts navigate to the handler's tab/field and execute the Change() method with the map key as the newValue parameter.

Example: If shortcuts return {"t": "test connection"}, pressing 't' calls Change("t", progress).

Note: DevTUI automatically loads a built-in ShortcutsHandler at position 0 in the first tab, which displays detailed keyboard navigation commands. This handler demonstrates the HandlerEdit interface and provides interactive help within the application.

Text Selection: Terminal text selection is enabled for copying error messages and logs. Mouse scroll functionality may vary depending on bubbletea version and terminal capabilities.

Acknowledgments

DevTUI is built on top of the excellent libraries from github.com/charmbracelet: bubbletea, bubbles and lipgloss, which provide the solid foundation for creating terminal interfaces in Go.

Contributing

Documentation

Index

Constants

View Source
const HandlerNameWidth = 8

Variables

This section is empty.

Functions

This section is empty.

Types

type ColorPalette added in v0.0.168

type ColorPalette struct {
	// Base (2 colores)
	Foreground string // #F4F4F4
	Background string // #000000

	// Accent (2 colores)
	Primary   string // #FF6600 (tu actual Primary)
	Secondary string // #666666 (tu actual Secondary)

	// Semantic (4 colores)
	Success string // #00FF00
	Warning string // #FFFF00
	Error   string // #FF0000
	Info    string // #00FFFF

	// UI (2-4 colores adicionales)
	Border   string // #444444
	Muted    string // #999999
	Selected string // Derivado de Primary
	Hover    string // Derivado de Primary
}

func DefaultPalette added in v0.0.168

func DefaultPalette() *ColorPalette

type DevTUI

type DevTUI struct {
	*TuiConfig
	// contains filtered or unexported fields
}

DevTUI mantiene el estado de la aplicación

func NewTUI

func NewTUI(c *TuiConfig) *DevTUI

NewTUI creates a new DevTUI instance and initializes it.

Usage Example:

config := &TuiConfig{
    AppName: "MyApp",
    ExitChan: make(chan bool),
    Color: nil, // or your *ColorPalette
    Logger: func(err any) { fmt.Println(err) },
}
tui := NewTUI(config)

func (*DevTUI) ContentView

func (h *DevTUI) ContentView() string

ContentView renderiza los mensajes para una sección de contenido

func (*DevTUI) Init

func (h *DevTUI) Init() tea.Cmd

Init initializes the terminal UI application.

func (*DevTUI) NewTabSection added in v0.0.43

func (t *DevTUI) NewTabSection(title, description string) *tabSection

NewTabSection creates and initializes a new tabSection with the given title and footer NewTabSection creates a new tab section and automatically adds it to the TUI

Example:

tab := tui.NewTabSection("BUILD", "Compiler Section")

func (*DevTUI) ReturnFocus

func (t *DevTUI) ReturnFocus() error

func (*DevTUI) SetTestMode added in v0.0.125

func (h *DevTUI) SetTestMode(enabled bool)

SetTestMode enables or disables test mode for synchronous behavior in tests. This should only be used in test files to make tests deterministic.

func (*DevTUI) Start added in v0.0.93

func (h *DevTUI) Start(args ...any)

Start initializes and runs the terminal UI application.

It accepts optional variadic arguments of any type. If a *sync.WaitGroup is provided among these arguments, Start will call its Done() method before returning.

The method runs the UI using the internal tea engine, and handles any errors that may occur during execution. If an error occurs, it will be displayed on the console and the application will wait for user input before exiting.

Parameters:

  • args ...any: Optional arguments. Can include a *sync.WaitGroup for synchronization.

func (*DevTUI) Update

func (h *DevTUI) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update maneja las actualizaciones del estado

func (*DevTUI) View

func (h *DevTUI) View() string

type HandlerDisplay added in v0.0.117

type HandlerDisplay interface {
	Name() string    // Full text to display in footer (handler responsible for content) eg. "System Status Information Display"
	Content() string // Display content (e.g., "help\n1-..\n2-...", "executing deploy wait...")
}

HandlerDisplay defines the interface for read-only information display handlers. These handlers show static or dynamic content without user interaction.

type HandlerEdit added in v0.0.117

type HandlerEdit interface {
	Name() string                                       // Identifier for logging: "ServerPort", "DatabaseURL"
	Label() string                                      // Field label (e.g., "Server Port", "Host Configuration")
	Value() string                                      // Current/initial value (e.g., "8080", "localhost")
	Change(newValue string, progress func(msgs ...any)) // New signature: no error, not variadic, string
}

HandlerEdit defines the interface for interactive fields that accept user input. These handlers allow users to modify values through text input.

type HandlerExecution added in v0.0.117

type HandlerExecution interface {
	Name() string                       // Identifier for logging: "DeployProd", "BuildProject"
	Label() string                      // Button label (e.g., "Deploy to Production", "Build Project")
	Execute(progress func(msgs ...any)) // New signature: no error, not variadic
}

HandlerExecution defines the interface for action buttons that execute operations. These handlers trigger business logic when activated by the user.

type HandlerInteractive added in v0.0.149

type HandlerInteractive interface {
	Name() string                                       // Identifier for logging: "ChatBot", "ConfigWizard"
	Label() string                                      // Field label (updates dynamically)
	Value() string                                      // Current input value
	Change(newValue string, progress func(msgs ...any)) // Handle user input + content display via progress
	WaitingForUser() bool                               // Should edit mode be auto-activated?
}

HandlerInteractive defines the interface for interactive content handlers. These handlers combine content display with user interaction capabilities. All content display is handled through progress() for consistency.

type HandlerLogger added in v0.0.176

type HandlerLogger interface {
	Name() string // Writer identifier (e.g., "webBuilder", "ApplicationLog")
}

HandlerLogger defines the interface for basic writers that create new lines for each write. These writers are suitable for simple logging or output display.

type MessageTracker added in v0.0.116

type MessageTracker interface {
	GetLastOperationID() string
	SetLastOperationID(id string)
}

MessageTracker provides optional interface for message tracking control. Handlers can implement this to control message updates and operation tracking.

type ShortcutEntry added in v0.0.161

type ShortcutEntry struct {
	Key         string // The shortcut key (e.g., "c", "d", "p")
	Description string // Human-readable description (e.g., "coding mode", "debug mode")
	TabIndex    int    // Index of the tab containing the handler
	FieldIndex  int    // Index of the field within the tab
	HandlerName string // Handler name for identification
	Value       string // Value to pass to Change()
}

ShortcutEntry represents a registered shortcut

type ShortcutProvider added in v0.0.161

type ShortcutProvider interface {
	Shortcuts() map[string]string // Returns shortcut keys with descriptions (e.g., {"c": "coding mode", "d": "debug mode", "p": "production mode"})
}

ShortcutProvider defines the optional interface for handlers that provide global shortcuts. HandlerEdit implementations can implement this interface to enable global shortcut keys.

type ShortcutRegistry added in v0.0.161

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

ShortcutRegistry manages global shortcut keys

func (*ShortcutRegistry) Get added in v0.0.161

func (sr *ShortcutRegistry) Get(key string) (*ShortcutEntry, bool)

func (*ShortcutRegistry) GetAll added in v0.0.161

func (sr *ShortcutRegistry) GetAll() map[string]*ShortcutEntry

GetAll returns all registered shortcuts for UI display

func (*ShortcutRegistry) List added in v0.0.161

func (sr *ShortcutRegistry) List() []string

func (*ShortcutRegistry) Register added in v0.0.161

func (sr *ShortcutRegistry) Register(key string, entry *ShortcutEntry)

func (*ShortcutRegistry) Unregister added in v0.0.161

func (sr *ShortcutRegistry) Unregister(key string)

type TuiConfig

type TuiConfig struct {
	AppName  string    // app name eg: "MyApp"
	ExitChan chan bool //  global chan to close app eg: make(chan bool)
	/*// *ColorPalette style for the TUI
	  // if nil it will use default style:
	type ColorPalette struct {
	 Foreground string // eg: #F4F4F4
	 Background string // eg: #000000
	 Primary  string // eg: #FF6600
	 Secondary   string // eg: #666666
	}*/
	Color *ColorPalette

	Logger func(messages ...any) // function to write log error
}

Directories

Path Synopsis
demo command

Jump to

Keyboard shortcuts

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