Skip to content

voocel/coal

Repository files navigation

Coal: Modern Terminal UI Library for Go

中文 | English

Build beautiful, interactive command-line applications with composable components and real-time streaming support.

package main

import (
    "context"
    "github.com/voocel/coal"
)

func main() {
    ctx := context.Background()
    
    // Get user input
    name, _ := coal.Input(ctx, "What's your name?", "Enter name...")
    
    // Show progress
    coal.ShowProgress(ctx, "Processing", 100, func(update func(int)) {
        // Your work here
        for i := 0; i <= 100; i += 10 {
            update(i)
        }
    })
    
    // Display styled result
    message := coal.NewTextDisplay().
        SetText("Welcome, " + name + "!").
        SetPrefix("Success: ").
        SetStyle(coal.NewStyle().Foreground(coal.ColorGreen))
    
    fmt.Print(message.Render(ctx))
}

That's it. No complex setup, no event loop management, no manual rendering. Just create components and they work.

Go Version License Go Report Card

Why Coal?

Building terminal UIs in Go is typically complex. You need to:

  1. Handle raw terminal input/output
  2. Manage screen rendering and updates
  3. Implement component state management
  4. Deal with terminal size changes
  5. Handle concurrent user interactions

Coal handles all of this with a simple component-based API:

Without Coal With Coal
// Setup raw terminal mode
oldState, _ := term.MakeRaw(int(os.Stdin.Fd()))
defer term.Restore(int(os.Stdin.Fd()), oldState)

// Clear screen
fmt.Print("\033[2J\033[H")

// Draw input box manually
fmt.Print("┌─────────────────┐\n")
fmt.Print("│ Enter name:     │\n") 
fmt.Print("│                 │\n")
fmt.Print("└─────────────────┘\n")

// Handle input character by character
var input string
for {
    var b [1]byte
    os.Stdin.Read(b[:])
    if b[0] == 13 { // Enter
        break
    }
    if b[0] == 127 { // Backspace
        if len(input) > 0 {
            input = input[:len(input)-1]
            // Redraw everything...
        }
        continue
    }
    input += string(b[0])
    // Redraw everything...
}
name, err := coal.Input(ctx, 
    "What's your name?", 
    "Enter name...")

// That's it! Full editing support included

Install in seconds

go get github.com/voocel/coal@latest

Real-time streaming for AI applications

Perfect for LLM integrations with built-in streaming support:

// Real-time AI response streaming
stream := coal.NewAIRealTimeStream()
stream.Start()

// As each token arrives from your LLM API
for token := range llmTokens {
    stream.Append(token)  // Immediately displayed
}

stream.Complete()

Works with any streaming API:

// OpenAI streaming example
stream := coal.NewAIRealTimeStream()
stream.Start()

resp, _ := client.CreateChatCompletionStream(ctx, req)
for {
    response, err := resp.Recv()
    if err == io.EOF {
        break
    }
    stream.Append(response.Choices[0].Delta.Content)
}
stream.Complete()

Production-ready components

Input Components

// Text input with validation
input := coal.NewTextInput().
    SetMessage("Enter email:").
    SetPlaceholder("user@example.com").
    SetValidator(validateEmail).
    SetWidth(50)

// Password input
password := coal.NewPasswordInput().
    SetMessage("Password:").
    SetShowPassword(false)

// Multi-line text area
textarea := coal.NewTextArea().
    SetMessage("Description:").
    SetSize(60, 8).
    SetLineNumbers(true)

Selection Components

// Single selection
options := []coal.Option[string]{
    {Value: "go", Label: "Go", Hint: "Fast and reliable"},
    {Value: "rust", Label: "Rust", Hint: "Memory safe"},
}

selected, _ := coal.SelectOption(ctx, "Choose language:", options)

// Multi-selection
tools, _ := coal.MultiSelectOptions(ctx, "Select tools:", toolOptions)

Progress Components

