zcatui/CLAUDE.md
reugenio b393008497 Update CLAUDE.md to v1.3 with complete documentation
Documents all features implemented in this session:
- Input widget (readline-style)
- Popup and Modal widgets
- Menu and MenuBar widgets
- Animation system (Easing, Animation, Timer)
- Clipboard OSC 52 support
- 10 example demos

Updated roadmap with pending features:
- Scrollable containers
- Textarea widget
- Tree widget
- File picker
- Hyperlinks OSC 8
- Image protocol
- Notifications OSC 9/777

Includes summary of LEGO panels study from simifactu-fyne

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 17:01:41 +01:00

17 KiB

zcatui - TUI Library para Zig

Última actualización: 2025-12-08 Lenguaje: Zig 0.15.2 Inspiración: ratatui + crossterm (Rust) Estado: v1.3 - Widgets completos + Animaciones + Clipboard + Menus

Descripción del Proyecto

zcatui es una librería para crear interfaces de usuario en terminal (TUI) en Zig puro, combinando las capacidades de ratatui (renderizado) y crossterm (eventos) de Rust.

Objetivo: Proveer una API idiomática Zig para construir aplicaciones TUI interactivas con widgets, layouts, estilos, y manejo de eventos de teclado/ratón, manteniendo la filosofía de Zig: simple, explícito, y sin magia.

Nombre: "zcat" + "ui" (un guiño a ratatui y la mascota de Zig)

Diferencia con Rust: En Rust, ratatui y crossterm son librerías separadas. En zcatui, todo está integrado en una sola librería.


Estado Actual del Proyecto

Implementación Completa (v1.3) - 2025-12-08

Componente Estado Archivo
Core Completo
Style + Color src/style.zig
Buffer + Cell src/buffer.zig
Text + Span + Line src/text.zig
Layout + Constraint src/layout.zig
Terminal src/terminal.zig
Backend ANSI src/backend/
Eventos (crossterm-style) Completo
Event, KeyEvent, MouseEvent src/event.zig
EventReader + polling src/event/reader.zig
Escape sequence parser src/event/parse.zig
Cursor control src/cursor.zig
Symbols Completo src/symbols/
Line drawing line.zig
Border sets border.zig
Block chars block.zig
Bar chars bar.zig
Braille patterns braille.zig
Half-block half_block.zig
Scrollbar symbols scrollbar.zig
Markers marker.zig
Widgets Completo (17 widgets) src/widgets/
Block block.zig
Paragraph paragraph.zig
List list.zig
Table table.zig
Gauge + LineGauge gauge.zig
Tabs tabs.zig
Sparkline sparkline.zig
Scrollbar scrollbar.zig
BarChart barchart.zig
Canvas canvas.zig
Chart chart.zig
Calendar (Monthly) calendar.zig
Clear clear.zig
Input (readline-style) input.zig
Popup popup.zig
Modal popup.zig
Menu + MenuBar menu.zig
Extras Completo
Animation system src/animation.zig
Clipboard (OSC 52) src/clipboard.zig

Examples (10 demos)

Ejemplo Descripción Comando
hello Minimal TUI app zig build hello
events_demo Keyboard/mouse events zig build events-demo
list_demo Lista navegable zig build list-demo
table_demo Tabla con selección zig build table-demo
dashboard Demo completo zig build dashboard
input_demo Input readline-style zig build input-demo
animation_demo Easing functions zig build animation-demo
clipboard_demo OSC 52 clipboard zig build clipboard-demo
menu_demo MenuBar + Modal zig build menu-demo

Tests

Módulo Tests
Widgets (13 originales) 103
Animation 12
Clipboard 8
Popup 5
Menu 5
Events 29
Total ~160+

Widgets Nuevos (v1.3)

Input (readline-style)

Input de texto con edición avanzada.

var state = InputState.init(allocator);
defer state.deinit();

const input = Input.init()
    .setBlock(Block.init().title("Name").borders(Borders.all))
    .setPlaceholder("Enter your name...");
input.render(area, buf, &state);

// Keyboard handling
if (state.handleKey(key_event)) {
    // Key was consumed by input
}

Features:

  • Cursor movement (←→, Home, End)
  • Word navigation (Ctrl+←→)
  • Delete (Backspace, Del, Ctrl+W, Ctrl+U, Ctrl+K)
  • Kill/yank (Ctrl+K, Ctrl+Y)
  • History (↑↓)
  • Unicode support

