Focus management system (src/focus.zig): - FocusRing for tab-order navigation within widget groups - FocusManager for managing multiple focus rings - Focusable interface with vtable pattern - Focus trapping for modals Theme system (src/theme.zig): - Theme struct with full color properties - Style builder methods (primaryStyle, errorStyle, etc.) - 10 predefined themes: dark, light, dracula, nord, gruvbox, solarized_dark, monokai, one_dark, tokyo_night, catppuccin Comprehensive test suite (src/tests/): - widget_tests.zig: Block, Gauge, Checkbox, RadioGroup, Select, Slider, StatusBar, Toast, Panel, TabbedPanel, Rect, Buffer, Style - theme_tests.zig: Theme system and predefined themes - layout_tests.zig: Layout constraints and splits - tests.zig: Test aggregator Bug fixes: - Fixed Zig 0.15 API compatibility in inline tests - style.fg -> style.foreground - std.time.sleep -> std.Thread.sleep - Cell.char -> Cell.symbol with proper Symbol comparison 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
292 lines
9.2 KiB
Zig
292 lines
9.2 KiB
Zig
//! Line drawing characters.
|
|
//!
|
|
//! Provides sets of Unicode box-drawing characters for creating lines,
|
|
//! borders, and tables with various styles (normal, rounded, double, thick).
|
|
|
|
const std = @import("std");
|
|
|
|
// ============================================================================
|
|
// Individual Line Characters
|
|
// ============================================================================
|
|
|
|
// Vertical lines
|
|
pub const VERTICAL: []const u8 = "│";
|
|
pub const DOUBLE_VERTICAL: []const u8 = "║";
|
|
pub const THICK_VERTICAL: []const u8 = "┃";
|
|
pub const LIGHT_DOUBLE_DASH_VERTICAL: []const u8 = "╎";
|
|
pub const HEAVY_DOUBLE_DASH_VERTICAL: []const u8 = "╏";
|
|
pub const LIGHT_TRIPLE_DASH_VERTICAL: []const u8 = "┆";
|
|
pub const HEAVY_TRIPLE_DASH_VERTICAL: []const u8 = "┇";
|
|
pub const LIGHT_QUADRUPLE_DASH_VERTICAL: []const u8 = "┊";
|
|
pub const HEAVY_QUADRUPLE_DASH_VERTICAL: []const u8 = "┋";
|
|
|
|
// Horizontal lines
|
|
pub const HORIZONTAL: []const u8 = "─";
|
|
pub const DOUBLE_HORIZONTAL: []const u8 = "═";
|
|
pub const THICK_HORIZONTAL: []const u8 = "━";
|
|
pub const LIGHT_DOUBLE_DASH_HORIZONTAL: []const u8 = "╌";
|
|
pub const HEAVY_DOUBLE_DASH_HORIZONTAL: []const u8 = "╍";
|
|
pub const LIGHT_TRIPLE_DASH_HORIZONTAL: []const u8 = "┄";
|
|
pub const HEAVY_TRIPLE_DASH_HORIZONTAL: []const u8 = "┅";
|
|
pub const LIGHT_QUADRUPLE_DASH_HORIZONTAL: []const u8 = "┈";
|
|
pub const HEAVY_QUADRUPLE_DASH_HORIZONTAL: []const u8 = "┉";
|
|
|
|
// Corners - Top Right
|
|
pub const TOP_RIGHT: []const u8 = "┐";
|
|
pub const ROUNDED_TOP_RIGHT: []const u8 = "╮";
|
|
pub const DOUBLE_TOP_RIGHT: []const u8 = "╗";
|
|
pub const THICK_TOP_RIGHT: []const u8 = "┓";
|
|
|
|
// Corners - Top Left
|
|
pub const TOP_LEFT: []const u8 = "┌";
|
|
pub const ROUNDED_TOP_LEFT: []const u8 = "╭";
|
|
pub const DOUBLE_TOP_LEFT: []const u8 = "╔";
|
|
pub const THICK_TOP_LEFT: []const u8 = "┏";
|
|
|
|
// Corners - Bottom Right
|
|
pub const BOTTOM_RIGHT: []const u8 = "┘";
|
|
pub const ROUNDED_BOTTOM_RIGHT: []const u8 = "╯";
|
|
pub const DOUBLE_BOTTOM_RIGHT: []const u8 = "╝";
|
|
pub const THICK_BOTTOM_RIGHT: []const u8 = "┛";
|
|
|
|
// Corners - Bottom Left
|
|
pub const BOTTOM_LEFT: []const u8 = "└";
|
|
pub const ROUNDED_BOTTOM_LEFT: []const u8 = "╰";
|
|
pub const DOUBLE_BOTTOM_LEFT: []const u8 = "╚";
|
|
pub const THICK_BOTTOM_LEFT: []const u8 = "┗";
|
|
|
|
// T-junctions
|
|
pub const VERTICAL_LEFT: []const u8 = "┤";
|
|
pub const DOUBLE_VERTICAL_LEFT: []const u8 = "╣";
|
|
pub const THICK_VERTICAL_LEFT: []const u8 = "┫";
|
|
|
|
pub const VERTICAL_RIGHT: []const u8 = "├";
|
|
pub const DOUBLE_VERTICAL_RIGHT: []const u8 = "╠";
|
|
pub const THICK_VERTICAL_RIGHT: []const u8 = "┣";
|
|
|
|
pub const HORIZONTAL_DOWN: []const u8 = "┬";
|
|
pub const DOUBLE_HORIZONTAL_DOWN: []const u8 = "╦";
|
|
pub const THICK_HORIZONTAL_DOWN: []const u8 = "┳";
|
|
|
|
pub const HORIZONTAL_UP: []const u8 = "┴";
|
|
pub const DOUBLE_HORIZONTAL_UP: []const u8 = "╩";
|
|
pub const THICK_HORIZONTAL_UP: []const u8 = "┻";
|
|
|
|
// Cross
|
|
pub const CROSS: []const u8 = "┼";
|
|
pub const DOUBLE_CROSS: []const u8 = "╬";
|
|
pub const THICK_CROSS: []const u8 = "╋";
|
|
|
|
// ============================================================================
|
|
// Line Set
|
|
// ============================================================================
|
|
|
|
/// A complete set of line drawing characters for a particular style.
|
|
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 default: Set = NORMAL;
|
|
};
|
|
|
|
/// Normal (thin) line set.
|
|
/// ```
|
|
/// ┌─┬┐
|
|
/// │ ││
|
|
/// ├─┼┤
|
|
/// └─┴┘
|
|
/// ```
|
|
pub const NORMAL: Set = .{
|
|
.vertical = VERTICAL,
|
|
.horizontal = HORIZONTAL,
|
|
.top_right = TOP_RIGHT,
|
|
.top_left = TOP_LEFT,
|
|
.bottom_right = BOTTOM_RIGHT,
|
|
.bottom_left = BOTTOM_LEFT,
|
|
.vertical_left = VERTICAL_LEFT,
|
|
.vertical_right = VERTICAL_RIGHT,
|
|
.horizontal_down = HORIZONTAL_DOWN,
|
|
.horizontal_up = HORIZONTAL_UP,
|
|
.cross = CROSS,
|
|
};
|
|
|
|
/// Rounded corner line set.
|
|
/// ```
|
|
/// ╭─┬╮
|
|
/// │ ││
|
|
/// ├─┼┤
|
|
/// ╰─┴╯
|
|
/// ```
|
|
pub const ROUNDED: Set = .{
|
|
.vertical = VERTICAL,
|
|
.horizontal = HORIZONTAL,
|
|
.top_right = ROUNDED_TOP_RIGHT,
|
|
.top_left = ROUNDED_TOP_LEFT,
|
|
.bottom_right = ROUNDED_BOTTOM_RIGHT,
|
|
.bottom_left = ROUNDED_BOTTOM_LEFT,
|
|
.vertical_left = VERTICAL_LEFT,
|
|
.vertical_right = VERTICAL_RIGHT,
|
|
.horizontal_down = HORIZONTAL_DOWN,
|
|
.horizontal_up = HORIZONTAL_UP,
|
|
.cross = CROSS,
|
|
};
|
|
|
|
/// Double line set.
|
|
/// ```
|
|
/// ╔═╦╗
|
|
/// ║ ║║
|
|
/// ╠═╬╣
|
|
/// ╚═╩╝
|
|
/// ```
|
|
pub const DOUBLE: Set = .{
|
|
.vertical = DOUBLE_VERTICAL,
|
|
.horizontal = DOUBLE_HORIZONTAL,
|
|
.top_right = DOUBLE_TOP_RIGHT,
|
|
.top_left = DOUBLE_TOP_LEFT,
|
|
.bottom_right = DOUBLE_BOTTOM_RIGHT,
|
|
.bottom_left = DOUBLE_BOTTOM_LEFT,
|
|
.vertical_left = DOUBLE_VERTICAL_LEFT,
|
|
.vertical_right = DOUBLE_VERTICAL_RIGHT,
|
|
.horizontal_down = DOUBLE_HORIZONTAL_DOWN,
|
|
.horizontal_up = DOUBLE_HORIZONTAL_UP,
|
|
.cross = DOUBLE_CROSS,
|
|
};
|
|
|
|
/// Thick (heavy) line set.
|
|
/// ```
|
|
/// ┏━┳┓
|
|
/// ┃ ┃┃
|
|
/// ┣━╋┫
|
|
/// ┗━┻┛
|
|
/// ```
|
|
pub const THICK: Set = .{
|
|
.vertical = THICK_VERTICAL,
|
|
.horizontal = THICK_HORIZONTAL,
|
|
.top_right = THICK_TOP_RIGHT,
|
|
.top_left = THICK_TOP_LEFT,
|
|
.bottom_right = THICK_BOTTOM_RIGHT,
|
|
.bottom_left = THICK_BOTTOM_LEFT,
|
|
.vertical_left = THICK_VERTICAL_LEFT,
|
|
.vertical_right = THICK_VERTICAL_RIGHT,
|
|
.horizontal_down = THICK_HORIZONTAL_DOWN,
|
|
.horizontal_up = THICK_HORIZONTAL_UP,
|
|
.cross = THICK_CROSS,
|
|
};
|
|
|
|
/// Light double-dashed line set.
|
|
pub const LIGHT_DOUBLE_DASHED: Set = .{
|
|
.vertical = LIGHT_DOUBLE_DASH_VERTICAL,
|
|
.horizontal = LIGHT_DOUBLE_DASH_HORIZONTAL,
|
|
.top_right = TOP_RIGHT,
|
|
.top_left = TOP_LEFT,
|
|
.bottom_right = BOTTOM_RIGHT,
|
|
.bottom_left = BOTTOM_LEFT,
|
|
.vertical_left = VERTICAL_LEFT,
|
|
.vertical_right = VERTICAL_RIGHT,
|
|
.horizontal_down = HORIZONTAL_DOWN,
|
|
.horizontal_up = HORIZONTAL_UP,
|
|
.cross = CROSS,
|
|
};
|
|
|
|
/// Heavy double-dashed line set.
|
|
pub const HEAVY_DOUBLE_DASHED: Set = .{
|
|
.vertical = HEAVY_DOUBLE_DASH_VERTICAL,
|
|
.horizontal = HEAVY_DOUBLE_DASH_HORIZONTAL,
|
|
.top_right = THICK_TOP_RIGHT,
|
|
.top_left = THICK_TOP_LEFT,
|
|
.bottom_right = THICK_BOTTOM_RIGHT,
|
|
.bottom_left = THICK_BOTTOM_LEFT,
|
|
.vertical_left = THICK_VERTICAL_LEFT,
|
|
.vertical_right = THICK_VERTICAL_RIGHT,
|
|
.horizontal_down = THICK_HORIZONTAL_DOWN,
|
|
.horizontal_up = THICK_HORIZONTAL_UP,
|
|
.cross = THICK_CROSS,
|
|
};
|
|
|
|
/// Light triple-dashed line set.
|
|
pub const LIGHT_TRIPLE_DASHED: Set = .{
|
|
.vertical = LIGHT_TRIPLE_DASH_VERTICAL,
|
|
.horizontal = LIGHT_TRIPLE_DASH_HORIZONTAL,
|
|
.top_right = TOP_RIGHT,
|
|
.top_left = TOP_LEFT,
|
|
.bottom_right = BOTTOM_RIGHT,
|
|
.bottom_left = BOTTOM_LEFT,
|
|
.vertical_left = VERTICAL_LEFT,
|
|
.vertical_right = VERTICAL_RIGHT,
|
|
.horizontal_down = HORIZONTAL_DOWN,
|
|
.horizontal_up = HORIZONTAL_UP,
|
|
.cross = CROSS,
|
|
};
|
|
|
|
/// Heavy triple-dashed line set.
|
|
pub const HEAVY_TRIPLE_DASHED: Set = .{
|
|
.vertical = HEAVY_TRIPLE_DASH_VERTICAL,
|
|
.horizontal = HEAVY_TRIPLE_DASH_HORIZONTAL,
|
|
.top_right = THICK_TOP_RIGHT,
|
|
.top_left = THICK_TOP_LEFT,
|
|
.bottom_right = THICK_BOTTOM_RIGHT,
|
|
.bottom_left = THICK_BOTTOM_LEFT,
|
|
.vertical_left = THICK_VERTICAL_LEFT,
|
|
.vertical_right = THICK_VERTICAL_RIGHT,
|
|
.horizontal_down = THICK_HORIZONTAL_DOWN,
|
|
.horizontal_up = THICK_HORIZONTAL_UP,
|
|
.cross = THICK_CROSS,
|
|
};
|
|
|
|
/// Light quadruple-dashed line set.
|
|
pub const LIGHT_QUADRUPLE_DASHED: Set = .{
|
|
.vertical = LIGHT_QUADRUPLE_DASH_VERTICAL,
|
|
.horizontal = LIGHT_QUADRUPLE_DASH_HORIZONTAL,
|
|
.top_right = TOP_RIGHT,
|
|
.top_left = TOP_LEFT,
|
|
.bottom_right = BOTTOM_RIGHT,
|
|
.bottom_left = BOTTOM_LEFT,
|
|
.vertical_left = VERTICAL_LEFT,
|
|
.vertical_right = VERTICAL_RIGHT,
|
|
.horizontal_down = HORIZONTAL_DOWN,
|
|
.horizontal_up = HORIZONTAL_UP,
|
|
.cross = CROSS,
|
|
};
|
|
|
|
/// Heavy quadruple-dashed line set.
|
|
pub const HEAVY_QUADRUPLE_DASHED: Set = .{
|
|
.vertical = HEAVY_QUADRUPLE_DASH_VERTICAL,
|
|
.horizontal = HEAVY_QUADRUPLE_DASH_HORIZONTAL,
|
|
.top_right = THICK_TOP_RIGHT,
|
|
.top_left = THICK_TOP_LEFT,
|
|
.bottom_right = THICK_BOTTOM_RIGHT,
|
|
.bottom_left = THICK_BOTTOM_LEFT,
|
|
.vertical_left = THICK_VERTICAL_LEFT,
|
|
.vertical_right = THICK_VERTICAL_RIGHT,
|
|
.horizontal_down = THICK_HORIZONTAL_DOWN,
|
|
.horizontal_up = THICK_HORIZONTAL_UP,
|
|
.cross = THICK_CROSS,
|
|
};
|
|
|
|
// ============================================================================
|
|
// Tests
|
|
// ============================================================================
|
|
|
|
test "line set default" {
|
|
try std.testing.expectEqualStrings(VERTICAL, Set.default.vertical);
|
|
try std.testing.expectEqualStrings(HORIZONTAL, Set.default.horizontal);
|
|
}
|
|
|
|
test "line characters are valid UTF-8" {
|
|
// Verify all characters decode properly
|
|
const v: [3]u8 = VERTICAL[0..3].*;
|
|
const h: [3]u8 = HORIZONTAL[0..3].*;
|
|
const tl: [3]u8 = TOP_LEFT[0..3].*;
|
|
_ = std.unicode.utf8Decode(&v) catch unreachable;
|
|
_ = std.unicode.utf8Decode(&h) catch unreachable;
|
|
_ = std.unicode.utf8Decode(&tl) catch unreachable;
|
|
}
|