From 20cae4b6e05f8aa85e7dd9f2b8b8eee5cfde3061 Mon Sep 17 00:00:00 2001 From: Warwick Date: Fri, 15 Nov 2024 16:29:12 +0000 Subject: [PATCH] Have a workingscreen except in kitty where the process keeps running after completion --- build.zig | 4 +++ src/ScreenInterface.zig | 20 +++++++++--- src/TopicScreen.zig | 72 +++++++++++++++++++++++++++++++++++++---- src/main.zig | 34 ++++++++++++++++--- 4 files changed, 114 insertions(+), 16 deletions(-) diff --git a/build.zig b/build.zig index 29ecfcf..ea8562d 100644 --- a/build.zig +++ b/build.zig @@ -22,6 +22,10 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }); + // Add Vaxis - tui library + const vaxis = b.dependency("vaxis", .{ .target = target, .optimize = optimize }); + exe.root_module.addImport("vaxis", vaxis.module("vaxis")); + // This declares intent for the executable to be installed into the // standard location when the user invokes the "install" step (the default // step when running `zig build`). diff --git a/src/ScreenInterface.zig b/src/ScreenInterface.zig index 938fcc8..1a99ff4 100644 --- a/src/ScreenInterface.zig +++ b/src/ScreenInterface.zig @@ -4,10 +4,6 @@ pub const ScreenInterface = struct { ptr: *anyopaque, vtable: VTable, - pub fn init(self: ScreenInterface) anyerror!ScreenInterface { - return self.vtable.initFn(self.ptr); - } - pub fn deinit(self: ScreenInterface) anyerror!void { return self.vtable.deinitFn(self.ptr); } @@ -18,7 +14,21 @@ pub const ScreenInterface = struct { }; const VTable = struct { - initFn: *const fn (self: *anyopaque) anyerror!ScreenInterface, deinitFn: *const fn (self: *anyopaque) anyerror!void, runFn: *const fn (self: *anyopaque) anyerror!void, }; + +pub const ScreenEvent = union(enum) { + key_press: vaxis.Key, + key_release: vaxis.Key, + //mouse: vaxis.Mouse, + focus_in, // window has gained focus + focus_out, // window has lost focus + paste_start, // bracketed paste start + paste_end, // bracketed paste end + paste: []const u8, // osc 52 paste, caller must free + color_report: vaxis.Color.Report, // osc 4, 10, 11, 12 response + color_scheme: vaxis.Color.Scheme, // light / dark OS theme changes + winsize: vaxis.Winsize, // the window size has changed. This event is always sent when the loop + // is started +}; diff --git a/src/TopicScreen.zig b/src/TopicScreen.zig index 482a8bd..bb6582d 100644 --- a/src/TopicScreen.zig +++ b/src/TopicScreen.zig @@ -1,13 +1,21 @@ const std = @import("std"); +const vaxis = @import("vaxis"); const ScreenInterface = @import("ScreenInterface.zig").ScreenInterface; +const ScreenEvent = @import("ScreenInterface.zig").ScreenEvent; pub const TopicScreen = struct { - topic: []const u8 = "ayy", + allocator: *std.mem.Allocator, + vx: *vaxis.Vaxis, + tty: *vaxis.Tty, + topic: []const u8 = "deinit\n", + quit: bool = false, - pub fn init(ptr: *anyopaque) !ScreenInterface { - const self: *TopicScreen = @ptrCast(@alignCast(ptr)); - std.debug.print("{s}", .{self.topic}); - return self.screenInterface(); + pub fn init(allocator: *std.mem.Allocator, tty: *vaxis.Tty, vaxis_instance: *vaxis.Vaxis) !TopicScreen { + return .{ + .allocator = allocator, + .tty = tty, + .vx = vaxis_instance, + }; } pub fn deinit(ptr: *anyopaque) !void { const self: *TopicScreen = @ptrCast(@alignCast(ptr)); @@ -15,12 +23,62 @@ pub const TopicScreen = struct { } pub fn run(ptr: *anyopaque) !void { const self: *TopicScreen = @ptrCast(@alignCast(ptr)); - return std.debug.print("{s}", .{self.topic}); + + var loop: vaxis.Loop(ScreenEvent) = .{ + .tty = self.tty, + .vaxis = self.vx, + }; + try loop.init(); + + try loop.start(); + //defer loop.stop(); + + try self.vx.enterAltScreen(self.tty.anyWriter()); + + try self.vx.queryTerminal(self.tty.anyWriter(), 1 * std.time.ns_per_s); + + while (!self.quit) { + loop.pollEvent(); + while (loop.tryEvent()) |event| { + try self.update(event); + } + + self.draw(); + + var buffered = self.tty.bufferedWriter(); + try self.vx.render(buffered.writer().any()); + try buffered.flush(); + } + } + pub fn update(self: *TopicScreen, event: ScreenEvent) !void { + switch (event) { + .key_press => |key| { + if (key.matches('c', .{ .ctrl = true })) + self.quit = true; + }, + .winsize => |ws| try self.vx.resize(self.allocator.*, self.tty.anyWriter(), ws), + else => {}, + } + } + + pub fn draw(self: *TopicScreen) void { + const msg = "Hello, world!"; + const win = self.vx.window(); + win.clear(); + //self.vx.setMouseShape(.default); + + const child = win.child(.{ + .x_off = (win.width / 2) - 7, + .y_off = win.height / 2 + 1, + .width = .{ .limit = msg.len }, + .height = .{ .limit = 1 }, + }); + + _ = try child.printSegment(.{ .text = msg, .style = .{} }, .{}); } pub fn screenInterface(self: *TopicScreen) ScreenInterface { return .{ .ptr = self, .vtable = .{ - .initFn = TopicScreen.init, .deinitFn = TopicScreen.deinit, .runFn = TopicScreen.run, } }; diff --git a/src/main.zig b/src/main.zig index 9d27a5d..ef79c03 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,10 +1,36 @@ const std = @import("std"); +const vaxis = @import("vaxis"); const TopicScreen = @import("TopicScreen.zig").TopicScreen; +pub const panic = vaxis.panic_handler; + +/// Set some scope levels for the vaxis scopes +pub const std_options: std.Options = .{ + .log_scope_levels = &.{ + .{ .scope = .vaxis, .level = .warn }, + .{ .scope = .vaxis_parser, .level = .warn }, + }, +}; + pub fn main() !void { - var topic_screen = TopicScreen{ .topic = "it worked?" }; + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer { + const deinit_status = gpa.deinit(); + //fail test; can't try in defer as defer is executed after we return + if (deinit_status == .leak) { + std.log.err("memory leak ", .{}); + } + } + var allocator = gpa.allocator(); + + var tty = try vaxis.Tty.init(); + var vx = try vaxis.init(allocator, .{}); + defer vx.deinit(allocator, tty.anyWriter()); + defer tty.deinit(); + + var topic_screen: TopicScreen = try TopicScreen.init(&allocator, &tty, &vx); var screen_interface = topic_screen.screenInterface(); - _ = try screen_interface.init(); - _ = try screen_interface.run(); - _ = try screen_interface.deinit(); + + try screen_interface.run(); + try screen_interface.deinit(); }