zcatui/examples/help_demo.zig
reugenio 7abc87a4f5 feat: zcatui v2.2 - Complete feature set with 13 new modules
New modules (13):
- src/resize.zig: SIGWINCH terminal resize detection
- src/drag.zig: Mouse drag state and Splitter panels
- src/diagnostic.zig: Elm-style error messages with code snippets
- src/debug.zig: Debug overlay (FPS, timing, widget count)
- src/profile.zig: Performance profiling with scoped timers
- src/sixel.zig: Sixel graphics encoding for terminal images
- src/async_loop.zig: epoll-based async event loop with timers
- src/compose.zig: Widget composition utilities
- src/shortcuts.zig: Keyboard shortcut registry
- src/widgets/logo.zig: ASCII art logo widget

Enhanced modules:
- src/layout.zig: Added Constraint.ratio(num, denom)
- src/terminal.zig: Integrated resize handling
- src/root.zig: Re-exports all new modules

New examples (9):
- resize_demo, splitter_demo, dirtree_demo
- help_demo, markdown_demo, progress_demo
- spinner_demo, syntax_demo, viewport_demo

Package manager:
- build.zig.zon: Zig package manager support

Stats: 60+ source files, 186+ tests, 20 executables

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

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

134 lines
4.6 KiB
Zig

//! Help Widget Demo - Shows keybinding help in different modes
//!
//! Run with: zig build help-demo
const std = @import("std");
const zcatui = @import("zcatui");
const Terminal = zcatui.Terminal;
const Rect = zcatui.Rect;
const Buffer = zcatui.Buffer;
const Style = zcatui.Style;
const Color = zcatui.Color;
const Block = zcatui.widgets.Block;
const Borders = zcatui.widgets.Borders;
const Help = zcatui.widgets.Help;
const KeyBinding = zcatui.widgets.KeyBinding;
const HelpMode = zcatui.widgets.HelpMode;
const bindings = [_]KeyBinding{
.{ .key = "q", .description = "Quit", .group = "General" },
.{ .key = "?", .description = "Toggle help", .group = "General" },
.{ .key = "up/k", .description = "Move up", .group = "Navigation" },
.{ .key = "down/j", .description = "Move down", .group = "Navigation" },
.{ .key = "left/h", .description = "Move left", .group = "Navigation" },
.{ .key = "right/l", .description = "Move right", .group = "Navigation" },
.{ .key = "PgUp", .description = "Page up", .group = "Navigation" },
.{ .key = "PgDn", .description = "Page down", .group = "Navigation" },
.{ .key = "Home", .description = "Go to start", .group = "Navigation" },
.{ .key = "End", .description = "Go to end", .group = "Navigation" },
.{ .key = "Enter", .description = "Select item", .group = "Actions" },
.{ .key = "Space", .description = "Toggle selection", .group = "Actions" },
.{ .key = "Tab", .description = "Next panel", .group = "Actions" },
.{ .key = "Ctrl+C", .description = "Copy", .group = "Edit" },
.{ .key = "Ctrl+V", .description = "Paste", .group = "Edit" },
.{ .key = "Ctrl+Z", .description = "Undo", .group = "Edit" },
};
const modes = [_]HelpMode{ .single_line, .compact, .multi_line, .full };
const mode_names = [_][]const u8{ "Single Line", "Compact", "Multi Line", "Full" };
/// State for the demo
const State = struct {
current_mode: usize = 0,
running: bool = true,
};
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();
var state = State{};
while (state.running) {
try term.drawWithContext(&state, render);
if (try term.pollEvent(100)) |event| {
switch (event) {
.key => |key| {
switch (key.code) {
.char => |c| {
if (c == 'q') state.running = false;
if (c >= '1' and c <= '4') {
state.current_mode = c - '1';
}
},
.left => {
if (state.current_mode > 0) state.current_mode -= 1;
},
.right => {
if (state.current_mode < modes.len - 1) state.current_mode += 1;
},
.esc => state.running = false,
else => {},
}
},
else => {},
}
}
}
}
fn render(state: *State, area: Rect, buf: *Buffer) void {
// Main border
const block = Block.init()
.title(" Help Widget Demo ")
.setBorders(Borders.all)
.borderStyle((Style{}).fg(Color.cyan));
block.render(area, buf);
// Mode tabs
var x: u16 = 2;
for (mode_names, 0..) |name, i| {
const style = if (i == state.current_mode)
(Style{}).fg(Color.black).bg(Color.cyan).bold()
else
(Style{}).fg(Color.white);
_ = buf.setString(x, 1, " ", style);
_ = buf.setString(x + 1, 1, name, style);
_ = buf.setString(x + 1 + @as(u16, @intCast(name.len)), 1, " ", style);
x += @as(u16, @intCast(name.len)) + 3;
}
// Help content area
const content_area = Rect.init(1, 3, area.width -| 2, area.height -| 5);
const help_block = Block.init()
.setBorders(Borders.all)
.title(" Keybindings ")
.borderStyle((Style{}).fg(Color.rgb(80, 80, 80)));
help_block.render(content_area, buf);
const inner = Rect.init(2, 4, area.width -| 4, area.height -| 7);
// Help widget
const key_style = (Style{}).fg(Color.yellow).bold();
const help = Help.init(&bindings)
.setMode(modes[state.current_mode])
.setKeyStyle(key_style);
help.render(inner, buf);
// Footer
_ = buf.setString(
2,
area.height -| 1,
"Press 1-4 or left/right to change mode, q to quit",
(Style{}).fg(Color.rgb(100, 100, 100)),
);
}