zcatui/CLAUDE.md
reugenio 2a62c0f60b Inicio proyecto zcatui - TUI library para Zig
Librería TUI inspirada en ratatui (Rust), implementada en Zig 0.15.2.

Estructura inicial:
- src/style.zig: Color, Style, Modifier
- src/buffer.zig: Cell, Buffer, Rect
- src/layout.zig: Layout, Constraint, Direction
- src/terminal.zig: Terminal abstraction
- src/backend/backend.zig: ANSI escape sequences
- src/widgets/block.zig: Block con borders y título
- src/widgets/paragraph.zig: Paragraph con wrapping
- examples/hello.zig: Demo funcional

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

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

13 KiB

zcatui - TUI Library para Zig

Última actualización: 2025-12-08 Lenguaje: Zig 0.15.2 Inspiración: 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.

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.

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.

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.

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.

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.

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
/// 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

// 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

# 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)

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)

Zig

ANSI Escape Codes


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