this repo has no description
13
fork

Configure Feed

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

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