Widgets implementados (13): - Block, Paragraph, List, Table - Gauge, LineGauge, Tabs, Sparkline - Scrollbar, BarChart, Canvas, Chart - Calendar (Monthly), Clear Modulos: - src/text.zig: Span, Line, Text, Alignment - src/symbols/: line, border, block, bar, braille, half_block, scrollbar, marker - src/widgets/: todos los widgets con tests Documentacion: - docs/ARCHITECTURE.md: arquitectura tecnica - docs/WIDGETS.md: guia completa de widgets - docs/API.md: referencia rapida - CLAUDE.md: actualizado con estado v1.0 Tests: 103+ tests en widgets, todos pasan 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
644 lines
15 KiB
Markdown
644 lines
15 KiB
Markdown
# zcatui - API Reference
|
||
|
||
> Referencia rapida de la API publica de zcatui
|
||
|
||
## Importar la Libreria
|
||
|
||
```zig
|
||
const zcatui = @import("zcatui");
|
||
|
||
// Core types
|
||
const Color = zcatui.Color;
|
||
const Style = zcatui.Style;
|
||
const Modifier = zcatui.Modifier;
|
||
const Cell = zcatui.Cell;
|
||
const Buffer = zcatui.Buffer;
|
||
const Rect = zcatui.Rect;
|
||
const Span = zcatui.Span;
|
||
const Line = zcatui.Line;
|
||
const Text = zcatui.Text;
|
||
const Alignment = zcatui.Alignment;
|
||
|
||
// Layout
|
||
const Layout = zcatui.Layout;
|
||
const Constraint = zcatui.Constraint;
|
||
const Direction = zcatui.Direction;
|
||
|
||
// Terminal
|
||
const Terminal = zcatui.Terminal;
|
||
|
||
// Widgets
|
||
const widgets = zcatui.widgets;
|
||
const Block = widgets.Block;
|
||
const Paragraph = widgets.Paragraph;
|
||
const List = widgets.List;
|
||
const ListState = widgets.ListState;
|
||
// ... etc
|
||
```
|
||
|
||
---
|
||
|
||
## Core Types
|
||
|
||
### Color
|
||
|
||
```zig
|
||
pub const Color = union(enum) {
|
||
// Reset
|
||
reset,
|
||
|
||
// Basic 16 colors
|
||
black, red, green, yellow, blue, magenta, cyan, white,
|
||
light_black, light_red, light_green, light_yellow,
|
||
light_blue, light_magenta, light_cyan, light_white,
|
||
|
||
// 256 color palette
|
||
indexed: u8,
|
||
|
||
// True color (24-bit)
|
||
rgb: struct { r: u8, g: u8, b: u8 },
|
||
|
||
// Constructor helpers
|
||
pub fn indexed(n: u8) Color;
|
||
pub fn rgb(r: u8, g: u8, b: u8) Color;
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
const red = Color.red;
|
||
const gray = Color.indexed(240);
|
||
const custom = Color.rgb(255, 128, 0);
|
||
```
|
||
|
||
### Style
|
||
|
||
```zig
|
||
pub const Style = struct {
|
||
foreground: ?Color = null,
|
||
background: ?Color = null,
|
||
add_modifiers: Modifier = .{},
|
||
sub_modifiers: Modifier = .{},
|
||
|
||
pub const default: Style = .{};
|
||
|
||
// Fluent setters
|
||
pub fn fg(self: Style, color: Color) Style;
|
||
pub fn bg(self: Style, color: Color) Style;
|
||
pub fn bold(self: Style) Style;
|
||
pub fn dim(self: Style) Style;
|
||
pub fn italic(self: Style) Style;
|
||
pub fn underlined(self: Style) Style;
|
||
pub fn slow_blink(self: Style) Style;
|
||
pub fn rapid_blink(self: Style) Style;
|
||
pub fn reversed(self: Style) Style;
|
||
pub fn hidden(self: Style) Style;
|
||
pub fn crossed_out(self: Style) Style;
|
||
|
||
// Remove modifiers
|
||
pub fn notBold(self: Style) Style;
|
||
pub fn notDim(self: Style) Style;
|
||
// ... etc
|
||
|
||
// Combine styles
|
||
pub fn patch(self: Style, other: Style) Style;
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
const style1 = Style.default.fg(Color.red).bold();
|
||
const style2 = Style.default.bg(Color.blue).italic();
|
||
const combined = style1.patch(style2); // red fg, blue bg, bold+italic
|
||
```
|
||
|
||
### Modifier
|
||
|
||
```zig
|
||
pub const Modifier = packed struct {
|
||
bold: bool = false,
|
||
dim: bool = false,
|
||
italic: bool = false,
|
||
underlined: bool = false,
|
||
slow_blink: bool = false,
|
||
rapid_blink: bool = false,
|
||
reversed: bool = false,
|
||
hidden: bool = false,
|
||
crossed_out: bool = false,
|
||
|
||
pub const empty: Modifier = .{};
|
||
pub const all: Modifier = .{ .bold = true, ... };
|
||
|
||
pub fn contains(self: Modifier, other: Modifier) bool;
|
||
pub fn insert(self: Modifier, other: Modifier) Modifier;
|
||
pub fn remove(self: Modifier, other: Modifier) Modifier;
|
||
};
|
||
```
|
||
|
||
### Rect
|
||
|
||
```zig
|
||
pub const Rect = struct {
|
||
x: u16,
|
||
y: u16,
|
||
width: u16,
|
||
height: u16,
|
||
|
||
pub fn init(x: u16, y: u16, width: u16, height: u16) Rect;
|
||
|
||
// Getters
|
||
pub fn left(self: Rect) u16; // x
|
||
pub fn right(self: Rect) u16; // x + width
|
||
pub fn top(self: Rect) u16; // y
|
||
pub fn bottom(self: Rect) u16; // y + height
|
||
pub fn area(self: Rect) u32; // width * height
|
||
|
||
// Queries
|
||
pub fn isEmpty(self: Rect) bool;
|
||
pub fn contains(self: Rect, x: u16, y: u16) bool;
|
||
|
||
// Transformations
|
||
pub fn inner(self: Rect, margin: u16) Rect;
|
||
pub fn innerMargins(self: Rect, top: u16, right: u16, bottom: u16, left_: u16) Rect;
|
||
pub fn intersection(self: Rect, other: Rect) Rect;
|
||
pub fn union_(self: Rect, other: Rect) Rect;
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
const area = Rect.init(0, 0, 80, 24);
|
||
const inner = area.inner(1); // Rect.init(1, 1, 78, 22)
|
||
```
|
||
|
||
### Cell
|
||
|
||
```zig
|
||
pub const Cell = struct {
|
||
symbol: Symbol,
|
||
style: Style,
|
||
|
||
pub const default_val: Cell = .{ .symbol = Symbol.default_val, .style = Style.default };
|
||
|
||
pub fn reset(self: *Cell) void;
|
||
pub fn setChar(self: *Cell, ch: u21) void;
|
||
pub fn setSymbol(self: *Cell, symbol: []const u8) void;
|
||
pub fn setStyle(self: *Cell, style: Style) void;
|
||
};
|
||
|
||
pub const Symbol = struct {
|
||
data: [4]u8,
|
||
len: u3,
|
||
|
||
pub const default_val: Symbol; // " "
|
||
pub fn slice(self: Symbol) []const u8;
|
||
};
|
||
```
|
||
|
||
### Buffer
|
||
|
||
```zig
|
||
pub const Buffer = struct {
|
||
area: Rect,
|
||
cells: []Cell,
|
||
allocator: Allocator,
|
||
|
||
pub fn init(allocator: Allocator, area: Rect) !Buffer;
|
||
pub fn deinit(self: *Buffer) void;
|
||
pub fn empty(area: Rect) Buffer; // No allocation
|
||
|
||
// Cell access
|
||
pub fn getCell(self: *Buffer, x: u16, y: u16) ?*Cell;
|
||
pub fn index(self: Buffer, x: u16, y: u16) ?usize;
|
||
|
||
// Setting content
|
||
pub fn setString(self: *Buffer, x: u16, y: u16, text: []const u8, style: Style) u16;
|
||
pub fn setSpan(self: *Buffer, x: u16, y: u16, span: Span, width: u16) u16;
|
||
pub fn setLine(self: *Buffer, x: u16, y: u16, line: Line, width: u16) u16;
|
||
pub fn setStyle(self: *Buffer, area: Rect, style: Style) void;
|
||
|
||
// Filling
|
||
pub fn fill(self: *Buffer, cell: Cell) void;
|
||
pub fn fillArea(self: *Buffer, area: Rect, cell: Cell) void;
|
||
|
||
// Merging
|
||
pub fn merge(self: *Buffer, other: *const Buffer) void;
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
var buf = try Buffer.init(allocator, Rect.init(0, 0, 80, 24));
|
||
defer buf.deinit();
|
||
|
||
_ = buf.setString(10, 5, "Hello, World!", Style.default.fg(Color.green));
|
||
|
||
if (buf.getCell(10, 5)) |cell| {
|
||
cell.setStyle(Style.default.bold());
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Text Types
|
||
|
||
### Span
|
||
|
||
```zig
|
||
pub const Span = struct {
|
||
content: []const u8,
|
||
style: Style,
|
||
|
||
pub fn init(content: []const u8) Span;
|
||
pub fn raw(content: []const u8) Span;
|
||
pub fn styled(content: []const u8, style: Style) Span;
|
||
pub fn setStyle(self: Span, style: Style) Span;
|
||
pub fn width(self: Span) usize;
|
||
};
|
||
```
|
||
|
||
### Line
|
||
|
||
```zig
|
||
pub const Line = struct {
|
||
spans: []const Span,
|
||
alignment: Alignment,
|
||
|
||
pub fn init(spans: []const Span) Line;
|
||
pub fn raw(content: []const u8) Line;
|
||
pub fn styled(content: []const u8, style: Style) Line;
|
||
pub fn setStyle(self: Line, style: Style) Line;
|
||
pub fn setAlignment(self: Line, alignment: Alignment) Line;
|
||
pub fn width(self: Line) usize;
|
||
};
|
||
```
|
||
|
||
### Text
|
||
|
||
```zig
|
||
pub const Text = struct {
|
||
lines: []const Line,
|
||
alignment: Alignment,
|
||
|
||
pub fn init(lines: []const Line) Text;
|
||
pub fn raw(content: []const u8) Text;
|
||
pub fn styled(content: []const u8, style: Style) Text;
|
||
pub fn setStyle(self: Text, style: Style) Text;
|
||
pub fn setAlignment(self: Text, alignment: Alignment) Text;
|
||
pub fn width(self: Text) usize;
|
||
pub fn height(self: Text) usize;
|
||
};
|
||
```
|
||
|
||
### Alignment
|
||
|
||
```zig
|
||
pub const Alignment = enum {
|
||
left,
|
||
center,
|
||
right,
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
// Simple text
|
||
const span = Span.styled("Hello", Style.default.fg(Color.red));
|
||
const line = Line.raw("Simple line");
|
||
|
||
// Multi-span line
|
||
const multi_line = Line.init(&[_]Span{
|
||
Span.styled("Error: ", Style.default.fg(Color.red).bold()),
|
||
Span.raw("Something went wrong"),
|
||
});
|
||
|
||
// Multi-line text
|
||
const text = Text.raw("Line 1\nLine 2\nLine 3");
|
||
```
|
||
|
||
---
|
||
|
||
## Layout
|
||
|
||
### Layout
|
||
|
||
```zig
|
||
pub const Layout = struct {
|
||
direction: Direction,
|
||
constraints: []const Constraint,
|
||
|
||
pub fn horizontal(constraints: []const Constraint) Layout;
|
||
pub fn vertical(constraints: []const Constraint) Layout;
|
||
pub fn init(direction: Direction, constraints: []const Constraint) Layout;
|
||
|
||
pub fn split(self: Layout, area: Rect, result: []Rect) void;
|
||
};
|
||
```
|
||
|
||
### Constraint
|
||
|
||
```zig
|
||
pub 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 (0-100)
|
||
ratio: struct { num: u32, den: u32 },
|
||
fill: u16, // Fill remaining space (weight)
|
||
|
||
pub fn length(n: u16) Constraint;
|
||
pub fn min(n: u16) Constraint;
|
||
pub fn max(n: u16) Constraint;
|
||
pub fn percentage(n: u16) Constraint;
|
||
pub fn ratio(num: u32, den: u32) Constraint;
|
||
pub fn fill(weight: u16) Constraint;
|
||
};
|
||
```
|
||
|
||
### Direction
|
||
|
||
```zig
|
||
pub const Direction = enum {
|
||
horizontal,
|
||
vertical,
|
||
};
|
||
```
|
||
|
||
**Ejemplos:**
|
||
```zig
|
||
// Vertical layout: header (3 rows), content (rest), footer (1 row)
|
||
const layout = Layout.vertical(&[_]Constraint{
|
||
Constraint.length(3),
|
||
Constraint.min(0),
|
||
Constraint.length(1),
|
||
});
|
||
|
||
var chunks: [3]Rect = undefined;
|
||
layout.split(area, &chunks);
|
||
|
||
// Horizontal split: 30% | 70%
|
||
const h_layout = Layout.horizontal(&[_]Constraint{
|
||
Constraint.percentage(30),
|
||
Constraint.percentage(70),
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Symbols
|
||
|
||
### Line Set
|
||
|
||
```zig
|
||
pub const line = struct {
|
||
pub const Set = struct {
|
||
vertical: []const u8,
|
||
horizontal: []const u8,
|
||
top_right: []const u8,
|
||
top_left: []const u8,
|
||
bottom_right: []const u8,
|
||
bottom_left: []const u8,
|
||
vertical_left: []const u8,
|
||
vertical_right: []const u8,
|
||
horizontal_down: []const u8,
|
||
horizontal_up: []const u8,
|
||
cross: []const u8,
|
||
};
|
||
|
||
pub const NORMAL: Set; // ─│┌┐└┘
|
||
pub const ROUNDED: Set; // ─│╭╮╰╯
|
||
pub const DOUBLE: Set; // ═║╔╗╚╝
|
||
pub const THICK: Set; // ━┃┏┓┗┛
|
||
};
|
||
```
|
||
|
||
### Border Set
|
||
|
||
```zig
|
||
pub const border = struct {
|
||
pub const Set = struct {
|
||
top_left: []const u8,
|
||
top_right: []const u8,
|
||
bottom_left: []const u8,
|
||
bottom_right: []const u8,
|
||
horizontal: []const u8,
|
||
vertical: []const u8,
|
||
};
|
||
|
||
pub const PLAIN: Set;
|
||
pub const ROUNDED: Set;
|
||
pub const DOUBLE: Set;
|
||
pub const THICK: Set;
|
||
};
|
||
```
|
||
|
||
### Block Characters
|
||
|
||
```zig
|
||
pub const block = struct {
|
||
pub const FULL: []const u8 = "█";
|
||
pub const UPPER_HALF: []const u8 = "▀";
|
||
pub const LOWER_HALF: []const u8 = "▄";
|
||
pub const LEFT_HALF: []const u8 = "▌";
|
||
pub const RIGHT_HALF: []const u8 = "▐";
|
||
// ...
|
||
};
|
||
```
|
||
|
||
### Bar Characters
|
||
|
||
```zig
|
||
pub const bar = struct {
|
||
pub const Set = struct {
|
||
full: []const u8,
|
||
seven_eighths: []const u8,
|
||
three_quarters: []const u8,
|
||
five_eighths: []const u8,
|
||
half: []const u8,
|
||
three_eighths: []const u8,
|
||
one_quarter: []const u8,
|
||
one_eighth: []const u8,
|
||
empty: []const u8,
|
||
};
|
||
|
||
pub const NINE_LEVELS: Set;
|
||
pub const THREE_LEVELS: Set;
|
||
};
|
||
```
|
||
|
||
### Braille
|
||
|
||
```zig
|
||
pub const braille = struct {
|
||
pub const BLANK: []const u8 = "⠀"; // U+2800
|
||
|
||
// Bit positions for 2x4 grid:
|
||
// 0 3
|
||
// 1 4
|
||
// 2 5
|
||
// 6 7
|
||
|
||
pub const PATTERNS: [256][3]u8; // Pre-computed UTF-8 patterns
|
||
|
||
pub fn fromPattern(pattern: u8) []const u8;
|
||
};
|
||
```
|
||
|
||
### Marker
|
||
|
||
```zig
|
||
pub const Marker = enum {
|
||
dot,
|
||
block,
|
||
bar,
|
||
braille,
|
||
half_block,
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## Terminal
|
||
|
||
```zig
|
||
pub const Terminal = struct {
|
||
pub fn init(allocator: Allocator) !Terminal;
|
||
pub fn deinit(self: *Terminal) void;
|
||
|
||
pub fn size(self: Terminal) struct { width: u16, height: u16 };
|
||
pub fn area(self: Terminal) Rect;
|
||
|
||
pub fn draw(self: *Terminal, render_fn: fn(area: Rect, buf: *Buffer) void) !void;
|
||
pub fn clear(self: *Terminal) !void;
|
||
pub fn flush(self: *Terminal) !void;
|
||
|
||
pub fn hideCursor(self: *Terminal) !void;
|
||
pub fn showCursor(self: *Terminal) !void;
|
||
pub fn setCursorPosition(self: *Terminal, x: u16, y: u16) !void;
|
||
|
||
pub fn enterAlternateScreen(self: *Terminal) !void;
|
||
pub fn leaveAlternateScreen(self: *Terminal) !void;
|
||
|
||
pub fn enableRawMode(self: *Terminal) !void;
|
||
pub fn disableRawMode(self: *Terminal) !void;
|
||
};
|
||
```
|
||
|
||
**Ejemplo de uso:**
|
||
```zig
|
||
pub fn main() !void {
|
||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||
defer _ = gpa.deinit();
|
||
const allocator = gpa.allocator();
|
||
|
||
var term = try Terminal.init(allocator);
|
||
defer term.deinit();
|
||
|
||
try term.enterAlternateScreen();
|
||
defer term.leaveAlternateScreen() catch {};
|
||
|
||
try term.hideCursor();
|
||
defer term.showCursor() catch {};
|
||
|
||
try term.draw(struct {
|
||
pub fn render(area: Rect, buf: *Buffer) void {
|
||
const block = Block.bordered().title("Hello zcatui!");
|
||
block.render(area, buf);
|
||
}
|
||
}.render);
|
||
|
||
// Wait for input...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Widgets Quick Reference
|
||
|
||
| Widget | Constructor | Stateful | Key Methods |
|
||
|--------|------------|----------|-------------|
|
||
| Block | `Block.init()` | No | `title()`, `borders()`, `borderStyle()` |
|
||
| Paragraph | `Paragraph.init(text)` | No | `setWrap()`, `setAlignment()`, `setScroll()` |
|
||
| List | `List.init(items)` | Yes | `setHighlightStyle()`, `setHighlightSymbol()` |
|
||
| Table | `Table.init(rows, widths)` | Yes | `setHeader()`, `setHighlightStyle()` |
|
||
| Gauge | `Gauge.init()` | No | `setRatio()`, `setPercent()`, `setLabel()` |
|
||
| LineGauge | `LineGauge.init()` | No | `setRatio()`, `setFilledStyle()` |
|
||
| Tabs | `Tabs.init(titles)` | No | `select()`, `setDivider()` |
|
||
| Sparkline | `Sparkline.init()` | No | `setData()`, `setMax()` |
|
||
| Scrollbar | `Scrollbar.init(orientation)` | Yes | `setSymbols()`, `setStyle()` |
|
||
| BarChart | `BarChart.init()` | No | `setData()`, `setBarWidth()` |
|
||
| Canvas | `Canvas.init()` | No | `setXBounds()`, `setYBounds()`, `paint()` |
|
||
| Chart | `Chart.init(datasets)` | No | `setXAxis()`, `setYAxis()` |
|
||
| Monthly | `Monthly.init(date)` | No | `showMonthHeader()`, `showWeekdaysHeader()` |
|
||
| Clear | `Clear.init()` | No | (none) |
|
||
|
||
---
|
||
|
||
## Error Handling
|
||
|
||
zcatui usa el sistema de errores de Zig. Las funciones que pueden fallar retornan `!T`.
|
||
|
||
```zig
|
||
// Errores comunes
|
||
const TerminalError = error{
|
||
InitFailed,
|
||
WriteFailed,
|
||
FlushFailed,
|
||
};
|
||
|
||
const BufferError = error{
|
||
OutOfMemory,
|
||
};
|
||
|
||
// Manejo tipico
|
||
var term = Terminal.init(allocator) catch |err| {
|
||
std.debug.print("Failed to init terminal: {}\n", .{err});
|
||
return err;
|
||
};
|
||
defer term.deinit();
|
||
```
|
||
|
||
---
|
||
|
||
## Patterns
|
||
|
||
### Builder Pattern
|
||
|
||
```zig
|
||
const widget = SomeWidget.init()
|
||
.setOption1(value1)
|
||
.setOption2(value2)
|
||
.setBlock(Block.bordered());
|
||
```
|
||
|
||
### Stateful Rendering
|
||
|
||
```zig
|
||
var state = WidgetState.init();
|
||
|
||
// En el loop de renderizado:
|
||
widget.renderStateful(area, buf, &state);
|
||
|
||
// Actualizar estado basado en input:
|
||
state.selectNext(items.len);
|
||
```
|
||
|
||
### Layout Composition
|
||
|
||
```zig
|
||
const outer = Layout.vertical(&[_]Constraint{
|
||
Constraint.length(3),
|
||
Constraint.min(0),
|
||
});
|
||
|
||
var outer_chunks: [2]Rect = undefined;
|
||
outer.split(area, &outer_chunks);
|
||
|
||
const inner = Layout.horizontal(&[_]Constraint{
|
||
Constraint.percentage(50),
|
||
Constraint.percentage(50),
|
||
});
|
||
|
||
var inner_chunks: [2]Rect = undefined;
|
||
inner.split(outer_chunks[1], &inner_chunks);
|
||
```
|