···15151616Vaxis uses zig `0.12.0`.
17171818-## Feature comparison
1818+## Features
19192020-| Feature | Vaxis | libvaxis | notcurses |
2121-| ------------------------------ | :---: | :------: | :-------: |
2222-| RGB | ✅ | ✅ | ✅ |
2323-| Hyperlinks | ✅ | ✅ | ❌ |
2424-| Bracketed Paste | ✅ | ✅ | ❌ |
2525-| Kitty Keyboard | ✅ | ✅ | ✅ |
2626-| Styled Underlines | ✅ | ✅ | ✅ |
2727-| Mouse Shapes (OSC 22) | ✅ | ✅ | ❌ |
2828-| System Clipboard (OSC 52) | ✅ | ✅ | ❌ |
2929-| System Notifications (OSC 9) | ✅ | ✅ | ❌ |
3030-| System Notifications (OSC 777) | ✅ | ✅ | ❌ |
3131-| Synchronized Output (DEC 2026) | ✅ | ✅ | ✅ |
3232-| Unicode Core (DEC 2027) | ✅ | ✅ | ❌ |
3333-| Color Mode Updates (DEC 2031) | ✅ | ✅ | ❌ |
3434-| Images (full/space) | ✅ | planned | ✅ |
3535-| Images (half block) | ✅ | planned | ✅ |
3636-| Images (quadrant) | ✅ | planned | ✅ |
3737-| Images (sextant) | ❌ | ❌ | ✅ |
3838-| Images (sixel) | ✅ | ❌ | ✅ |
3939-| Images (kitty) | ✅ | ✅ | ✅ |
4040-| Images (iterm2) | ❌ | ❌ | ✅ |
4141-| Video | ❌ | ❌ | ✅ |
4242-| Dank | 🆗 | 🆗 | ✅ |
2020+| Feature | libvaxis |
2121+| ------------------------------ | :------: |
2222+| RGB | ✅ |
2323+| Hyperlinks | ✅ |
2424+| Bracketed Paste | ✅ |
2525+| Kitty Keyboard | ✅ |
2626+| Styled Underlines | ✅ |
2727+| Mouse Shapes (OSC 22) | ✅ |
2828+| System Clipboard (OSC 52) | ✅ |
2929+| System Notifications (OSC 9) | ✅ |
3030+| System Notifications (OSC 777) | ✅ |
3131+| Synchronized Output (DEC 2026) | ✅ |
3232+| Unicode Core (DEC 2027) | ✅ |
3333+| Color Mode Updates (DEC 2031) | ✅ |
3434+| Images (kitty) | ✅ |
43354436## Usage
45374638[Documentation](https://rockorager.github.io/libvaxis/#vaxis.Vaxis)
47394848-The below example can be run using `zig build run 2>log`. stderr must be
4949-redirected in order to not print to the same screen.
4040+Vaxis requires three basic primitives to operate:
4141+4242+1. A TTY instance
4343+2. An instance of Vaxis
4444+3. An event loop
4545+4646+The library provides a general purpose posix TTY implementation, as well as a
4747+multi-threaded event loop implementation. Users of the library are encouraged to
4848+use the event loop of their choice. The event loop is responsible for reading
4949+the TTY, passing the read bytes to the vaxis parser, and handling events.
5050+5151+A core feature of Vaxis is it's ability to detect features via terminal queries
5252+instead of relying on a terminfo database. This requires that the event loop
5353+also handle these query responses and update the Vaxis.caps struct accordingly.
5454+See the `Loop` implementation to see how this is done if writing your own event
5555+loop.
5656+5757+## Example
50585159```zig
5260const std = @import("std");
···7684 }
7785 const alloc = gpa.allocator();
78868787+ // Initialize a tty
8888+ var tty = try vaxis.Tty.init();
8989+ defer tty.deinit();
9090+7991 // Initialize Vaxis
8092 var vx = try vaxis.init(alloc, .{});
8193 // deinit takes an optional allocator. If your program is exiting, you can
8294 // choose to pass a null allocator to save some exit time.
8383- defer vx.deinit(alloc);
9595+ defer vx.deinit(alloc, tty.anyWriter());
849685978686- var loop: vaxis.Loop(Event) = .{};
9898+ // The event loop requires an intrusive init. We create an instance with
9999+ // stable points to Vaxis and our TTY, then init the instance. Doing so
100100+ // installs a signal handler for SIGWINCH on posix TTYs
101101+ //
102102+ // This event loop is thread safe. It reads the tty in a separate thread
103103+ var loop: vaxis.Loop(Event) = .{
104104+ .tty = &tty,
105105+ .vaxis = &vaxis,
106106+ };
107107+ try loop.init();
108108+87109 // Start the read loop. This puts the terminal in raw mode and begins
88110 // reading user input
8989- try loop.run();
111111+ try loop.start();
90112 defer loop.stop();
9111392114 // Optionally enter the alternate screen
9393- try vx.enterAltScreen();
115115+ try vx.enterAltScreen(tty.anyWriter());
9411695117 // We'll adjust the color index every keypress for the border
96118 var color_idx: u8 = 0;
···100122 var text_input = TextInput.init(alloc);
101123 defer text_input.deinit();
102124103103- // Sends queries to terminal to detect certain features. This should
104104- // _always_ be called, but is left to the application to decide when
105105- try vx.queryTerminal();
125125+ // Sends queries to terminal to detect certain features. This should always
126126+ // be called after entering the alt screen, if you are using the alt screen
127127+ try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
106128107107- // The main event loop. Vaxis provides a thread safe, blocking, buffered
108108- // queue which can serve as the primary event queue for an application
109129 while (true) {
110130 // nextEvent blocks until an event is in the queue
111131 const event = loop.nextEvent();
···141161 // more than one byte will incur an allocation on the first render
142162 // after it is drawn. Thereafter, it will not allocate unless the
143163 // screen is resized
144144- .winsize => |ws| try vx.resize(alloc, ws),
164164+ .winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
145165 else => {},
146166 }
147167···175195 // Draw the text_input in the child window
176196 text_input.draw(child);
177197178178- // Render the screen
179179- try vx.render();
198198+ // Render the screen. Using a buffered writer will offer much better
199199+ // performance, but is not required
200200+ try vx.render(tty.anyWriter());
180201 }
181202}
182203```
···3131 }
3232 const alloc = gpa.allocator();
33333434- // Initialize Vaxis with our event type
3535- var vx = try vaxis.init(Event, .{});
3636- // deinit takes an optional allocator. If your program is exiting, you can
3737- // choose to pass a null allocator to save some exit time.
3838- defer vx.deinit(alloc);
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());
39394040- // Start the read loop. This puts the terminal in raw mode and begins
4141- // reading user input
4242- try vx.startReadThread();
4343- defer vx.stopReadThread();
4040+ var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
4141+ try loop.init();
44424545- // Optionally enter the alternate screen
4646- try vx.enterAltScreen();
4747- defer vx.exitAltScreen() catch {};
4343+ try loop.start();
4444+ defer loop.stop();
48454946 // We'll adjust the color index every keypress for the border
5047 var color_idx: u8 = 0;
···56535754 // Sends queries to terminal to detect certain features. This should
5855 // _always_ be called, but is left to the application to decide when
5959- try vx.queryTerminal();
5656+ try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
60576158 try vx.setMouseMode(true);
6259···7875 break;
7976 } else if (key.matches('l', .{ .ctrl = true })) {
8077 vx.queueRefresh();
8181- } else if (key.matches('n', .{ .ctrl = true })) {
8282- try vx.notify("vaxis", "hello from vaxis");
8378 } else if (key.matches('z', .{ .ctrl = true })) {
8479 try openDirVim(alloc, &vx, "examples");
8580 } else {
···10297 // more than one byte will incur an allocation on the first render
10398 // after it is drawn. Thereafter, it will not allocate unless the
10499 // screen is resized
105105- .winsize => |ws| try vx.resize(alloc, ws),
100100+ .winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
106101 else => {},
107102 }
108103···128123 text_input.draw(border.all(child, style));
129124130125 // Render the screen
131131- try vx.render();
126126+ try vx.render(tty.anyWriter());
132127 }
133128}
134129
···40404141 // Initialize Vaxis
4242 var vx = try vaxis.init(alloc, .{});
4343- defer vx.deinit(tty.anyWriter(), alloc);
4343+ defer vx.deinit(alloc, tty.anyWriter());
44444545 var loop: vaxis.Loop(Event) = .{
4646 .vaxis = &vx,
···120120 // more than one byte will incur an allocation on the first render
121121 // after it is drawn. Thereafter, it will not allocate unless the
122122 // screen is resized
123123- .winsize => |ws| try vx.resize(alloc, ws, tty.anyWriter()),
123123+ .winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
124124 else => {},
125125 }
126126