Popup

Overlay flotante.

const popup = Popup.init()
    .setSize(40, 10)
    .setBlock(Block.init().title("Info").borders(Borders.all))
    .setDimBackground(true)
    .center();
popup.render(area, buf);

Modal

Diálogo con botones.

var modal = Modal.init()
    .setTitle("Confirm")
    .setMessage(&.{"Are you sure?"})
    .setButtons(&.{
        .{ .label = "OK" },
        .{ .label = "Cancel" },
    });
modal.render(area, buf);

// Navigation
modal.focusNext();  // Tab
modal.focusPrev();  // Shift+Tab
const selected = modal.getFocusedButton();

Helpers:

const confirm = confirmDialog("Title", &.{"Message"});
const alert = alertDialog("Title", &.{"Message"});
const yesno = yesNoCancelDialog("Title", &.{"Message"});

Menu + MenuBar

Sistema de menús.

const file_menu = Menu.init().setItems(&.{
    MenuItem.action("New", 'n').setShortcut("Ctrl+", 'N'),
    MenuItem.action("Open", 'o'),
    MenuItem.separator(),
    MenuItem.action("Exit", 'q'),
});

var menu_bar = MenuBar.init().setItems(&.{
    MenuBarItem.init("File", file_menu),
    MenuBarItem.init("Edit", edit_menu),
});

menu_bar.render(area, buf);

// Navigation
menu_bar.selectNext();      // →
menu_bar.selectPrev();      // ←
menu_bar.openSelected();    // Enter
menu_bar.closeMenus();      // Esc

// Dropdown
if (menu_bar.open_menu) |idx| {
    const dropdown_area = menu_bar.getDropdownArea(area, idx);
    var menu = getCurrentMenu();
    menu.render(dropdown_area, buf);
}

MenuItem types:

  • .action - Clickable action
  • .separator - Visual separator
  • .submenu - Opens nested menu
  • .toggle - Checkbox option

Sistema de Animaciones

Easing Functions

const Easing = zcatui.Easing;

// Available:
Easing.linear
Easing.easeIn / easeOut / easeInOut
Easing.easeInCubic / easeOutCubic / easeInOutCubic
Easing.easeInExpo / easeOutExpo
Easing.easeOutBounce
Easing.easeOutElastic
Easing.easeOutBack

Animation

var anim = Animation.init(0, 100, 2000)  // 0→100 over 2 seconds
    .setEasing(Easing.easeOutBounce)
    .setRepeat(-1)      // Infinite
    .setPingPong(true); // Reverse on repeat

// In game loop:
anim.advance(delta_ms);
const value = anim.getValue();      // f64
const percent = anim.getValueU16(); // u16 (0-65535)

Timer

var timer = Timer.repeating(1000); // 1 second

if (timer.advance(delta_ms)) {
    // Timer triggered!
}

AnimationGroup

var group = AnimationGroup.parallel(&animations);
// or
var group = AnimationGroup.sequential(&animations);

group.advance(delta_ms);
if (group.isComplete()) { ... }

Clipboard (OSC 52)

const clipboard = zcatui.clipboard;
const writer = term.backend.stdout.deprecatedWriter();

// Copy to system clipboard
try clipboard.copy(allocator, writer, "Hello!");

// Copy to X11 primary selection
try clipboard.copySmallTo(writer, "Text", .primary);

// Copy to both
try clipboard.copySmallTo(writer, "Text", .both);

// Clear clipboard
try clipboard.clear(writer);

Terminal support: xterm, iTerm2, kitty, alacritty, WezTerm, foot tmux: Enable with set -g set-clipboard on


Arquitectura

Diseño: Immediate Mode Rendering

┌─────────────┐    ┌────────┐    ┌──────────┐
│ Application │───▶│ Buffer │───▶│ Terminal │
│   (widgets) │    │ (cells)│    │ (output) │
└─────────────┘    └────────┘    └──────────┘
  • Cada frame, la aplicación renderiza TODOS los widgets al buffer
  • El buffer se compara con el anterior (diff)
  • Solo se envían cambios a la terminal (eficiencia)

Estructura de Archivos

