a modern tui library written in zig
1const std = @import("std");
2const assert = std.debug.assert;
3const Style = @import("cell.zig").Style;
4const Cell = @import("cell.zig").Cell;
5const Shape = @import("Mouse.zig").Shape;
6
7const log = std.log.scoped(.internal_screen);
8
9const InternalScreen = @This();
10
11pub const InternalCell = struct {
12 char: std.ArrayList(u8) = undefined,
13 style: Style = .{},
14 uri: std.ArrayList(u8) = undefined,
15 uri_id: std.ArrayList(u8) = undefined,
16 // if we got skipped because of a wide character
17 skipped: bool = false,
18
19 pub fn eql(self: InternalCell, cell: Cell) bool {
20 return std.mem.eql(u8, self.char.items, cell.char.grapheme) and
21 std.meta.eql(self.style, cell.style) and
22 std.mem.eql(u8, self.uri.items, cell.link.uri) and
23 std.mem.eql(u8, self.uri_id.items, cell.link.params);
24 }
25};
26
27width: usize = 0,
28height: usize = 0,
29
30buf: []InternalCell = undefined,
31
32cursor_row: usize = 0,
33cursor_col: usize = 0,
34cursor_vis: bool = false,
35
36mouse_shape: Shape = .default,
37
38/// sets each cell to the default cell
39pub fn init(alloc: std.mem.Allocator, w: usize, h: usize) !InternalScreen {
40 var screen = InternalScreen{
41 .buf = try alloc.alloc(InternalCell, w * h),
42 };
43 for (screen.buf, 0..) |_, i| {
44 screen.buf[i] = .{
45 .char = try std.ArrayList(u8).initCapacity(alloc, 1),
46 .uri = std.ArrayList(u8).init(alloc),
47 .uri_id = std.ArrayList(u8).init(alloc),
48 };
49 }
50 screen.width = w;
51 screen.height = h;
52 return screen;
53}
54
55pub fn deinit(self: *InternalScreen, alloc: std.mem.Allocator) void {
56 for (self.buf, 0..) |_, i| {
57 self.buf[i].char.deinit();
58 self.buf[i].uri.deinit();
59 self.buf[i].uri_id.deinit();
60 }
61
62 alloc.free(self.buf);
63}
64
65/// writes a cell to a location. 0 indexed
66pub fn writeCell(
67 self: *InternalScreen,
68 col: usize,
69 row: usize,
70 cell: Cell,
71) void {
72 if (self.width < col) {
73 // column out of bounds
74 return;
75 }
76 if (self.height < row) {
77 // height out of bounds
78 return;
79 }
80 const i = (row * self.width) + col;
81 assert(i < self.buf.len);
82 self.buf[i].char.clearRetainingCapacity();
83 self.buf[i].char.appendSlice(cell.char.grapheme) catch {
84 log.warn("couldn't write grapheme", .{});
85 };
86 self.buf[i].uri.clearRetainingCapacity();
87 self.buf[i].uri.appendSlice(cell.link.uri) catch {
88 log.warn("couldn't write uri", .{});
89 };
90 self.buf[i].uri.clearRetainingCapacity();
91 self.buf[i].uri_id.appendSlice(cell.link.params) catch {
92 log.warn("couldn't write uri_id", .{});
93 };
94 self.buf[i].style = cell.style;
95}