- 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>
32 KiB
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
- Quick Start
- Core Types
- Terminal
- Layout System
- Widgets
- Events
- Styling
- Animation
- Focus Management
- Themes
- Utilities
- 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);
Logo
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
Hyperlinks (src/hyperlink.zig)
// 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