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>
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 normasNORMAS_TRABAJO_CONSENSUADAS.md- Metodología fundamentalQUICK_REFERENCE.md- Cheat sheet rápidoINFRASTRUCTURE/- Documentación de servidores
Protocolo de Inicio de Conversación
- Leer
TEAM_STANDARDS/LAST_UPDATE.md(detectar cambios recientes) - Leer este archivo
CLAUDE.md - Verificar estado del proyecto (
git status,zig build) - 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
- Repo: https://github.com/ratatui/ratatui
- Docs: https://docs.rs/ratatui/latest/ratatui/
- Website: https://ratatui.rs/
- Clone local:
/mnt/cello2/arno/re/recode/ratatui-reference/
Zig
- Docs 0.15: https://ziglang.org/documentation/0.15.0/std/
- Guía migración:
TEAM_STANDARDS/INFRASTRUCTURE/ZIG_0.15_GUIA.md
ANSI Escape Codes
- Referencia: https://en.wikipedia.org/wiki/ANSI_escape_code
- Colores: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
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