this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 8a9c2d5e1b3778f1ea43c9bd5d325cfa72016584 157 lines 6.1 kB view raw
1const std = @import("std"); 2const vaxis = @import("vaxis"); 3const Cell = vaxis.Cell; 4const TextInput = vaxis.widgets.TextInput; 5const border = vaxis.widgets.border; 6 7const log = std.log.scoped(.main); 8 9// Our Event. This can contain internal events as well as Vaxis events. 10// Internal events can be posted into the same queue as vaxis events to allow 11// for a single event loop with exhaustive switching. Booya 12const Event = union(enum) { 13 key_press: vaxis.Key, 14 mouse: vaxis.Mouse, 15 winsize: vaxis.Winsize, 16 focus_in, 17 focus_out, 18 foo: u8, 19}; 20 21pub fn main() !void { 22 var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 23 defer { 24 const deinit_status = gpa.deinit(); 25 //fail test; can't try in defer as defer is executed after we return 26 if (deinit_status == .leak) { 27 log.err("memory leak", .{}); 28 } 29 } 30 const alloc = gpa.allocator(); 31 32 // Initalize a tty 33 var buffer: [1024]u8 = undefined; 34 var tty = try vaxis.Tty.init(&buffer); 35 defer tty.deinit(); 36 37 // Use a buffered writer for better performance. There are a lot of writes 38 // in the render loop and this can have a significant savings 39 const writer = tty.writer(); 40 41 // Initialize Vaxis 42 var vx = try vaxis.init(alloc, .{ 43 .kitty_keyboard_flags = .{ .report_events = true }, 44 }); 45 defer vx.deinit(alloc, tty.writer()); 46 47 var loop: vaxis.Loop(Event) = .{ 48 .vaxis = &vx, 49 .tty = &tty, 50 }; 51 try loop.init(); 52 53 // Start the read loop. This puts the terminal in raw mode and begins 54 // reading user input 55 try loop.start(); 56 defer loop.stop(); 57 58 // Optionally enter the alternate screen 59 try vx.enterAltScreen(writer); 60 61 // We'll adjust the color index every keypress for the border 62 var color_idx: u8 = 0; 63 64 // init our text input widget. The text input widget needs an allocator to 65 // store the contents of the input 66 var text_input = TextInput.init(alloc); 67 defer text_input.deinit(); 68 69 try vx.setMouseMode(writer, true); 70 71 try writer.flush(); 72 // Sends queries to terminal to detect certain features. This should 73 // _always_ be called, but is left to the application to decide when 74 try vx.queryTerminal(tty.writer(), 1 * std.time.ns_per_s); 75 76 // The main event loop. Vaxis provides a thread safe, blocking, buffered 77 // queue which can serve as the primary event queue for an application 78 while (true) { 79 // nextEvent blocks until an event is in the queue 80 const event = loop.nextEvent(); 81 log.debug("event: {}", .{event}); 82 // exhaustive switching ftw. Vaxis will send events if your Event 83 // enum has the fields for those events (ie "key_press", "winsize") 84 switch (event) { 85 .key_press => |key| { 86 color_idx = switch (color_idx) { 87 255 => 0, 88 else => color_idx + 1, 89 }; 90 if (key.matches('c', .{ .ctrl = true })) { 91 break; 92 } else if (key.matches('l', .{ .ctrl = true })) { 93 vx.queueRefresh(); 94 } else if (key.matches('n', .{ .ctrl = true })) { 95 try vx.notify(tty.writer(), "vaxis", "hello from vaxis"); 96 loop.stop(); 97 var child = std.process.Child.init(&.{"nvim"}, alloc); 98 _ = try child.spawnAndWait(); 99 try loop.start(); 100 try vx.enterAltScreen(tty.writer()); 101 vx.queueRefresh(); 102 } else if (key.matches(vaxis.Key.enter, .{}) or key.matches('j', .{ .ctrl = true })) { 103 text_input.clearAndFree(); 104 } else { 105 try text_input.update(.{ .key_press = key }); 106 } 107 }, 108 109 // winsize events are sent to the application to ensure that all 110 // resizes occur in the main thread. This lets us avoid expensive 111 // locks on the screen. All applications must handle this event 112 // unless they aren't using a screen (IE only detecting features) 113 // 114 // This is the only call that the core of Vaxis needs an allocator 115 // for. The allocations are because we keep a copy of each cell to 116 // optimize renders. When resize is called, we allocated two slices: 117 // one for the screen, and one for our buffered screen. Each cell in 118 // the buffered screen contains an ArrayList(u8) to be able to store 119 // the grapheme for that cell Each cell is initialized with a size 120 // of 1, which is sufficient for all of ASCII. Anything requiring 121 // more than one byte will incur an allocation on the first render 122 // after it is drawn. Thereafter, it will not allocate unless the 123 // screen is resized 124 .winsize => |ws| try vx.resize(alloc, tty.writer(), ws), 125 else => {}, 126 } 127 128 // vx.window() returns the root window. This window is the size of the 129 // terminal and can spawn child windows as logical areas. Child windows 130 // cannot draw outside of their bounds 131 const win = vx.window(); 132 133 // Clear the entire space because we are drawing in immediate mode. 134 // vaxis double buffers the screen. This new frame will be compared to 135 // the old and only updated cells will be drawn 136 win.clear(); 137 // draw the text_input using a bordered window 138 const style: vaxis.Style = .{ 139 .fg = .{ .index = color_idx }, 140 }; 141 const child = win.child(.{ 142 .x_off = win.width / 2 - 20, 143 .y_off = win.height / 2 - 3, 144 .width = 40, 145 .height = 3, 146 .border = .{ 147 .where = .all, 148 .style = style, 149 }, 150 }); 151 text_input.draw(child); 152 153 // Render the screen 154 try vx.render(writer); 155 try writer.flush(); 156 } 157}