a modern tui library written in zig
at main 3.7 kB view raw
1const std = @import("std"); 2const vaxis = @import("vaxis"); 3const Cell = vaxis.Cell; 4const TextInput = vaxis.widgets.TextInput; 5 6const log = std.log.scoped(.main); 7pub fn main() !void { 8 var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 9 defer { 10 const deinit_status = gpa.deinit(); 11 if (deinit_status == .leak) { 12 log.err("memory leak", .{}); 13 } 14 } 15 const alloc = gpa.allocator(); 16 17 var buffer: [1024]u8 = undefined; 18 var tty = try vaxis.Tty.init(&buffer); 19 defer tty.deinit(); 20 21 var vx = try vaxis.init(alloc, .{}); 22 defer vx.deinit(alloc, tty.writer()); 23 24 var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx }; 25 try loop.init(); 26 27 try loop.start(); 28 defer loop.stop(); 29 30 try vx.queryTerminal(tty.writer(), 1 * std.time.ns_per_s); 31 32 var text_input = TextInput.init(alloc); 33 defer text_input.deinit(); 34 35 var selected_option: ?usize = null; 36 37 const options = [_][]const u8{ 38 "option 1", 39 "option 2", 40 "option 3", 41 }; 42 43 // The main event loop. Vaxis provides a thread safe, blocking, buffered 44 // queue which can serve as the primary event queue for an application 45 while (true) { 46 // nextEvent blocks until an event is in the queue 47 const event = loop.nextEvent(); 48 // exhaustive switching ftw. Vaxis will send events if your Event 49 // enum has the fields for those events (ie "key_press", "winsize") 50 switch (event) { 51 .key_press => |key| { 52 if (key.codepoint == 'c' and key.mods.ctrl) { 53 break; 54 } else if (key.matches(vaxis.Key.tab, .{})) { 55 if (selected_option == null) { 56 selected_option = 0; 57 } else { 58 selected_option.? = @min(options.len - 1, selected_option.? + 1); 59 } 60 } else if (key.matches(vaxis.Key.tab, .{ .shift = true })) { 61 if (selected_option == null) { 62 selected_option = 0; 63 } else { 64 selected_option.? = selected_option.? -| 1; 65 } 66 } else if (key.matches(vaxis.Key.enter, .{}) or key.matches('j', .{ .ctrl = true })) { 67 if (selected_option) |i| { 68 log.err("enter", .{}); 69 try text_input.insertSliceAtCursor(options[i]); 70 selected_option = null; 71 } 72 } else { 73 if (selected_option == null) 74 try text_input.update(.{ .key_press = key }); 75 } 76 }, 77 .winsize => |ws| { 78 try vx.resize(alloc, tty.writer(), ws); 79 }, 80 else => {}, 81 } 82 83 const win = vx.window(); 84 win.clear(); 85 86 text_input.draw(win); 87 88 if (selected_option) |i| { 89 win.hideCursor(); 90 for (options, 0..) |opt, j| { 91 log.err("i = {d}, j = {d}, opt = {s}", .{ i, j, opt }); 92 var seg = [_]vaxis.Segment{.{ 93 .text = opt, 94 .style = if (j == i) .{ .reverse = true } else .{}, 95 }}; 96 _ = win.print(&seg, .{ .row_offset = @intCast(j + 1) }); 97 } 98 } 99 try vx.render(tty.writer()); 100 } 101} 102 103// Our Event. This can contain internal events as well as Vaxis events. 104// Internal events can be posted into the same queue as vaxis events to allow 105// for a single event loop with exhaustive switching. Booya 106const Event = union(enum) { 107 key_press: vaxis.Key, 108 winsize: vaxis.Winsize, 109 focus_in, 110 foo: u8, 111};