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