zcatui/
├── src/
│   ├── root.zig           # Entry point, re-exports públicos
│   ├── terminal.zig       # Terminal + eventos integrados
│   ├── buffer.zig         # Buffer + Cell + Rect
│   ├── layout.zig         # Layout, Constraint, Direction
│   ├── style.zig          # Color, Style, Modifier
│   ├── text.zig           # Text, Line, Span, Alignment
│   ├── event.zig          # Event, KeyEvent, MouseEvent, KeyCode
│   ├── cursor.zig         # Cursor control (shapes, position)
│   ├── animation.zig      # Easing, Animation, Timer
│   ├── clipboard.zig      # OSC 52 clipboard support
│   ├── event/
│   │   ├── reader.zig     # EventReader + polling
│   │   └── parse.zig      # Escape sequence parser
│   ├── backend/
│   │   └── backend.zig    # ANSI escape sequences backend
│   ├── symbols/
│   │   ├── symbols.zig    # Re-exports
│   │   ├── line.zig       # Line drawing characters
│   │   ├── border.zig     # Border sets
│   │   ├── block.zig      # Block elements
│   │   ├── bar.zig        # Bar characters
│   │   ├── braille.zig    # Braille patterns (256)
│   │   ├── half_block.zig # Half-block chars
│   │   ├── scrollbar.zig  # Scrollbar symbols
│   │   └── marker.zig     # Chart markers
│   └── widgets/
│       ├── block.zig      # Block (borders, titles, padding)
│       ├── paragraph.zig  # Text with wrapping
│       ├── list.zig       # Selectable list with state
│       ├── table.zig      # Multi-column table
│       ├── gauge.zig      # Progress bars (Gauge + LineGauge)
│       ├── tabs.zig       # Tab navigation
│       ├── sparkline.zig  # Mini line graphs
│       ├── scrollbar.zig  # Scroll indicator
│       ├── barchart.zig   # Bar charts with groups
│       ├── canvas.zig     # Drawing (braille/half-block)
│       ├── chart.zig      # Line/scatter/bar graphs
│       ├── calendar.zig   # Monthly calendar
│       ├── clear.zig      # Clear/reset area
│       ├── input.zig      # Readline-style input
│       ├── popup.zig      # Popup + Modal
│       └── menu.zig       # Menu + MenuBar
├── examples/
│   ├── hello.zig
│   ├── events_demo.zig
│   ├── list_demo.zig
│   ├── table_demo.zig
│   ├── dashboard.zig
│   ├── input_demo.zig
│   ├── animation_demo.zig
│   ├── clipboard_demo.zig
│   └── menu_demo.zig
├── docs/
│   ├── ARCHITECTURE.md
│   ├── WIDGETS.md
│   └── API.md
├── build.zig
└── CLAUDE.md

Stack Técnico

Componente Elección
Lenguaje Zig 0.15.2
Zig path /mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig
Backend ANSI escape sequences (portable)
Sin dependencias externas Solo stdlib de Zig
Target Linux primario, cross-platform objetivo

Comandos

# Compilar todo
zig build

# Tests
zig build test

# Ejecutar ejemplos
zig build hello
zig build events-demo
zig build list-demo
zig build table-demo
zig build dashboard
zig build input-demo
zig build animation-demo
zig build clipboard-demo
zig build menu-demo

Funcionalidades Pendientes (Roadmap)

Prioridad Alta

  • Scrollable containers - Viewport para contenido largo
  • Textarea widget - Input multilínea con scroll

Prioridad Media

  • Sistema LEGO panels - Patrones de simifactu-fyne (isDirty, composites)
  • Context menu - Menú contextual (right-click)
  • Tooltips - Información emergente

Prioridad Baja

  • Hyperlinks OSC 8 - Links clickeables en terminal
  • Image protocol - Kitty/iTerm2 inline images
  • Notifications OSC 9/777 - Desktop notifications
  • Tree widget - Árbol expandible/colapsable
  • File picker - Selección de archivos

Performance

  • Lazy rendering para widgets grandes
  • Pooling de memoria para cells
  • SIMD para operaciones de buffer masivas

Documentación

  • Tutorial paso a paso
  • API reference generada
  • Más ejemplos

Estudio: Sistema LEGO Panels (simifactu-fyne)

Se realizó un análisis completo del sistema de paneles de simifactu-fyne. Los patrones clave son:

1. Autonomous Panel Interface

Cada panel se auto-gestiona: conoce su ID, tipo, sabe construir su UI y refrescarse.

2. isDirty Pattern

