const std = @import("std"); const vaxis = @import("vaxis"); const zlog = @import("zlog"); const widget = @import("widget.zig"); const TextInput = vaxis.widgets.TextInput; const Event = widget.Event; pub const std_options = zlog.std_options; pub fn main() !void { 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", .{}); } } const alloc = gpa.allocator(); // Initialize a tty var tty = try vaxis.Tty.init(); defer tty.deinit(); // Initialize Vaxis var vx = try vaxis.init(alloc, .{}); // deinit takes an optional allocator. If your program is exiting, you can // choose to pass a null allocator to save some exit time. defer vx.deinit(alloc, tty.anyWriter()); // The event loop requires an intrusive init. We create an instance with // stable pointers to Vaxis and our TTY, then init the instance. Doing so // installs a signal handler for SIGWINCH on posix TTYs // // This event loop is thread safe. It reads the tty in a separate thread var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx, }; try loop.init(); // Start the read loop. This puts the terminal in raw mode and begins // reading user input try loop.start(); defer loop.stop(); // Optionally enter the alternate screen try vx.enterAltScreen(tty.anyWriter()); var header = try widget.Header.init(alloc, &vx.unicode); defer header.deinit(); var view_port = widget.ViewPort.init(alloc, &vx.unicode); defer view_port.deinit(); var active_menu = false; var menu = widget.PopupMenu.init(alloc, &vx.unicode); defer menu.deinit(); // Sends queries to terminal to detect certain features. This should always // be called after entering the alt screen, if you are using the alt screen try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s); loop.postEvent(.{ .path = "./doc/home.md" }); while (true) { const event = loop.nextEvent(); // update widgets header.update(event); view_port.update(event); if (active_menu) { if (menu.update(event)) |e| { _ = loop.tryPostEvent(e); active_menu = false; } } switch (event) { .key_press => |key| { if (active_menu) { if (key.matches(vaxis.Key.escape, .{})) { active_menu = false; } } if (key.matches('c', .{ .ctrl = true })) { break; } else if (key.matches(vaxis.Key.space, .{})) { active_menu = true; } else if (key.matches('l', .{ .ctrl = true })) { vx.queueRefresh(); } }, .winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws), else => {}, } var root_window = vx.window(); root_window.clear(); // FIXME: this should not be necessary to clear the contents try vx.render(tty.anyWriter()); // re-draw after clear! header.draw(root_window.child(.{ .x_off = 0, .y_off = 0, .height = .{ .limit = 3 }, .border = .{ .where = .all }, })); // should be 120 characters wide and centered horizontally var view_port_x_off: usize = undefined; var limit: usize = 120; if (root_window.width / 2 -| 60 > 0) { view_port_x_off = root_window.width / 2 -| 60; } else { view_port_x_off = 1; limit = root_window.width - 1; } view_port.draw(root_window.child(.{ .x_off = view_port_x_off, .y_off = 3, .width = .{ .limit = limit }, })); if (active_menu) { menu.draw(root_window.child(.{ .x_off = root_window.width / 2 -| 25, .y_off = root_window.height / 2 -| 10, .width = .{ .limit = 50 }, .height = .{ .limit = 20 }, .border = .{ .where = .all }, })); } // Render the screen. Using a buffered writer will offer much better // performance, but is not required try vx.render(tty.anyWriter()); } }