TUI library para Zig, inspirada en ratatui
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .claude/commands | ||
| docs | ||
| examples | ||
| src | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| claude.md | ||
| README.md | ||
| VERIFIED_FEATURES.md | ||
| ZIG_VERSION_NOTES.md | ||
zcatui
A Terminal User Interface (TUI) library for Zig, inspired by ratatui.
zcatui = "zcat" + "ui" (a nod to ratatui and Zig's mascot)
Features
Core
- Immediate mode rendering with double buffering and diff-based updates
- Flexible layout system with constraints (Length, Min, Max, Percentage, Ratio)
- Rich styling with 16/256/RGB colors and modifiers (bold, italic, underline, etc.)
- Full event handling for keyboard and mouse input
- Cross-terminal compatibility via ANSI escape sequences
Widgets (30+)
| Category | Widgets |
|---|---|
| Basic | Block, Paragraph, List, Table, Tabs |
| Data | Gauge, LineGauge, Sparkline, BarChart, Chart, Canvas |
| Input | Input (text field), TextArea, Checkbox, RadioGroup, Select, Slider |
| Navigation | Menu, MenuBar, ContextMenu, Tree, FilePicker |
| Overlays | Popup, Modal, Tooltip, Toast |
| Layout | Panel, PanelSplit, TabbedPanel, DockingPanel, ScrollView, VirtualList |
| Utilities | Scrollbar, Calendar, StatusBar, Clear |
Terminal Extensions
- Clipboard (OSC 52) - Read/write system clipboard
- Hyperlinks (OSC 8) - Clickable links in terminal
- Notifications (OSC 9/777) - Desktop notifications
- Images (Kitty/iTerm2) - Display images in terminal
- Cursor control - Style, visibility, position
Advanced Features
- Animation system with easing functions
- Lazy rendering with caching and throttling
- Virtual scrolling for large datasets
- LEGO panel system for complex layouts
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();
// Main loop
while (true) {
try term.draw(render);
if (try term.pollEvent(100)) |event| {
if (event == .key) {
if (event.key.code == .char and event.key.code.char == 'q') {
break;
}
}
}
}
}
fn render(area: zcatui.Rect, buf: *zcatui.Buffer) void {
const block = zcatui.widgets.Block.init()
.title(" Hello zcatui! ")
.setBorders(zcatui.widgets.Borders.all)
.style(zcatui.Style.default.fg(zcatui.Color.cyan));
block.render(area, buf);
}
Installation
Add zcatui to your build.zig.zon:
.dependencies = .{
.zcatui = .{
.url = "https://git.reugenio.com/reugenio/zcatui/archive/main.tar.gz",
// Add hash after first build attempt
},
},
Then in build.zig:
const zcatui = b.dependency("zcatui", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zcatui", zcatui.module("zcatui"));
Examples
Run examples with:
zig build hello # Basic hello world
zig build events-demo # Keyboard/mouse events
zig build list-demo # List widget
zig build table-demo # Table widget
zig build dashboard # Dashboard with multiple widgets
zig build input-demo # Text input
zig build animation-demo # Animations
zig build menu-demo # Menus and modals
zig build form-demo # Form widgets
zig build panel-demo # Panel system
Widget Examples
Layout
const Layout = zcatui.Layout;
const Constraint = zcatui.Constraint;
// Split area vertically
const chunks = Layout.vertical(&.{
Constraint.length(3), // Fixed 3 rows
Constraint.percentage(50), // 50% of remaining
Constraint.min(5), // At least 5 rows
}).split(area);
// Split horizontally
const cols = Layout.horizontal(&.{
Constraint.ratio(1, 3), // 1/3 of width
Constraint.ratio(2, 3), // 2/3 of width
}).split(area);
Block with Borders
const Block = zcatui.widgets.Block;
const Borders = zcatui.widgets.Borders;
const block = Block.init()
.title(" My Panel ")
.setBorders(Borders.all)
.style(Style.default.fg(Color.cyan));
block.render(area, buf);
const inner = block.inner(area); // Get content area
List
const List = zcatui.widgets.List;
const ListItem = zcatui.widgets.ListItem;
const items = &[_]ListItem{
ListItem.init("Item 1"),
ListItem.init("Item 2").style(Style.default.fg(Color.green)),
ListItem.init("Item 3"),
};
var list = List.init(items)
.block(Block.init().title("List").setBorders(Borders.all))
.highlightStyle(Style.default.bg(Color.blue));
list.renderStateful(area, buf, &list_state);
Form Widgets
// Checkbox
const checkbox = Checkbox.init("Enable feature")
.setChecked(true)
.setFocused(is_focused);
checkbox.render(area, buf);
// Radio buttons
var radio = RadioGroup.init(&.{"Option A", "Option B", "Option C"})
.setSelected(1);
radio.render(area, buf);
// Dropdown select
var select = Select.init(&.{"Small", "Medium", "Large"})
.setPlaceholder("Choose size...");
select.render(area, buf);
// Slider
const slider = Slider.init(0, 100)
.setValue(50)
.setLabel("Volume");
slider.render(area, buf);
Charts
// Bar chart
const BarChart = zcatui.widgets.BarChart;
const chart = BarChart.init()
.data(&.{
.{ .label = "A", .value = 10 },
.{ .label = "B", .value = 20 },
.{ .label = "C", .value = 15 },
})
.barWidth(5);
chart.render(area, buf);
// Sparkline
const Sparkline = zcatui.widgets.Sparkline;
const sparkline = Sparkline.init(&.{1, 4, 2, 8, 5, 3, 9, 2});
sparkline.render(area, buf);
Popups and Modals
const Modal = zcatui.widgets.Modal;
const confirmDialog = zcatui.widgets.confirmDialog;
// Quick confirm dialog
const modal = confirmDialog("Confirm", &.{"Are you sure?"});
modal.render(area, buf);
// Handle button press
if (modal.getFocusedButton() == 0) {
// OK pressed
}
Toast Notifications
const ToastManager = zcatui.widgets.ToastManager;
var toasts = ToastManager.init();
// Show notifications
toasts.info("Information message");
toasts.success("Operation completed!");
toasts.warning("Warning!");
toasts.showError("Error occurred");
// In render loop
toasts.update();
toasts.render(area, buf);
Terminal Extensions
Clipboard
const Clipboard = zcatui.Clipboard;
// Write to clipboard
try Clipboard.write(writer, "Hello clipboard!");
// Read (async - response comes via terminal)
try Clipboard.requestRead(writer);
Hyperlinks
const Hyperlink = zcatui.Hyperlink;
const link = Hyperlink.init("https://example.com", "Click here");
try link.write(writer);
Notifications
const notification = zcatui.notification;
try notification.notify(writer, "Build complete!");
try notification.notifyWithTitle(writer, "zcatui", "Task finished");
Images
const image = zcatui.image;
// Display image (Kitty protocol)
try image.Kitty.displayFile(writer, "/path/to/image.png", .{
.width = 40,
.height = 20,
});
Architecture
┌─────────────┐ ┌────────┐ ┌──────────┐
│ Application │───▶│ Buffer │───▶│ Terminal │
│ (widgets) │ │ (diff) │ │ (output) │
└─────────────┘ └────────┘ └──────────┘
- Application renders widgets to a Buffer
- Buffer is compared (diff) with previous frame
- Only changes are sent to terminal (efficient)
Requirements
- Zig 0.15.x
- POSIX terminal (Linux, macOS) or Windows Terminal
- Terminal with ANSI escape sequence support
License
MIT
Credits
- Inspired by ratatui (Rust)
- Built with Zig