Desacopla notificación (O(1)) de actualización (O(n)):

  • Observer notifica → solo pone flag isDirty = true
  • Refresh loop verifica isDirty()
  • Panel actualiza solo si necesario
  • Flags granulares: dirtyData, dirtyColors, dirtyConfig, dirtySorting

3. Composición LEGO

Paneles pequeños se combinan en layouts:

  • HSplit: Dos paneles lado a lado
  • VSplit/Border: Top/center/bottom
  • Composites: Paneles que contienen otros paneles

4. WindowComposer

Orquestador que maneja:

  • Registro de paneles por posición (left, center, right, top)
  • Navegación de foco (NextPanel, PreviousPanel)
  • Broadcasting de eventos

5. Callbacks para comunicación

listPanel.OnItemSelected = func(item Item) {
    detailPanel.LoadItem(item)
}

Archivos de referencia:

  • /mnt/cello2/arno/re/recode/go/simifactu-fyne/internal/ui/panels_v3/

Equipo y Metodología

Quiénes Somos

  • Usuario: Desarrollador independiente, proyectos comerciales propios
  • Claude: Asistente de programación (Claude Code)

Normas de Trabajo Centralizadas

IMPORTANTE: Todas las normas de trabajo están en:

/mnt/cello2/arno/re/recode/TEAM_STANDARDS/

Archivos clave a leer:

  • LAST_UPDATE.md - LEER PRIMERO - Cambios recientes en normas
  • NORMAS_TRABAJO_CONSENSUADAS.md - Metodología fundamental
  • QUICK_REFERENCE.md - Cheat sheet rápido
  • INFRASTRUCTURE/ - Documentación de servidores

Protocolo de Inicio de Conversación

  1. Leer TEAM_STANDARDS/LAST_UPDATE.md (detectar cambios recientes)
  2. Leer este archivo CLAUDE.md
  3. Verificar estado del proyecto (git status, zig build)
  4. Continuar desde donde se dejó

Control de Versiones

# Remote
git remote: git@git.reugenio.com:reugenio/zcatui.git

# Comandos frecuentes
zig build                    # Compilar
zig build test               # Tests
zig build test --summary all # Tests con detalles

Recursos y Referencias

ratatui (Rust) - Referencia de implementación

Zig

ANSI Escape Codes


Historial de Desarrollo

2025-12-08 - v1.3 (Widgets avanzados + Extras)

Widgets nuevos:

  • Input: Readline-style con cursor, word nav, kill/yank, history, Unicode
  • Popup: Overlay flotante con backdrop dimming
  • Modal: Diálogo con título, mensaje, botones navegables
  • Menu: Dropdown menu con shortcuts
  • MenuBar: Barra horizontal con dropdowns

Sistemas nuevos:

  • Animation: Easing functions, Animation, AnimationGroup, Timer
  • Clipboard: OSC 52 copy/paste support

Ejemplos nuevos:

  • list_demo.zig, table_demo.zig, dashboard.zig
  • input_demo.zig, animation_demo.zig
  • clipboard_demo.zig, menu_demo.zig

Estudio:

  • Análisis completo del sistema LEGO panels de simifactu-fyne

2025-12-08 - v1.2 (Eventos - crossterm-style)

  • Sistema de eventos integrado (teclado + ratón)
  • Event, KeyEvent, MouseEvent, KeyCode types
  • EventReader con polling y timeout
  • Parser de escape sequences (CSI, SS3, SGR mouse, X10 mouse)
  • Cursor control (shapes, blinking, save/restore)
  • Terminal integrado: pollEvent(), enableMouseCapture(), enableFocusChange()
  • Ejemplo interactivo: events_demo.zig

2025-12-08 - v1.1 (Performance)

  • Symbol: tipo compacto UTF-8 (4 bytes max)
  • Buffer.diff(): renderizado diferencial eficiente
  • Cell.eql(): comparación optimizada
  • Buffer.resize(): redimensionado con preservación
  • writeSymbol(): output UTF-8 directo

2025-12-08 - v1.0 (Implementación Completa)

  • Implementados todos los widgets de ratatui (13 widgets)
  • Sistema de símbolos completo (braille, half-block, borders, etc.)
  • 103+ tests en widgets
  • Documentación completa (ARCHITECTURE.md, WIDGETS.md, API.md)

2025-12-08 - Inicio del Proyecto

  • Creación de CLAUDE.md
  • Definición de arquitectura
  • Estructura inicial del proyecto