# zcatui - TUI Library para Zig > **Última actualización**: 2025-12-08 > **Lenguaje**: Zig 0.15.2 > **Inspiración**: [ratatui](https://github.com/ratatui/ratatui) (Rust TUI library) ## Descripción del Proyecto **zcatui** es una librería para crear interfaces de usuario en terminal (TUI) en Zig puro, inspirada en ratatui de Rust. **Objetivo**: Proveer una API idiomática Zig para construir aplicaciones TUI con widgets, layouts, y estilos, 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) --- ## Arquitectura Objetivo ### 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) ### Módulos Principales (Objetivo) ``` zcatui/ ├── src/ │ ├── root.zig # Entry point, re-exports públicos │ ├── terminal.zig # Terminal abstraction │ ├── buffer.zig # Buffer + Cell types │ ├── layout.zig # Layout, Constraint, Rect │ ├── style.zig # Color, Style, Modifier │ ├── text.zig # Text, Line, Span │ ├── backend/ │ │ ├── backend.zig # Backend interface │ │ └── ansi.zig # ANSI escape sequences (default) │ └── widgets/ │ ├── widget.zig # Widget trait/interface │ ├── block.zig # Block (borders, titles) │ ├── paragraph.zig # Text paragraphs │ ├── list.zig # Selectable lists │ ├── table.zig # Tables with columns │ ├── gauge.zig # Progress bars │ ├── chart.zig # Line/bar charts │ ├── canvas.zig # Arbitrary drawing │ └── tabs.zig # Tab navigation ├── build.zig └── examples/ ├── hello.zig # Minimal example ├── demo.zig # Feature showcase └── counter.zig # Interactive counter ``` --- ## Fases de Implementación ### Fase 1: Core (Mínimo Viable) - [ ] Buffer + Cell (almacenamiento de caracteres + estilos) - [ ] Style + Color (colores 16, 256, RGB) - [ ] Rect (área rectangular) - [ ] Backend ANSI (escape sequences para cualquier terminal) - [ ] Terminal (init, draw, restore) - [ ] Widget trait básico ### Fase 2: Layout - [ ] Constraint (Min, Max, Percentage, Length, Ratio) - [ ] Layout (horizontal, vertical splitting) - [ ] Direction (Horizontal, Vertical) ### Fase 3: Widgets Básicos - [ ] Block (borders, titles, padding) - [ ] Paragraph (texto con wrapping) - [ ] List (items seleccionables) ### Fase 4: Widgets Avanzados - [ ] Table (columnas, headers, selección) - [ ] Gauge (barra de progreso) - [ ] Tabs (navegación por pestañas) - [ ] Chart (gráficos simples) - [ ] Canvas (dibujo libre con braille/block chars) ### Fase 5: Extras - [ ] Input handling (keyboard events) - [ ] Mouse support - [ ] Scrolling - [ ] Animations (opcional) --- ## Conceptos Clave de ratatui a Replicar ### 1. Cell Unidad mínima del buffer: un carácter + su estilo. ```zig const Cell = struct { char: u21, // Unicode codepoint fg: Color, // Foreground color bg: Color, // Background color modifiers: Modifiers, // Bold, italic, underline, etc. }; ``` ### 2. Buffer Grid de celdas que representa el estado de la terminal. ```zig const Buffer = struct { area: Rect, cells: []Cell, pub fn get(self: *Buffer, x: u16, y: u16) *Cell { ... } pub fn set_string(self: *Buffer, x: u16, y: u16, text: []const u8, style: Style) void { ... } pub fn diff(self: *Buffer, other: *Buffer) []Update { ... } }; ``` ### 3. Rect Área rectangular en la terminal. ```zig const Rect = struct { x: u16, y: u16, width: u16, height: u16, pub fn inner(self: Rect, margin: Margin) Rect { ... } pub fn intersection(self: Rect, other: Rect) Rect { ... } }; ``` ### 4. Style Combinación de colores y modificadores. ```zig const Style = struct { fg: ?Color = null, bg: ?Color = null, modifiers: Modifiers = .{}, pub fn fg(color: Color) Style { ... } pub fn bg(color: Color) Style { ... } pub fn bold() Style { ... } pub fn patch(self: Style, other: Style) Style { ... } }; ``` ### 5. Layout Sistema de distribución de espacio. ```zig const Layout = struct { direction: Direction, constraints: []const Constraint, pub fn split(self: Layout, area: Rect) []Rect { ... } }; const Constraint = union(enum) { length: u16, // Exactly N cells min: u16, // At least N cells max: u16, // At most N cells percentage: u16, // N% of available space ratio: struct { num: u32, den: u32 }, }; ``` ### 6. Widget Interface Trait que deben implementar todos los widgets. ```zig const Widget = struct { ptr: *anyopaque, render_fn: *const fn(*anyopaque, Rect, *Buffer) void, pub fn render(self: Widget, area: Rect, buf: *Buffer) void { self.render_fn(self.ptr, area, buf); } }; // Ejemplo implementación: const Block = struct { title: ?[]const u8 = null, borders: Borders = .all, style: Style = .{}, pub fn widget(self: *Block) Widget { return .{ .ptr = self, .render_fn = render, }; } fn render(ptr: *anyopaque, area: Rect, buf: *Buffer) void { const self: *Block = @ptrCast(@alignCast(ptr)); // ... render logic } }; ``` --- ## Referencia: ratatui Widgets | Widget | Descripción | Prioridad | |--------|-------------|-----------| | **Block** | Contenedor con bordes y título | Alta | | **Paragraph** | Texto con wrap y scroll | Alta | | **List** | Lista seleccionable | Alta | | **Table** | Tabla con columnas | Media | | **Gauge** | Barra de progreso | Media | | **Sparkline** | Gráfico mini de línea | Baja | | **Chart** | Gráficos de línea/barras | Baja | | **Canvas** | Dibujo libre (braille) | Baja | | **BarChart** | Gráfico de barras | Baja | | **Tabs** | Navegación por tabs | Media | | **Scrollbar** | Indicador de scroll | Media | | **Calendar** | Widget de calendario | Baja | --- ## 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 | --- ## 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 | ```zig /// Renderiza un widget Block en el área especificada. /// /// Dibuja los bordes según `borders` y el título si está definido. /// El área interior queda disponible para contenido hijo. pub fn render(self: *Block, area: Rect, buf: *Buffer) void { // ... } ``` ### 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()` | ### Terminal I/O ```zig // Escribir a stdout const stdout = std.fs.File.stdout(); const writer = stdout.deprecatedWriter(); try writer.print("\x1b[2J", .{}); // Clear screen // Leer de stdin (para eventos) const stdin = std.fs.File.stdin(); const reader = stdin.deprecatedReader(); ``` --- ## Otros Proyectos del Ecosistema ### Proyectos Zig | Proyecto | Descripción | Estado | |----------|-------------|--------| | **service-monitor** | Monitor HTTP/TCP con notificaciones | Completado | ### 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 (cuando se cree el repo) git remote: git@git.reugenio.com:reugenio/zcatui.git # Comandos frecuentes zig build # Compilar zig build test # Tests zig build run -- examples/hello.zig # Ejecutar ejemplo ``` --- ## Ejemplo de Uso (Objetivo Final) ```zig const std = @import("std"); const zcatui = @import("zcatui"); const Terminal = zcatui.Terminal; const Block = zcatui.widgets.Block; const Paragraph = zcatui.widgets.Paragraph; const Layout = zcatui.Layout; const Constraint = zcatui.Constraint; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); // Inicializar terminal var term = try Terminal.init(allocator); defer term.deinit(); // Loop principal while (true) { try term.draw(struct { pub fn render(frame: *Frame) void { // Layout: dividir en 2 áreas const chunks = Layout.vertical(&.{ Constraint.length(3), Constraint.min(0), }).split(frame.area); // Header var header = Block.init() .title("zcatui Demo") .borders(.all); frame.render(header.widget(), chunks[0]); // Content var content = Paragraph.init("Hello from zcatui!") .block(Block.init().borders(.all)); frame.render(content.widget(), chunks[1]); } }.render); // Handle input if (try term.pollEvent()) |event| { if (event.key == .q) break; } } } ``` --- ## Recursos y Referencias ### ratatui (Rust) - Repo: https://github.com/ratatui/ratatui - Docs: https://docs.rs/ratatui/latest/ratatui/ - Website: https://ratatui.rs/ ### 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 --- ## Estado del Proyecto | Componente | Estado | |------------|--------| | CLAUDE.md | ✅ Creado | | build.zig | ⏳ Pendiente | | Fase 1 (Core) | ⏳ Pendiente | | Fase 2 (Layout) | ⏳ Pendiente | | Fase 3 (Widgets básicos) | ⏳ Pendiente | | Fase 4 (Widgets avanzados) | ⏳ Pendiente | | Fase 5 (Input/extras) | ⏳ Pendiente | --- **Próximos pasos sugeridos para la primera sesión:** 1. Crear `build.zig` básico 2. Implementar `src/style.zig` (Color, Style, Modifiers) 3. Implementar `src/buffer.zig` (Cell, Buffer, Rect) 4. Implementar `src/backend/ansi.zig` (escape sequences) 5. Crear ejemplo mínimo que pinte algo en pantalla