phoenix

package module
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Feb 23, 2026 License: MIT Imports: 5 Imported by: 0

README

Phoenix TUI Framework

Phoenix TUI Framework

Go Version Release CI Go Report Card License GoDoc

Multi-module monorepo - 10 independent libraries. Full metrics in CI.

Next-generation Terminal User Interface framework for Go

Organization: github.com/phoenix-tui Go Version: 1.25+

Why Phoenix?

Phoenix rises from the ashes of legacy TUI frameworks, solving critical problems:

  • Perfect Unicode/Emoji support - No more layout bugs
  • High Performance - Differential rendering, caching, zero allocations
  • DDD Architecture - Clean, testable, extendable
  • Rich Component Library - Everything you need out of the box
  • Public Cursor API - Full control for shell applications
  • Inline & Alt-Screen rendering - Per-line diffing without alt screen, or full-screen mode
  • TTY Control - Run editors, shells, and other processes from within your TUI
  • Easy Migration from Charm - Comprehensive migration guide included

Libraries

Phoenix is a modular framework with 10 independent libraries:

Library Description
phoenix/core Terminal primitives, Unicode/Emoji support (correct width calculation)
phoenix/terminal ANSI terminal operations, raw mode, capabilities
phoenix/style CSS-like styling + Theme System (presets, runtime switching)
phoenix/layout Flexbox & grid layout (box model, responsive sizing)
phoenix/tea Elm Architecture + TTY Control + Inline Renderer
phoenix/render High-performance differential renderer
phoenix/components UI components: TextArea, TextInput, List, Viewport, Table, Modal, Progress, Select, MultiSelect, Confirm, Form
phoenix/mouse Mouse events (click, scroll, drag-drop, right-click)
phoenix/clipboard Cross-platform clipboard (OSC 52 for SSH)
phoenix/testing Mock terminal and test utilities

Installation

go get github.com/phoenix-tui/phoenix@latest

This installs the umbrella module with convenient access to all Phoenix libraries through a single import:

import "github.com/phoenix-tui/phoenix"

// Use convenience API
term := phoenix.AutoDetectTerminal()
style := phoenix.NewStyle().Foreground("#00FF00").Bold()
p := phoenix.NewProgram(myModel, phoenix.WithAltScreen[MyModel]())
Install Individual Libraries (For existing projects or selective use)
go get github.com/phoenix-tui/phoenix/tea@latest        # Elm Architecture
go get github.com/phoenix-tui/phoenix/components@latest # UI Components
go get github.com/phoenix-tui/phoenix/style@latest      # Styling
go get github.com/phoenix-tui/phoenix/core@latest       # Terminal primitives

Individual imports give you more control and smaller dependencies:

import (
    tea "github.com/phoenix-tui/phoenix/tea/api"
    "github.com/phoenix-tui/phoenix/components/input/api"
)

Quick Start

Using the Umbrella Module
go get github.com/phoenix-tui/phoenix@latest
package main

import (
    "fmt"
    "os"
    "github.com/phoenix-tui/phoenix"
    tea "github.com/phoenix-tui/phoenix/tea/api"
)

type Model struct {
    count int
}

func (m Model) Init() tea.Cmd { return nil }

func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.KeyMsg:
        if msg.String() == "q" {
            return m, phoenix.Quit()
        }
        m.count++
    }
    return m, nil
}

func (m Model) View() string {
    style := phoenix.NewStyle().Foreground("#00FF00").Bold()
    return style.Render(fmt.Sprintf("Count: %d\n", m.count))
}

func main() {
    p := phoenix.NewProgram(Model{}, phoenix.WithAltScreen[Model]())
    if err := p.Run(); err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
}
Using Individual Libraries
go get github.com/phoenix-tui/phoenix/tea@latest
package main

import (
    "fmt"
    "os"
    "github.com/phoenix-tui/phoenix/tea/api"
)

type Model struct {
    count int
}

func (m Model) Init() api.Cmd { return nil }