// Progress bar
coal.ShowProgress(ctx, "Processing files", 100, func(update func(int)) {
    // Your work here
})

// Spinner
coal.ShowSpinner(ctx, "Loading data", func() {
    // Your work here
})

// Task sequence
tasks := []coal.Task{
    {"Initialize", func() { /* work */ }},
    {"Process", func() { /* work */ }},
    {"Complete", func() { /* work */ }},
}
coal.RunTaskSequence(ctx, tasks)

Layout Components

// Container with border
container := coal.NewContainer().
    SetTitle("User Profile").
    SetBorder(true).
    SetRounded(true).
    AddChild(userInfo).
    AddChild(statusDisplay)

// Vertical stack
vstack := coal.NewVStack().
    SetSpacing(1).
    AddChild(header).
    AddChild(content).
    AddChild(footer)

// Split layout
split := coal.NewSplit().
    SetLeft(sidebar).
    SetRight(mainContent).
    SetRatio(0.3)

Theming and styling

Built-in themes with full customization:

// Built-in themes
coal.ThemeDefault
coal.ThemeModern  
coal.ThemeGitHub
coal.ThemeVSCode
coal.ThemeDracula

// Custom styling
style := coal.NewStyle().
    Foreground(coal.ColorBlue).
    Background(coal.ColorYellow).
    SetBold(true)

text := coal.NewTextDisplay().
    SetText("Custom styled text").
    SetStyle(style)

Architecture

Coal uses an event-driven architecture with high-performance rendering:

  • 60fps differential rendering - Only updates what changed
  • Thread-safe components - Safe for concurrent use
  • Memory optimized - Object pooling and buffer reuse
  • Context-aware - Full context.Context support for cancellation
Components → Render Engine → Terminal I/O
    ↑              ↑             ↓
    └── Event System ←───────────┘

Requirements

  • Go 1.24 or later
  • Real terminal environment (Terminal.app, Command Prompt, SSH, etc.)
  • Not supported: IDE output panels, non-interactive environments

Examples

Basic CLI tool

func main() {
    ctx := context.Background()
    
    display := coal.NewTextDisplay().
        SetText("Server status: Running").
        SetPrefix("Status: ").
        SetStyle(coal.NewStyle().Foreground(coal.ColorGreen))
    
    fmt.Print(display.Render(ctx))
}

Interactive form

func collectUserInfo(ctx context.Context) {
    name, _ := coal.Input(ctx, "Name:", "Enter your name")
    
    languages := []coal.Option[string]{
        {Value: "go", Label: "Go"},
        {Value: "python", Label: "Python"},
        {Value: "rust", Label: "Rust"},
    }
    
    lang, _ := coal.SelectOption(ctx, "Favorite language:", languages)
    
    // Process results...
}

AI chat interface

func chatInterface() {
    // User input
    userMsg := coal.NewUserMessage("How does this work?")
    fmt.Print(userMsg.Render(ctx))
    
    // AI streaming response
    aiStream := coal.NewAIRealTimeStream()
    aiStream.Start()
    
    // Stream from your LLM API
    for token := range llmResponse {
        aiStream.Append(token)
    }
    
    aiStream.Complete()
}

Performance

Optimized for complex terminal applications:

  • < 1ms render time for typical components
  • < 5MB memory usage for complex UIs
  • 1000+ components supported in single application
  • 60fps smooth animations and real-time updates

Used by

Coal is designed for modern terminal applications:

  • CLI tools and utilities
  • Development environments
  • AI assistants and chat interfaces
  • Monitoring dashboards
  • Interactive installers

Contributing

We welcome contributions! See our Contributing Guide for details.

Development

git clone https://github.com/voocel/coal.git
cd coal
go mod tidy
go test ./...

# Run examples
go run examples/basic/main.go

License

MIT License - see LICENSE for details.


Built with Go for the modern terminal. Inspired by Clack and Bubble Tea.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages