zcatui/docs/API_REFERENCE.md
reugenio 75185cb4fa docs: Add comprehensive API reference manual
- Complete API documentation for zcatui v2.2
- All 35 widgets documented with examples
- Core types: Buffer, Style, Text, Layout
- Terminal interface and event handling
- Animation, focus, themes systems
- v2.2 features: resize, drag, debug, profiler
- Utilities: clipboard, hyperlinks, notifications
- File index with all 70+ source files
- 1100+ lines of documentation

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

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

32 KiB

zcatui API Reference v2.2

Manual de referencia completo para la libreria TUI de Zig. Equivalente a ratatui + crossterm de Rust, en un solo paquete.


Tabla de Contenidos

  1. Quick Start
  2. Core Types
  3. Terminal
  4. Layout System
  5. Widgets
  6. Events
  7. Styling
  8. Animation
  9. Focus Management
  10. Themes
  11. Utilities
  12. v2.2 Features

Quick Start

const std = @import("std");
const zcatui = @import("zcatui");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Initialize terminal
    var term = try zcatui.Terminal.init(allocator);
    defer term.deinit();

    // Enable features
    try term.enableMouseCapture();
    term.enableAutoResize();

    // Main loop
    while (true) {
        try term.draw(render);

        if (try term.pollEvent(100)) |event| {
            switch (event) {
                .key => |key| {
                    if (key.code == .esc) break;
                },
                else => {},
            }
        }
    }
}

fn render(area: zcatui.Rect, buf: *zcatui.Buffer) void {
    const block = zcatui.widgets.Block.bordered()
        .title("Hello zcatui!");
    block.render(area, buf);
}

Core Types

Buffer (src/buffer.zig)

Buffer de renderizado con diff para actualizaciones eficientes.

Type Description
Buffer Grid de celdas para renderizado
Cell Celda individual (simbolo + estilo)
Rect Area rectangular (x, y, width, height)
Symbol UTF-8 compacto (hasta 4 bytes)
Margin Margenes para Rect.inner()
CellUpdate Update de celda para diff
DiffIterator Iterador de diferencias entre buffers
// Rect
const area = Rect.init(0, 0, 80, 24);
area.isEmpty()           // bool
area.area()              // u32 (width * height)
area.left(), .right()    // u16
area.top(), .bottom()    // u16
area.inner(margin)       // Rect con margenes aplicados
area.intersection(other) // Rect interseccion
area.contains(x, y)      // bool

// Margin
Margin.uniform(2)           // 2 en todos lados
Margin.symmetric(h, v)      // horizontal, vertical

// Buffer
var buf = try Buffer.init(allocator, rect);
defer buf.deinit();
buf.setChar(x, y, 'X', style)
buf.setString(x, y, "text", style) // returns u16 chars written
buf.fill(rect, char, style)
buf.clear()
buf.get(x, y)            // ?Cell
buf.getPtr(x, y)         // ?*Cell
buf.diff(&other_buffer)  // DiffIterator
buf.merge(&other_buffer)
buf.setStyle(rect, style)
try buf.resize(new_rect)

// Symbol
Symbol.fromSlice("X")
Symbol.fromCodepoint('X')
symbol.slice()           // []const u8
symbol.eql(other)        // bool

// Cell
Cell.init('X')
Cell.fromStr("X")
cell.setStyle(style)
cell.setChar(codepoint)
cell.setSymbol(string)
cell.reset()
cell.eql(other)
cell.char()              // u21

Style (src/style.zig)

Colores y modificadores de texto.

Type Description
Color Color (ANSI, 256, RGB)
Style Estilo completo (fg, bg, modifiers)
Modifier Modificadores (bold, italic, etc)
// Color
Color.reset              // Reset to default
Color.black, .red, .green, .yellow, .blue, .magenta, .cyan, .white
Color.rgb(255, 128, 0)   // 24-bit RGB
Color.indexed(200)       // 256 palette

// Style (builder pattern)
const style = Style{}
    .fg(Color.red)
    .bg(Color.black)
    .bold()
    .italic()
    .underlined()
    .dim()
    .reversed();

style.add_modifier(.{ .bold = true })
style.remove_modifier(.{ .bold = true })
style.patch(other_style)

// Modifier
Modifier.BOLD
Modifier.DIM
Modifier.ITALIC
Modifier.UNDERLINED
Modifier.REVERSED
Modifier.CROSSED_OUT
modifier.insert(other)   // union
modifier.remove(other)   // difference

Text (src/text.zig)

Primitivas de texto con estilos.

Type Description
Span String con un solo estilo
Line Linea de Spans
Text Multiples Lines
StyledGrapheme Grafema con estilo
Alignment left, center, right
// Span
Span.raw("hello")
Span.styled("hello", style)
span.fg(Color.red).bold()
span.width()             // usize
span.render(area, buf)   // u16 chars written

// Line
Line.raw("hello world")
Line.styled("hello", style)
Line.fromSpans(&[_]Span{ span1, span2 })
line.centered()
line.rightAligned()
line.leftAligned()
line.fg(Color.blue).bold()
line.width()
line.render(area, buf)

// Text
Text.fromLine(line)
Text.fromLines(&[_]Line{ line1, line2 })
text.centered()
text.width()             // max width of lines
text.height()            // number of lines
text.render(area, buf)

Terminal

Terminal (src/terminal.zig)

Interfaz principal para aplicaciones TUI.

// Initialization
var term = try Terminal.init(allocator);
defer term.deinit();

// Properties
term.area()              // Rect
term.buffer()            // *Buffer

// Drawing
try term.draw(render_fn);                    // fn(Rect, *Buffer) void
try term.drawWithContext(ctx, render_fn);    // fn(T, Rect, *Buffer) void
try term.clear();

// Resize
term.enableAutoResize()
term.disableAutoResize()
term.getSize()           // Size { width, height }
try term.checkAndHandleResize()  // bool
term.isResizePending()   // bool
try term.resize(width, height)

// Events
try term.pollEvent(timeout_ms)  // ?Event (null = timeout)
try term.readEvent()            // Event (blocking)

// Mouse
try term.enableMouseCapture()
try term.disableMouseCapture()

// Focus
try term.enableFocusChange()
try term.disableFocusChange()

// Paste
try term.enableBracketedPaste()
try term.disableBracketedPaste()

// Cursor
try term.showCursor()
try term.hideCursor()
try term.setCursorPosition(col, row)

Layout System

Layout (src/layout.zig)

Sistema de layout para dividir areas.

Type Description
Layout Divisor de areas
Constraint Restriccion de tamano
Direction horizontal, vertical
Flex Layout CSS-like
JustifyContent start, end, center, space_between, space_around, space_evenly
AlignItems stretch, start, end, center
SplitResult Resultado con hasta 16 Rects
// Basic Layout
const result = Layout.vertical(&.{
    Constraint.length(3),      // 3 rows exactas
    Constraint.min(0),         // resto del espacio
}).split(area);

const header = result.get(0);  // Rect
const content = result.get(1); // Rect

// Constraint types
Constraint.length(10)      // exactly 10 cells
Constraint.min(5)          // at least 5 cells
Constraint.max(20)         // at most 20 cells
Constraint.percentage(50)  // 50% of space
Constraint.ratio(1, 3)     // 1/3 of space
Constraint.fill()          // fill remaining (= min(0))

// Ratio helpers
Constraint.half()          // 1/2
Constraint.third()         // 1/3
Constraint.twoThirds()     // 2/3
Constraint.quarter()       // 1/4
Constraint.threeQuarters() // 3/4
Constraint.fifth()         // 1/5
Constraint.goldenLarge()   // ~61.8%
Constraint.goldenSmall()   // ~38.2%
Constraint.prop(2, 5)      // 2 parts of 5

// Layout with margin
Layout.vertical(&constraints).withMargin(2)

// Flex layout (CSS-like)
const flex = Flex.horizontal()
    .setJustify(.center)
    .setAlign(.stretch)
    .setGap(2)
    .setMargin(1)
    .items(&.{ 20, 30, 20 });
const result = flex.split(area);

// Helper functions
centerRect(outer, width, height)      // Rect centered
alignBottom(outer, height)            // Rect at bottom
alignRight(outer, width)              // Rect at right
alignBottomRight(outer, width, height)

Widgets

Widget Index