func (m Model) Update(msg api.Msg) (Model, api.Cmd) {
    switch msg := msg.(type) {
    case api.KeyMsg:
        if msg.String() == "q" {
            return m, api.Quit()
        }
        m.count++
    }
    return m, nil
}

func (m Model) View() string {
    return fmt.Sprintf("Count: %d\nPress any key to increment, 'q' to quit\n", m.count)
}

func main() {
    p := api.New(Model{}, api.WithAltScreen[Model]())
    if err := p.Run(); err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
}

Documentation

Key Features

1. Perfect Unicode/Emoji Support

Problem: Charm's Lipgloss has broken emoji width calculation (issue #562) Solution: Phoenix uses grapheme cluster detection with correct East Asian Width (UAX #11)

// Phoenix: CORRECT
text := "Hello 👋 World 🌍"
width := style.Width(text)  // Returns 17 (correct!)

// Charm Lipgloss: BROKEN
width := lipgloss.Width(text)  // Returns 19 (wrong!)
2. High Performance

Techniques: Differential rendering, virtual buffer, caching, zero allocations on hot paths

3. DDD Architecture
library/
├── domain/        # Business logic (highest coverage)
├── application/   # Use cases
├── infrastructure/ # Technical details
└── api/           # Public interface
4. Public Cursor API

Problem: Bubbles TextArea has private cursor - syntax highlighting impossible Solution: Phoenix TextInput exposes CursorPosition() and ContentParts()

// Phoenix: PUBLIC API (syntax highlighting works!)
before, at, after := input.ContentParts()
highlighted := syntax.Highlight(before) +
               cursor.Render(at) +
               syntax.Highlight(after)

// Bubbles: PRIVATE (syntax highlighting impossible!)
// cursor is internal field - no access
5. TTY Control

Run external processes (vim, shells, pagers) from within your TUI:

case api.KeyMsg:
    if msg.String() == "e" {
        return m, api.ExecProcess("vim", "file.txt")
    }
case api.ExecProcessFinishedMsg:
    // Editor closed, TUI restored automatically
6. Inline Rendering

Run without alt screen - per-line diffing renders updates in place:

p := api.New(myModel) // inline mode by default - no alt screen needed
7. Mouse & Clipboard Support

Mouse: All buttons (Left, Right, Middle, Wheel), drag-drop, click detection (single/double/triple) Clipboard: Cross-platform (Windows/macOS/Linux), SSH support (OSC 52)

8. Progress Component

Progress bars and 15 animated spinner styles:

import progress "github.com/phoenix-tui/phoenix/components/progress/api"

bar := progress.NewBar(100).SetWidth(40).SetLabel("Downloading").SetValue(65)
spinner := progress.NewSpinner(progress.SpinnerDots).SetLabel("Loading")

Comparison with Charm Ecosystem

