···11-const std = @import("std");
22-const mem = std.mem;
33-const process = std.process;
44-const vaxis = @import("vaxis");
55-const Cell = vaxis.Cell;
66-const TextInput = vaxis.widgets.TextInput;
77-const border = vaxis.widgets.border;
88-99-const log = std.log.scoped(.main);
1010-1111-// Our Event. This can contain internal events as well as Vaxis events.
1212-// Internal events can be posted into the same queue as vaxis events to allow
1313-// for a single event loop with exhaustive switching. Booya
1414-const Event = union(enum) {
1515- key_press: vaxis.Key,
1616- mouse: vaxis.Mouse,
1717- winsize: vaxis.Winsize,
1818- focus_in,
1919- focus_out,
2020- foo: u8,
2121-};
2222-2323-pub fn main() !void {
2424- var gpa = std.heap.GeneralPurposeAllocator(.{}){};
2525- defer {
2626- const deinit_status = gpa.deinit();
2727- //fail test; can't try in defer as defer is executed after we return
2828- if (deinit_status == .leak) {
2929- log.err("memory leak", .{});
3030- }
3131- }
3232- const alloc = gpa.allocator();
3333-3434- var tty = try vaxis.Tty.init();
3535- defer tty.deinit();
3636-3737- var vx = try vaxis.init(alloc, .{});
3838- defer vx.deinit(alloc, tty.anyWriter());
3939-4040- var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
4141- try loop.init();
4242-4343- try loop.start();
4444- defer loop.stop();
4545-4646- // We'll adjust the color index every keypress for the border
4747- var color_idx: u8 = 0;
4848-4949- // init our text input widget. The text input widget needs an allocator to
5050- // store the contents of the input
5151- var text_input = TextInput.init(alloc);
5252- defer text_input.deinit();
5353-5454- // Sends queries to terminal to detect certain features. This should
5555- // _always_ be called, but is left to the application to decide when
5656- try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
5757-5858- try vx.setMouseMode(true);
5959-6060- // The main event loop. Vaxis provides a thread safe, blocking, buffered
6161- // queue which can serve as the primary event queue for an application
6262- while (true) {
6363- // nextEvent blocks until an event is in the queue
6464- const event = vx.nextEvent();
6565- log.debug("event: {}", .{event});
6666- // exhaustive switching ftw. Vaxis will send events if your Event
6767- // enum has the fields for those events (ie "key_press", "winsize")
6868- switch (event) {
6969- .key_press => |key| {
7070- color_idx = switch (color_idx) {
7171- 255 => 0,
7272- else => color_idx + 1,
7373- };
7474- if (key.matches('c', .{ .ctrl = true })) {
7575- break;
7676- } else if (key.matches('l', .{ .ctrl = true })) {
7777- vx.queueRefresh();
7878- } else if (key.matches('z', .{ .ctrl = true })) {
7979- try openDirVim(alloc, &vx, "examples");
8080- } else {
8181- try text_input.update(.{ .key_press = key });
8282- }
8383- },
8484-8585- // winsize events are sent to the application to ensure that all
8686- // resizes occur in the main thread. This lets us avoid expensive
8787- // locks on the screen. All applications must handle this event
8888- // unless they aren't using a screen (IE only detecting features)
8989- //
9090- // This is the only call that the core of Vaxis needs an allocator
9191- // for. The allocations are because we keep a copy of each cell to
9292- // optimize renders. When resize is called, we allocated two slices:
9393- // one for the screen, and one for our buffered screen. Each cell in
9494- // the buffered screen contains an ArrayList(u8) to be able to store
9595- // the grapheme for that cell Each cell is initialized with a size
9696- // of 1, which is sufficient for all of ASCII. Anything requiring
9797- // more than one byte will incur an allocation on the first render
9898- // after it is drawn. Thereafter, it will not allocate unless the
9999- // screen is resized
100100- .winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
101101- else => {},
102102- }
103103-104104- // vx.window() returns the root window. This window is the size of the
105105- // terminal and can spawn child windows as logical areas. Child windows
106106- // cannot draw outside of their bounds
107107- const win = vx.window();
108108-109109- // Clear the entire space because we are drawing in immediate mode.
110110- // vaxis double buffers the screen. This new frame will be compared to
111111- // the old and only updated cells will be drawn
112112- win.clear();
113113- const child = win.initChild(
114114- win.width / 2 - 20,
115115- win.height / 2 - 3,
116116- .{ .limit = 40 },
117117- .{ .limit = 3 },
118118- );
119119- // draw the text_input using a bordered window
120120- const style: vaxis.Style = .{
121121- .fg = .{ .index = color_idx },
122122- };
123123- text_input.draw(border.all(child, style));
124124-125125- // Render the screen
126126- try vx.render(tty.anyWriter());
127127- }
128128-}
129129-130130-/// Open the provided Directory in a temp Vim session, pausing the TUI.
131131-fn openDirVim(alloc: mem.Allocator, vx: anytype, path: []const u8) !void {
132132- try vx.exitAltScreen();
133133- vx.stopReadThread();
134134- var dir_look = process.Child.init(&.{ "vim", "-R", path }, alloc);
135135- _ = try dir_look.spawnAndWait();
136136- try vx.startReadThread();
137137- try vx.enterAltScreen();
138138- vx.queueRefresh();
139139-}