Eventos de teclado: - Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind - Soporte para todas las teclas: caracteres, F1-F12, navegación, control - Modificadores: Ctrl, Alt, Shift, Super Eventos de ratón: - MouseEvent, MouseEventKind, MouseButton - Click, release, drag, scroll (up/down/left/right) - Posición (column, row) con modificadores - Protocolos: SGR extended y X10 legacy Parser de escape sequences: - CSI sequences (arrows, F-keys, navigation) - SS3 sequences (F1-F4 alternativo) - SGR mouse protocol (mejores coordenadas) - X10 mouse protocol (compatibilidad) - Focus events, bracketed paste Cursor control: - Visibility: show/hide - Blinking: enable/disable - Styles: block, underline, bar (blinking/steady) - Position: moveTo, moveUp/Down/Left/Right - Save/restore position Terminal integrado: - pollEvent(timeout_ms) - polling con timeout - readEvent() - blocking read - enableMouseCapture/disableMouseCapture - enableFocusChange/disableFocusChange - enableBracketedPaste/disableBracketedPaste Ejemplo interactivo: - examples/events_demo.zig Tests: 47 (29 nuevos para eventos y cursor) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
493 lines
15 KiB
Markdown
493 lines
15 KiB
Markdown
# zcatui - TUI Library para Zig
|
|
|
|
> **Última actualización**: 2025-12-08
|
|
> **Lenguaje**: Zig 0.15.2
|
|
> **Inspiración**: [ratatui](https://github.com/ratatui/ratatui) + [crossterm](https://github.com/crossterm-rs/crossterm) (Rust)
|
|
> **Estado**: v1.2 - Renderizado + Eventos integrados
|
|
|
|
## 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.2) - 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 (13 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` |
|
|
|
|
### Tests
|
|
|
|
| Archivo | Tests |
|
|
|---------|-------|
|
|
| barchart.zig | 16 |
|
|
| table.zig | 14 |
|
|
| calendar.zig | 10 |
|
|
| canvas.zig | 10 |
|
|
| list.zig | 10 |
|
|
| tabs.zig | 9 |
|
|
| chart.zig | 8 |
|
|
| gauge.zig | 8 |
|
|
| sparkline.zig | 6 |
|
|
| scrollbar.zig | 5 |
|
|
| block.zig | 3 |
|
|
| paragraph.zig | 2 |
|
|
| clear.zig | 2 |
|
|
| **Total widgets** | **103** |
|
|
|
|
---
|
|
|
|
## Arquitectura
|
|
|
|
### Diseño: Immediate Mode Rendering
|
|
|
|
Como ratatui, usamos **renderizado inmediato con buffers intermedios**:
|
|
|
|
```
|
|
┌─────────────┐ ┌────────┐ ┌──────────┐
|
|
│ 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)
|
|
│ ├── 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
|
|
├── examples/
|
|
│ ├── hello.zig # Minimal example
|
|
│ └── events_demo.zig # Interactive keyboard/mouse demo
|
|
├── docs/
|
|
│ ├── ARCHITECTURE.md # Arquitectura detallada
|
|
│ ├── WIDGETS.md # Documentación de widgets
|
|
│ └── API.md # Referencia de API
|
|
├── build.zig
|
|
└── CLAUDE.md
|
|
```
|
|
|
|
---
|
|
|
|
## Widgets Implementados
|
|
|
|
### Block
|
|
Contenedor base con bordes y títulos.
|
|
```zig
|
|
const block = Block.init()
|
|
.title("Mi Título")
|
|
.borders(Borders.all)
|
|
.borderStyle(Style.default.fg(Color.blue));
|
|
block.render(area, buf);
|
|
```
|
|
|
|
### Paragraph
|
|
Texto con word-wrapping y scroll.
|
|
```zig
|
|
const para = Paragraph.init(text)
|
|
.setBlock(block)
|
|
.setWrap(.{ .trim = true })
|
|
.setAlignment(.center);
|
|
para.render(area, buf);
|
|
```
|
|
|
|
### List (con ListState)
|
|
Lista seleccionable con scroll automático.
|
|
```zig
|
|
var state = ListState.init();
|
|
state.select(2);
|
|
const list = List.init(items)
|
|
.setBlock(block)
|
|
.setHighlightStyle(Style.default.bg(Color.yellow));
|
|
list.renderStateful(area, buf, &state);
|
|
```
|
|
|
|
### Table (con TableState)
|
|
Tabla multi-columna con selección.
|
|
```zig
|
|
var state = TableState.init();
|
|
const table = Table.init(rows, widths)
|
|
.setHeader(header_row)
|
|
.setHighlightStyle(Style.default.bg(Color.blue));
|
|
table.renderStateful(area, buf, &state);
|
|
```
|
|
|
|
### Gauge y LineGauge
|
|
Barras de progreso.
|
|
```zig
|
|
const gauge = Gauge.init()
|
|
.setRatio(0.75)
|
|
.setLabel("75%")
|
|
.setGaugeStyle(Style.default.fg(Color.green));
|
|
gauge.render(area, buf);
|
|
```
|
|
|
|
### Tabs
|
|
Navegación por pestañas.
|
|
```zig
|
|
const tabs = Tabs.init(&titles)
|
|
.select(1)
|
|
.setHighlightStyle(Style.default.fg(Color.yellow));
|
|
tabs.render(area, buf);
|
|
```
|
|
|
|
### Sparkline
|
|
Mini gráficos de línea.
|
|
```zig
|
|
const spark = Sparkline.init()
|
|
.setData(&data)
|
|
.setMax(100)
|
|
.setStyle(Style.default.fg(Color.cyan));
|
|
spark.render(area, buf);
|
|
```
|
|
|
|
### Scrollbar (con ScrollbarState)
|
|
Indicador de scroll.
|
|
```zig
|
|
var state = ScrollbarState.init(100).setPosition(25);
|
|
const scrollbar = Scrollbar.init(.vertical_right);
|
|
scrollbar.render(area, buf, &state);
|
|
```
|
|
|
|
### BarChart
|
|
Gráficos de barras con grupos.
|
|
```zig
|
|
const chart = BarChart.init()
|
|
.setData(&bar_groups)
|
|
.setBarWidth(5)
|
|
.setBarGap(1);
|
|
chart.render(area, buf);
|
|
```
|
|
|
|
### Canvas
|
|
Dibujo libre con diferentes marcadores.
|
|
```zig
|
|
const canvas = Canvas.init()
|
|
.setXBounds(0, 100)
|
|
.setYBounds(0, 100)
|
|
.setMarker(.braille)
|
|
.paint(struct {
|
|
pub fn draw(ctx: *Painter) void {
|
|
ctx.drawLine(0, 0, 100, 100, Color.red);
|
|
ctx.drawCircle(50, 50, 25, Color.blue);
|
|
}
|
|
}.draw);
|
|
canvas.render(area, buf);
|
|
```
|
|
|
|
### Chart
|
|
Gráficos de línea/scatter/barras con ejes.
|
|
```zig
|
|
const chart = Chart.init(&datasets)
|
|
.setXAxis(x_axis)
|
|
.setYAxis(y_axis)
|
|
.setLegendPosition(.top_right);
|
|
chart.render(area, buf);
|
|
```
|
|
|
|
### Calendar (Monthly)
|
|
Calendario mensual.
|
|
```zig
|
|
const cal = Monthly.init(Date.init(2024, 12, 1))
|
|
.showMonthHeader(Style.default.fg(Color.blue))
|
|
.showWeekdaysHeader(Style.default)
|
|
.withEvents(events);
|
|
cal.render(area, buf);
|
|
```
|
|
|
|
### Clear
|
|
Limpia/resetea un área.
|
|
```zig
|
|
Clear.init().render(area, buf);
|
|
```
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
```bash
|
|
# Compilar
|
|
zig build
|
|
|
|
# Tests
|
|
zig build test
|
|
|
|
# Tests con resumen
|
|
zig build test --summary all
|
|
```
|
|
|
|
---
|
|
|
|
## 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ó
|
|
|
|
---
|
|
|
|
## Principios de Desarrollo
|
|
|
|
### Estándares Zig Open Source (#24 de NORMAS)
|
|
|
|
> **Este proyecto será público. El código debe ser ejemplar.**
|
|
|
|
| Aspecto | Estándar |
|
|
|---------|----------|
|
|
| **Claridad** | Código autoexplicativo, nombres descriptivos |
|
|
| **Comentarios** | Doc comments (`///`) en TODAS las funciones públicas |
|
|
| **Estructura** | Organización lógica, separación de responsabilidades |
|
|
| **Idiomático** | snake_case, error handling explícito, sin magia |
|
|
|
|
### Principios Generales
|
|
|
|
- **DRY**: Una sola función por tarea
|
|
- **Fragmentación**: <400 líneas core, <200 líneas utils
|
|
- **Testing progresivo**: Compilar y probar cada cambio
|
|
- **Funcionalidad > Performance**: Primero que funcione, luego optimizar
|
|
|
|
---
|
|
|
|
## API de Zig 0.15.2 - Cambios Importantes
|
|
|
|
> Ver guía completa: `TEAM_STANDARDS/INFRASTRUCTURE/ZIG_0.15_GUIA.md`
|
|
|
|
### Cambios Clave para este Proyecto
|
|
|
|
| Componente | Zig 0.15 |
|
|
|------------|----------|
|
|
| stdout | `std.fs.File.stdout().deprecatedWriter()` |
|
|
| ArrayList | `std.array_list.Managed(T).init(alloc)` |
|
|
| file.reader() | `file.deprecatedReader()` |
|
|
| sleep | `std.Thread.sleep()` |
|
|
|
|
---
|
|
|
|
## Otros Proyectos del Ecosistema
|
|
|
|
### Proyectos Zig
|
|
| Proyecto | Descripción | Estado |
|
|
|----------|-------------|--------|
|
|
| **service-monitor** | Monitor HTTP/TCP con notificaciones | Completado |
|
|
| **zcatui** | TUI library inspirada en ratatui | v1.0 Completo |
|
|
|
|
### Proyectos Go (referencia)
|
|
| Proyecto | Descripción |
|
|
|----------|-------------|
|
|
| **simifactu** | API facturación electrónica |
|
|
| **ms-web** (mundisofa) | Web e-commerce |
|
|
| **0fiS** | Aplicación desktop Fyne |
|
|
|
|
### Infraestructura
|
|
| Recurso | Ubicación |
|
|
|---------|-----------|
|
|
| **Git server** | git.reugenio.com (Forgejo) |
|
|
| **Servidor** | Simba (188.245.244.244) |
|
|
| **Docs infra** | `TEAM_STANDARDS/INFRASTRUCTURE/` |
|
|
|
|
---
|
|
|
|
## Control de Versiones
|
|
|
|
```bash
|
|
# 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
|
|
|
|
---
|
|
|
|
## Optimizaciones de Performance (v1.1)
|
|
|
|
### Implementadas
|
|
- [x] **Symbol compacto**: Almacena UTF-8 directamente (4 bytes max), evita conversión en cada render
|
|
- [x] **Buffer diff**: Iterator que solo retorna celdas modificadas, reduce I/O dramáticamente
|
|
- [x] **Cell.eql()**: Comparación eficiente de celdas para el diff
|
|
- [x] **Buffer.resize()**: Redimensiona preservando contenido existente
|
|
- [x] **writeSymbol()**: Escribe UTF-8 directo sin conversión de codepoint
|
|
|
|
### Pendientes (v1.2+)
|
|
- [ ] Lazy rendering para widgets grandes
|
|
- [ ] Pooling de memoria para cells
|
|
- [ ] SIMD para operaciones de buffer masivas
|
|
|
|
### Funcionalidades Adicionales
|
|
- [ ] Input handling (keyboard events)
|
|
- [ ] Mouse support
|
|
- [ ] Clipboard integration
|
|
- [ ] Animaciones
|
|
|
|
### Documentación
|
|
- [ ] Ejemplos completos
|
|
- [ ] Tutorial paso a paso
|
|
- [ ] API reference generada
|
|
|
|
---
|
|
|
|
## Historial de Desarrollo
|
|
|
|
### 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
|
|
- Tests: 47 tests (29 nuevos para eventos)
|
|
|
|
### 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
|
|
- Tests: 18 tests (9 nuevos para optimizaciones)
|
|
|
|
### 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
|