Feature Phoenix Charm (Bubbletea/Lipgloss)
Unicode/Emoji Correct width (UAX #11) Broken (#562)
Type Safety Generic constraints interface{} casts
Inline Rendering Per-line diffing Basic
TTY Control ExecProcess + Suspend/Resume ExecProcess only
Cursor API Public Private
Architecture DDD layers Monolithic
Theme System Built-in (4 presets) Manual

Contributing

Phoenix is part of an active development effort. See CONTRIBUTING.md for contribution guidelines and GoDoc for API documentation.

License

MIT License - see LICENSE file for details

Special Thanks

Professor Ancha Baranova - This project would not have been possible without her invaluable help and support. Her assistance was crucial in bringing Phoenix to life.


Rising from the ashes of legacy TUI frameworks

Documentation

Overview

Package phoenix is the root umbrella module for Phoenix TUI Framework.

Phoenix is a modern, high-performance Terminal User Interface framework for Go, built with Domain-Driven Design principles and modern Go 1.25+ patterns.

Architecture

Phoenix consists of 10 independent libraries that can be used together or separately:

  • github.com/phoenix-tui/phoenix/core - Terminal primitives & Unicode support
  • github.com/phoenix-tui/phoenix/style - CSS-like styling system
  • github.com/phoenix-tui/phoenix/tea - Elm Architecture (Model-Update-View)
  • github.com/phoenix-tui/phoenix/layout - Flexbox & Box Model layouts
  • github.com/phoenix-tui/phoenix/render - High-performance differential renderer
  • github.com/phoenix-tui/phoenix/components - Rich UI component library
  • github.com/phoenix-tui/phoenix/mouse - Mouse input handling
  • github.com/phoenix-tui/phoenix/clipboard - Cross-platform clipboard operations
  • github.com/phoenix-tui/phoenix/terminal - Terminal detection & capabilities
  • github.com/phoenix-tui/phoenix/testing - Testing utilities (Mock/Null terminals)

Quick Start

Install individual libraries:

go get github.com/phoenix-tui/phoenix/tea@latest
go get github.com/phoenix-tui/phoenix/components@latest

Or install all libraries via the root module:

go get github.com/phoenix-tui/phoenix@latest

Example: Hello World

package main

import (
    "fmt"
    "os"
    tea "github.com/phoenix-tui/phoenix/tea/api"
)

type model struct{ message string }

func (m model) Init() tea.Cmd { return nil }

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    if _, ok := msg.(tea.KeyMsg); ok {
        return m, tea.Quit
    }
    return m, nil
}

func (m model) View() string {
    return fmt.Sprintf("Hello, %s!\n\nPress any key to quit.", m.message)
}

func main() {
    p := tea.NewProgram(model{message: "World"})
    if _, err := p.Run(); err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
}

Why Phoenix?

Phoenix was created to address critical issues in the Charm ecosystem:

  • Perfect Unicode/Emoji support (no width calculation bugs)
  • 10x better performance (29,000 FPS renderer vs ~450 FPS)
  • Type-safe API with Go 1.25+ generics
  • DDD architecture (testable, maintainable)
  • 94.5% average test coverage
  • Zero external TUI dependencies

Multi-Module Monorepo

This repository uses a multi-module structure where each library is independently versioned. The root module serves as an umbrella module for convenient installation and documentation.

For more information, see:

Version

Phoenix version is managed through git tags and Go modules. To check your installed version:

go list -m github.com/phoenix-tui/phoenix

This will show the exact version you're using, including any pre-release tags.

Index

Constants

View Source
const (
	ColorDepthNone      = coreapi.ColorDepthNone
	ColorDepth8         = coreapi.ColorDepth8
	ColorDepth256       = coreapi.ColorDepth256
	ColorDepthTrueColor = coreapi.ColorDepthTrueColor
)

ColorDepth constants (re-exported from core).

Variables

This section is empty.

Functions

func AutoDetectTerminal

func AutoDetectTerminal() *coreapi.Terminal

AutoDetectTerminal creates a Terminal by auto-detecting the current environment. This is the recommended way to create a Terminal for most applications.

Example:

term := phoenix.AutoDetectTerminal()
fmt.Printf("Terminal size: %dx%d\n", term.Size().Width, term.Size().Height)

func NewANSITerminal

func NewANSITerminal() terminalapi.Terminal

NewANSITerminal creates a new ANSI-based Terminal. Use this when you want to force ANSI escape codes (e.g., for SSH, tmux).

Example:

term := phoenix.NewANSITerminal()
term.Clear()

func NewCapabilities

func NewCapabilities(ansi bool, colorDepth coreapi.ColorDepth, mouse, altScreen, cursor bool) *coreapi.Capabilities

NewCapabilities creates a new terminal capabilities configuration.

Example:

caps := phoenix.NewCapabilities(
	true,                      // ANSI support
	phoenix.ColorDepth256,     // 256-color support
	true,                      // Mouse support
	true,                      // Alt screen support
	true,                      // Cursor support
)

func NewPlatformTerminal