Widget File Description
Block widgets/block.zig Container con bordes y titulos
Paragraph widgets/paragraph.zig Texto con wrapping
List widgets/list.zig Lista seleccionable
Table widgets/table.zig Tabla multi-columna
Gauge widgets/gauge.zig Barra de progreso
LineGauge widgets/gauge.zig Progreso en linea
Tabs widgets/tabs.zig Navegacion por tabs
Sparkline widgets/sparkline.zig Mini graficos
Scrollbar widgets/scrollbar.zig Indicador de scroll
BarChart widgets/barchart.zig Graficos de barras
Canvas widgets/canvas.zig Dibujo libre
Chart widgets/chart.zig Graficos con ejes
Calendar widgets/calendar.zig Calendario mensual
Clear widgets/clear.zig Limpiar area
Input widgets/input.zig Campo de texto
TextArea widgets/textarea.zig Editor multi-linea
Popup widgets/popup.zig Ventana emergente
Modal widgets/popup.zig Dialogo modal
Menu widgets/menu.zig Menu desplegable
MenuBar widgets/menu.zig Barra de menu
ContextMenu widgets/menu.zig Menu contextual
Tooltip widgets/tooltip.zig Tooltips
Tree widgets/tree.zig Vista de arbol
FilePicker widgets/filepicker.zig Selector de archivos
ScrollView widgets/scroll.zig Vista con scroll
VirtualList widgets/scroll.zig Lista virtualizada
Panel widgets/panel.zig Panel basico
TabbedPanel widgets/panel.zig Panel con tabs
Checkbox widgets/checkbox.zig Checkbox
RadioGroup widgets/checkbox.zig Radio buttons
Select widgets/select.zig Dropdown select
MultiSelect widgets/select.zig Multi-select
Slider widgets/slider.zig Slider de valor
RangeSlider widgets/slider.zig Slider de rango
StatusBar widgets/statusbar.zig Barra de estado
Toast widgets/statusbar.zig Notificaciones toast
Spinner widgets/spinner.zig Indicador de carga
Help widgets/help.zig Panel de keybindings
Viewport widgets/viewport.zig Scroll generico
Progress widgets/progress.zig Progreso con ETA
Markdown widgets/markdown.zig Renderizado markdown
DirectoryTree widgets/dirtree.zig Navegador de archivos
SyntaxHighlighter widgets/syntax.zig Resaltado de codigo
Logo widgets/logo.zig Logo ASCII art

Block

const block = zcatui.widgets.Block.default()
    .title("Title")
    .titleBottom("Footer")
    .titleAlignment(.center)
    .borders(.all)              // .none, .top, .bottom, .left, .right, .all
    .borderType(.rounded)       // .plain, .rounded, .double, .thick
    .borderStyle(style)
    .style(style);

block.render(area, buf);
const inner = block.inner(area);  // area inside borders

Paragraph

const para = zcatui.widgets.Paragraph.init(text)
    .block(block)
    .style(style)
    .alignment(.center)
    .wrap(.{ .trim = true });   // word wrapping

para.render(area, buf);

List

const items = [_]zcatui.widgets.ListItem{
    zcatui.widgets.ListItem.init("Item 1"),
    zcatui.widgets.ListItem.init("Item 2").style(style),
};

var state = zcatui.widgets.ListState{};
state.select(0);

const list = zcatui.widgets.List.init(&items)
    .block(block)
    .highlightStyle(style)
    .highlightSymbol("> ");

list.renderStateful(area, buf, &state);

// State methods
state.selected()         // ?usize
state.select(index)
state.selectNext()
state.selectPrevious()
state.selectFirst()
state.selectLast()

Table

const rows = [_]zcatui.widgets.TableRow{
    zcatui.widgets.TableRow.init(&.{
        zcatui.widgets.TableCell.init("Cell 1"),
        zcatui.widgets.TableCell.init("Cell 2"),
    }),
};

var state = zcatui.widgets.TableState{};

const table = zcatui.widgets.Table.init(&rows)
    .block(block)
    .header(header_row)
    .widths(&.{ Constraint.percentage(50), Constraint.percentage(50) })
    .highlightStyle(style)
    .highlightSymbol("> ");

table.renderStateful(area, buf, &state);

Gauge / LineGauge

// Full gauge
const gauge = zcatui.widgets.Gauge.default()
    .ratio(0.5)              // 0.0 - 1.0
    .percent(50)             // alternative: 0-100
    .label("50%")
    .gaugeStyle(style);
gauge.render(area, buf);

// Line gauge (single line)
const line_gauge = zcatui.widgets.LineGauge.default()
    .ratio(0.75)
    .lineSet(.thick)         // .normal, .thick
    .filledStyle(style)
    .unfilledStyle(style);
line_gauge.render(area, buf);

Input

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

const input = zcatui.widgets.Input.default()
    .placeholder("Enter text...")
    .style(style)
    .cursorStyle(style);

input.renderStateful(area, buf, &state);

// State methods
state.insert(char)
state.deleteBack()
state.deleteForward()
state.moveCursorLeft()
state.moveCursorRight()
state.moveCursorStart()
state.moveCursorEnd()
state.getText()          // []const u8
state.clear()

Popup / Modal

// Popup (positioned)
const popup = zcatui.widgets.Popup.init()
    .title("Popup")
    .content("Content here")
    .percentWidth(50)
    .percentHeight(30);
popup.render(area, buf);

// Modal dialog
const modal = zcatui.widgets.Modal.init()
    .title("Confirm")
    .message("Are you sure?")
    .buttons(&.{
        zcatui.widgets.ModalButton.init("Yes", .confirm),
        zcatui.widgets.ModalButton.init("No", .cancel),
    });
modal.render(area, buf);

// Pre-built dialogs
zcatui.widgets.confirmDialog("Title", "Message")
zcatui.widgets.alertDialog("Title", "Message")
zcatui.widgets.yesNoCancelDialog("Title", "Message")

Spinner

const spinner = zcatui.widgets.Spinner.init()
    .spinnerStyle(.dots)     // .dots, .line, .arc, .box, .bounce, etc (17 styles)
    .label("Loading...")
    .style(style);
spinner.render(area, buf, frame_count);  // frame_count for animation

Progress

const progress = zcatui.widgets.Progress.init()
    .ratio(0.5)
    .format(.percentage)     // .percentage, .ratio, .bytes, .eta
    .showEta(true)
    .showSpeed(true)
    .style(style);
progress.render(area, buf);

Markdown

const md = zcatui.widgets.Markdown.init(
    \\# Title
    \\
    \\Some **bold** and *italic* text.
    \\
    \\- List item 1
    \\- List item 2
)
    .theme(.default);        // .default, .github, .dracula

md.render(area, buf);

SyntaxHighlighter

const highlighter = zcatui.widgets.SyntaxHighlighter.init(code)
    .language(.zig)          // .zig, .rust, .python, .javascript, etc
    .theme(.monokai)         // .monokai, .dracula, .github
    .showLineNumbers(true);

highlighter.render(area, buf);

DirectoryTree

var tree = try zcatui.widgets.DirectoryTree.init(allocator, "/path/to/dir");
defer tree.deinit();

tree.toggleHidden();         // show/hide hidden files
tree.expand();
tree.collapse();
tree.selectNext();
tree.selectPrev();
tree.getSelectedPath()       // ?[]const u8

tree.render(area, buf);
const logo = zcatui.widgets.Logo.init()
    .text(zcatui.widgets.predefined_logos.zcatui)
    .style(style)
    .animation(.pulse)       // .none, .pulse, .wave, .rainbow
    .alignment(.center);

logo.render(area, buf, frame_count);

Events

Event Types (src/event.zig)

const Event = union(enum) {
    key: KeyEvent,
    mouse: MouseEvent,
    resize: ResizeEvent,
    focus_gained,
    focus_lost,
    paste: []const u8,
};

KeyEvent

// Handling
switch (event) {
    .key => |key| {
        // Check specific key
        if (key.code == .esc) return;
        if (key.code == .enter) submit();
        if (key.code == .{ .char = 'q' }) quit();
        if (key.code == .{ .f = 1 }) showHelp();

        // Check modifiers
        if (key.isCtrl() and key.getChar() == 'c') quit();
        if (key.isAlt()) handleAlt(key);

        // Get character
        if (key.getChar()) |c| {
            insertChar(c);
        }
    },
}

// KeyCode variants
.char: u21          // Unicode character
.f: u8              // F1-F12
.backspace, .enter, .tab, .backtab
.left, .right, .up, .down
.home, .end, .page_up, .page_down
.insert, .delete
.esc

// KeyModifiers
key.modifiers.ctrl
key.modifiers.alt
key.modifiers.shift
key.modifiers.super

MouseEvent

switch (event) {
    .mouse => |mouse| {
        if (mouse.kind == .down and mouse.button == .left) {
            handleClick(mouse.column, mouse.row);
        }
        if (mouse.kind == .scroll_up) scrollUp();
        if (mouse.kind == .scroll_down) scrollDown();
        if (mouse.kind == .drag) handleDrag(mouse);
    },
}

// MouseEventKind
.down, .up, .drag, .moved
.scroll_down, .scroll_up, .scroll_left, .scroll_right

// MouseButton
.left, .right, .middle, .none

Event Reader (src/event/reader.zig)

var reader = zcatui.EventReader.init();

// Poll with timeout (non-blocking)
if (try reader.poll(100)) |event| {
    // handle event
}

// Read blocking
const event = try reader.read();

Styling

Color Examples

// ANSI 16 colors
Color.black, Color.red, Color.green, Color.yellow
Color.blue, Color.magenta, Color.cyan, Color.white

// 256 palette
Color.indexed(196)   // bright red
Color.indexed(46)    // bright green
Color.indexed(236)   // dark gray

// True color (24-bit)
Color.rgb(255, 128, 0)   // orange
Color.rgb(30, 30, 30)    // dark background

Style Composition

// Builder pattern
const title_style = Style{}
    .fg(Color.yellow)
    .bold();

const error_style = Style{}
    .fg(Color.red)
    .bg(Color.black)
    .bold();

const selected = Style{}
    .fg(Color.white)
    .bg(Color.blue)
    .reversed();

// Patching styles
const combined = base_style.patch(overlay_style);

Animation

Animation System (src/animation.zig)

// Basic animation
var anim = zcatui.Animation.init(0, 100, 1000);  // from, to, duration_ms
anim.easing = zcatui.Easing.easeInOut;

while (!anim.isComplete()) {
    const value = anim.getValue();  // current interpolated value
    render(value);
    anim.advance(delta_ms);
}

// Easing functions
zcatui.Easing.linear(t)
zcatui.Easing.easeIn(t)
zcatui.Easing.easeOut(t)
zcatui.Easing.easeInOut(t)
zcatui.Easing.easeInCubic(t)
zcatui.Easing.easeOutCubic(t)
zcatui.Easing.easeInOutCubic(t)
zcatui.Easing.easeInExpo(t)
zcatui.Easing.easeOutExpo(t)
zcatui.Easing.easeOutBounce(t)

// Timer
var timer = zcatui.Timer.init(1000);  // 1000ms
if (timer.tick(delta_ms)) {
    // Timer fired
}
timer.reset();

Focus Management

Focus System (src/focus.zig)

// FocusRing - manages focus within widget group
var ring = zcatui.FocusRing{};
ring.add(widget1.focusable());
ring.add(widget2.focusable());

ring.focusNext();
ring.focusPrev();
ring.focusFirst();
ring.focusLast();

if (ring.getFocused()) |focused| {
    // render focused widget differently
}

// FocusManager - global focus management
var manager = zcatui.FocusManager.init(allocator);
defer manager.deinit();

manager.register("input1", input.focusable());
manager.setFocus("input1");
manager.moveFocus(.next);
manager.moveFocus(.prev);

// Focusable interface
pub const Focusable = struct {
    ptr: *anyopaque,
    vtable: *const VTable,

    pub const VTable = struct {
        onFocusChange: ?*const fn (*anyopaque, FocusEvent) void,
        canFocus: *const fn (*anyopaque) bool,
        getId: *const fn (*anyopaque) []const u8,
        getOrder: ?*const fn (*anyopaque) i32,
        getGroup: ?*const fn (*anyopaque) ?[]const u8,
    };
};

// FocusDirection
.next, .prev, .up, .down, .left, .right

// FocusEvent
.gained, .lost

Themes

Theme System (src/theme.zig)

// Built-in themes
const theme = zcatui.Theme.default;
const theme = zcatui.Theme.dark;
const theme = zcatui.Theme.light;
const theme = zcatui.Theme.nord;
const theme = zcatui.Theme.dracula;
const theme = zcatui.Theme.solarized_dark;
const theme = zcatui.Theme.solarized_light;
const theme = zcatui.Theme.monokai;
const theme = zcatui.Theme.gruvbox;
const theme = zcatui.Theme.one_dark;

// Theme colors
theme.background
theme.foreground
theme.primary
theme.secondary
theme.success
theme.warning
theme.error_color
theme.info
theme.border
theme.border_focused
theme.selection_bg
theme.selection_fg

// Theme styles (return Style)
theme.default()
theme.primaryStyle()
theme.secondaryStyle()
theme.successStyle()
theme.warningStyle()
theme.errorStyle()
theme.infoStyle()
theme.disabledStyle()
theme.borderStyle()
theme.borderFocusedStyle()
theme.selectionStyle()
theme.highlightStyle()
theme.surfaceStyle()
theme.statusBarStyle()

Theme Hot-Reload (src/theme_loader.zig)

var loader = zcatui.ThemeLoader.init(allocator);
defer loader.deinit();

// Load from file
const theme = try loader.loadFromFile("theme.json");

// Watch for changes
var watcher = try zcatui.ThemeWatcher.init(allocator, "theme.json");
defer watcher.deinit();

if (watcher.hasChanged()) {
    theme = try loader.reload();
}

// Export theme
try zcatui.exportTheme(theme, "theme.json");

Utilities

Clipboard (src/clipboard.zig)

// Copy to clipboard (OSC 52)
try zcatui.Clipboard.copy(writer, "text to copy");

// Selection types
zcatui.ClipboardSelection.clipboard  // system clipboard
zcatui.ClipboardSelection.primary    // X11 primary
zcatui.ClipboardSelection.secondary  // X11 secondary
// Create clickable link (OSC 8)
const link = zcatui.Hyperlink.init("Click here", "https://example.com");
link.render(area, buf);

Notifications (src/notification.zig)

// Send desktop notification (OSC 9/777)
try zcatui.Notification.send(writer, "Title", "Body");

Images (src/image.zig)

// Kitty protocol
try zcatui.Kitty.display(writer, image_data, options);

// iTerm2 protocol
try zcatui.Iterm2.display(writer, image_data, options);

// Options
const options = zcatui.ImageOptions{
    .width = 40,
    .height = 20,
    .format = .png,
};

Unicode (src/unicode.zig)

zcatui.charWidth(codepoint)          // u2 (0, 1, or 2)
zcatui.stringWidth("hello")          // usize
zcatui.truncateToWidth(str, max)     // []const u8

Terminal Capabilities (src/termcap.zig)

const caps = zcatui.detectCapabilities();

caps.color_support    // .none, .ansi16, .ansi256, .truecolor
caps.unicode          // bool
caps.mouse            // bool
caps.bracketed_paste  // bool
caps.kitty_keyboard   // bool
caps.sixel            // bool
caps.kitty_graphics   // bool
caps.iterm2_images    // bool

Lazy Rendering (src/lazy.zig)

// Render cache
var cache = zcatui.RenderCache.init(allocator);
defer cache.deinit();

if (cache.isValid(key)) {
    // use cached
} else {
    // render and cache
    cache.store(key, rendered);
}

// Throttle
var throttle = zcatui.Throttle.init(16);  // 16ms = ~60fps
if (throttle.shouldRun()) {
    render();
}

// Debounce
var debounce = zcatui.Debounce.init(100);  // 100ms delay
debounce.trigger();
if (debounce.isReady()) {
    execute();
}

Serialization (src/serialize.zig)

// State snapshot
var snapshot = zcatui.StateSnapshot.init(allocator);
defer snapshot.deinit();
snapshot.save("key", value);
const restored = snapshot.load("key", T);

// Undo stack
var undo = zcatui.UndoStack.init(allocator);
defer undo.deinit();
undo.push(state);
if (undo.undo()) |prev| { state = prev; }
if (undo.redo()) |next| { state = next; }

// JSON export
const json = try zcatui.toJson(allocator, value);
defer allocator.free(json);

Accessibility (src/accessibility.zig)

// Accessible info
const info = zcatui.AccessibleInfo{
    .role = .button,
    .label = "Submit",
    .description = "Submit the form",
};

// Announcer for screen readers
var announcer = zcatui.Announcer.init();
announcer.announce("Form submitted successfully");

// Check preferences
if (zcatui.prefersReducedMotion()) {
    // disable animations
}
if (zcatui.prefersHighContrast()) {
    theme = zcatui.high_contrast_theme;
}

// Skip links
var skip = zcatui.SkipLinks.init();
skip.add("main", "Skip to main content");

v2.2 Features

Resize Handler (src/resize.zig)

// Automatic (recommended)
term.enableAutoResize();
// Resize is handled automatically in draw()

// Manual
var handler = zcatui.ResizeHandler.init();
defer handler.deinit();

if (handler.hasResized()) {
    const size = handler.getLastKnownSize();
    try term.resize(size.width, size.height);
}

// Check pending
if (zcatui.resize.isResizePending()) {
    // handle resize
}

Drag & Drop (src/drag.zig)

// Drag state
var drag = zcatui.DragState{};

// On mouse down
drag.start(.resize, mouse.column, mouse.row);

// On mouse move
drag.update(mouse.column, mouse.row);

// Get delta
const dx = drag.deltaX();  // i32
const dy = drag.deltaY();  // i32

// On mouse up
drag.stop();

// Splitter panel
var splitter = zcatui.Splitter{
    .direction = .vertical,
    .position = 50,  // percentage
};

const areas = splitter.split(area);
// areas.first, areas.second, areas.handle

// Adjust on drag
splitter.adjustPosition(area, delta);

Debug Overlay (src/debug.zig)

var debug = zcatui.DebugOverlay.init();
debug.setEnabled(true);
debug.setFlags(.{
    .show_fps = true,
    .show_render_time = true,
    .show_boundaries = true,
    .show_mouse = true,
});

// In render loop
debug.beginFrame();
// ... render ...
debug.endFrame();
debug.render(area, buf);

// Log events
debug.logEvent("Button clicked: {s}", .{button_id});

// Get metrics
debug.current_fps      // f32
debug.getFrameTimeMs() // f32
debug.widget_count     // u32

// Global debug
zcatui.debug.toggleDebug();
zcatui.debug.isDebugEnabled();

Profiler (src/profile.zig)

var profiler = zcatui.Profiler.init();

// Time a section
profiler.begin("render");
// ... code ...
profiler.end("render");

// Get stats
if (profiler.getStats("render")) |stats| {
    stats.avg_ns    // average time
    stats.min_ns    // minimum time
    stats.max_ns    // maximum time
    stats.count     // call count
}

// Scoped timer (RAII-style)
{
    var timer = zcatui.ScopedTimer.start(&profiler, "section");
    defer timer.stop();
    // ... code ...
}

// Reset
profiler.reset();

Diagnostic Messages (src/diagnostic.zig)

// Create diagnostic
const diag = zcatui.Diagnostic.err("INVALID VALUE", "Value must be positive")
    .withSnippet(.{
        .lines = &.{ "let x = -5;", "    ^^^^" },
        .start_line = 10,
        .highlight_line = 0,
        .highlight_col = 8,
        .highlight_len = 2,
    })
    .withHint("Use a positive number instead")
    .withSeeAlso("https://docs.example.com/values");

// Render to buffer
diag.render(area, buf);

// Format as string
const text = try diag.format(allocator);
defer allocator.free(text);

// Severity levels
zcatui.Severity.hint
zcatui.Severity.warning
zcatui.Severity.@"error"

// Pre-built diagnostics
zcatui.diagnostic.invalidPercentage(150)
zcatui.diagnostic.emptyConstraints()
zcatui.diagnostic.widgetOutOfBounds("Button")
zcatui.diagnostic.invalidColor("red", 300)

Sixel Graphics (src/sixel.zig)

var encoder = zcatui.SixelEncoder.init(allocator);
defer encoder.deinit();

// Encode image
const pixels: []const zcatui.Pixel = // ...
const sixel_data = try encoder.encode(pixels, width, height);
defer allocator.free(sixel_data);

// Write to terminal
try writer.writeAll(sixel_data);

Async Event Loop (src/async_loop.zig)

var loop = try zcatui.AsyncLoop.init(allocator);
defer loop.deinit();

// Add stdin
try loop.addStdin();

// Add timer (100ms interval)
const timer_id = try loop.addTimer(100);

// Add custom fd
try loop.addFd(fd, true, false);  // readable, writable

// Event loop
while (running) {
    const events = try loop.wait(1000);  // 1s timeout
    for (events) |event| {
        switch (event.source) {
            .stdin => handleInput(),
            .timer => |id| if (id == timer_id) animate(),
            .fd => |f| handleFd(f),
            .signal => |sig| handleSignal(sig),
        }
    }
}

// Remove timer
loop.removeTimer(timer_id);

// Ticker helper
var ticker = try zcatui.Ticker.init(&loop, 16);  // 16ms = ~60fps
defer ticker.deinit();

Shortcuts (src/shortcuts.zig)

var shortcuts = zcatui.ShortcutMap.init(allocator);
defer shortcuts.deinit();

// Register shortcuts
try shortcuts.register(.{
    .key = .{ .char = 's' },
    .modifiers = .{ .ctrl = true },
    .action = .save,
    .description = "Save file",
});

// Match event
if (shortcuts.match(key_event)) |action| {
    switch (action) {
        .save => saveFile(),
        .quit => quit(),
        // ...
    }
}

// Context-aware shortcuts
var ctx = zcatui.ShortcutContext.init(allocator);
ctx.push("editor");  // enter editor context
// shortcuts for editor...
ctx.pop();  // exit context

Widget Composition (src/compose.zig)

// Vertical stack
const areas = zcatui.vstack(area, &.{
    Constraint.length(3),
    Constraint.fill(),
    Constraint.length(1),
});

// Horizontal stack
const cols = zcatui.hstack(area, &.{
    Constraint.percentage(30),
    Constraint.fill(),
});

// Splits
const split = zcatui.splitV(area, 50);  // 50%
// split.first, split.second

const split3 = zcatui.splitV3(area, 3, 1);  // header, footer sizes
// split3.top, split3.middle, split3.bottom

// Sizing
const sized = zcatui.sized(area, 40, 10);  // width, height (centered)

// Flex children
const child = zcatui.flexChild(2);  // flex: 2
const filler = zcatui.fillChild();  // flex: 1 (fill remaining)
const space = zcatui.spacer(5);     // fixed 5 cells

File Index

File Description
src/root.zig Entry point, re-exports
src/buffer.zig Buffer, Cell, Rect, Symbol
src/style.zig Color, Style, Modifier
src/text.zig Span, Line, Text
src/layout.zig Layout, Constraint, Flex
src/terminal.zig Terminal interface
src/event.zig Event types
src/event/reader.zig EventReader
src/event/parse.zig Escape sequence parser
src/animation.zig Animation, Easing, Timer
src/focus.zig FocusRing, FocusManager
src/theme.zig Theme definitions
src/theme_loader.zig Theme hot-reload
src/cursor.zig Cursor control
src/clipboard.zig OSC 52 clipboard
src/hyperlink.zig OSC 8 hyperlinks
src/notification.zig OSC 9/777 notifications
src/image.zig Kitty/iTerm2 images
src/unicode.zig Unicode width
src/termcap.zig Terminal capabilities
src/lazy.zig Render cache, throttle
src/testing.zig Widget testing framework
src/serialize.zig JSON, undo/redo
src/accessibility.zig A11y support
src/resize.zig SIGWINCH handler
src/drag.zig Drag state, Splitter
src/debug.zig Debug overlay
src/profile.zig Performance profiler
src/diagnostic.zig Elm-style errors
src/sixel.zig Sixel encoding
src/async_loop.zig Async epoll loop
src/shortcuts.zig Shortcut registry
src/compose.zig Widget composition
src/backend/backend.zig ANSI backend
src/symbols/*.zig Unicode symbols
src/widgets/*.zig All widgets

Examples

Los ejemplos estan en examples/:

zig build hello          # Hello World basico
zig build events-demo    # Manejo de eventos
zig build list-demo      # Lista interactiva
zig build table-demo     # Tabla con datos
zig build dashboard      # Dashboard completo
zig build input-demo     # Campos de entrada
zig build animation-demo # Animaciones
zig build clipboard-demo # Clipboard
zig build menu-demo      # Menus
zig build form-demo      # Formularios
zig build panel-demo     # Paneles
zig build resize-demo    # Manejo resize
zig build splitter-demo  # Paneles redimensionables
zig build dirtree-demo   # Navegador archivos
zig build spinner-demo   # Spinners
zig build progress-demo  # Barras progreso
zig build markdown-demo  # Markdown
zig build syntax-demo    # Syntax highlighting
zig build help-demo      # Panel de ayuda
zig build viewport-demo  # Scroll viewport

Version

  • zcatui v2.2
  • Zig 0.15.2
  • 70+ source files
  • 35 widgets
  • 186+ tests
  • 20 demos

Generated 2025-12-08