func NewPlatformTerminal() terminalapi.Terminal

NewPlatformTerminal creates a new platform-optimized Terminal. Automatically selects the best implementation for the current platform:

  • Windows Console API (fastest on Windows cmd.exe/PowerShell)
  • ANSI fallback (for Git Bash, MinTTY, Unix)

Note: This is from the terminal package, providing platform-optimized terminal operations. Different from core package which focuses on capabilities detection.

Example:

term := phoenix.NewPlatformTerminal()
term.HideCursor()
defer term.ShowCursor()

func NewProgram

func NewProgram[T modelConstraint[T]](model T, opts ...teaapi.Option[T]) *teaapi.Program[T]

NewProgram creates a new Tea Program with the given model. This is the main entry point for building Phoenix TUI applications.

Example:

type MyModel struct { count int }
// ... implement tea.Model interface ...

p := phoenix.NewProgram(MyModel{}, phoenix.WithAltScreen[MyModel]())
if err := p.Run(); err != nil {
	log.Fatal(err)
}

func NewSize

func NewSize(width, height int) coreapi.Size

NewSize creates a new terminal size (width x height in cells).

Example:

size := phoenix.NewSize(80, 24)  // 80 columns, 24 rows

func NewStyle

func NewStyle() styleapi.Style

NewStyle creates a new Style builder for applying colors, borders, padding, etc.

Example:

s := phoenix.NewStyle().
	Foreground("#00FF00").
	Background("#000000").
	Bold().
	Padding(1)
fmt.Println(s.Render("Styled text"))

func NewTerminal

func NewTerminal() *coreapi.Terminal

NewTerminal creates a new Terminal with default auto-detected capabilities. Equivalent to AutoDetectTerminal() - provided for API completeness.

Example:

term := phoenix.NewTerminal()
fmt.Printf("Terminal size: %dx%d\n", term.Size().Width, term.Size().Height)

func NewTerminalWithCapabilities

func NewTerminalWithCapabilities(caps *coreapi.Capabilities) *coreapi.Terminal

NewTerminalWithCapabilities creates a new Terminal with the specified capabilities. Use this when you need full control over terminal configuration.

Example:

caps := phoenix.NewCapabilities(true, phoenix.ColorDepth256, true, true, true)
term := phoenix.NewTerminalWithCapabilities(caps)

func Quit

func Quit() teaapi.Cmd

Quit returns a command that quits the program.

Example:

func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
	if msg.(tea.KeyMsg).String() == "q" {
		return m, phoenix.Quit()
	}
	return m, nil
}

func ReadClipboard

func ReadClipboard() (string, error)

ReadClipboard reads text from the system clipboard.

Example:

text, err := phoenix.ReadClipboard()
if err != nil {
	log.Fatal(err)
}
fmt.Println("Clipboard:", text)

func WithAltScreen

func WithAltScreen[T any]() teaapi.Option[T]

WithAltScreen enables the alternate screen buffer. This allows your TUI to take over the full terminal without affecting the scrollback.

Example:

p := phoenix.NewProgram(model, phoenix.WithAltScreen[MyModel]())

func WithMouseAllMotion

func WithMouseAllMotion[T any]() teaapi.Option[T]

WithMouseAllMotion enables mouse support with all motion events.

Example:

p := phoenix.NewProgram(model, phoenix.WithMouseAllMotion[MyModel]())

func WriteClipboard

func WriteClipboard(text string) error

WriteClipboard writes text to the system clipboard.

Example:

err := phoenix.WriteClipboard("Hello, clipboard!")
if err != nil {
	log.Fatal(err)
}

Types

This section is empty.

Directories

Path Synopsis
clipboard module
components module
list module
core module
examples
umbrella command
Package main demonstrates using Phoenix via the umbrella module.
Package main demonstrates using Phoenix via the umbrella module.
wheel-scroll module
layout module
mouse module
render module
style module
tea module
terminal module
testing module

Jump to

Keyboard shortcuts

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