refactor(vaxis): require an io.AnyWriter for writes
All vaxis functions that write to the terminal now require an io.AnyWriter as a parameter
This commit is contained in:
parent
59abd7d7d4
commit
5f41978054
13 changed files with 294 additions and 517 deletions
97
README.md
97
README.md
|
@ -15,38 +15,46 @@ Contributions are welcome.
|
|||
|
||||
Vaxis uses zig `0.12.0`.
|
||||
|
||||
## Feature comparison
|
||||
## Features
|
||||
|
||||
| Feature | Vaxis | libvaxis | notcurses |
|
||||
| ------------------------------ | :---: | :------: | :-------: |
|
||||
| RGB | ✅ | ✅ | ✅ |
|
||||
| Hyperlinks | ✅ | ✅ | ❌ |
|
||||
| Bracketed Paste | ✅ | ✅ | ❌ |
|
||||
| Kitty Keyboard | ✅ | ✅ | ✅ |
|
||||
| Styled Underlines | ✅ | ✅ | ✅ |
|
||||
| Mouse Shapes (OSC 22) | ✅ | ✅ | ❌ |
|
||||
| System Clipboard (OSC 52) | ✅ | ✅ | ❌ |
|
||||
| System Notifications (OSC 9) | ✅ | ✅ | ❌ |
|
||||
| System Notifications (OSC 777) | ✅ | ✅ | ❌ |
|
||||
| Synchronized Output (DEC 2026) | ✅ | ✅ | ✅ |
|
||||
| Unicode Core (DEC 2027) | ✅ | ✅ | ❌ |
|
||||
| Color Mode Updates (DEC 2031) | ✅ | ✅ | ❌ |
|
||||
| Images (full/space) | ✅ | planned | ✅ |
|
||||
| Images (half block) | ✅ | planned | ✅ |
|
||||
| Images (quadrant) | ✅ | planned | ✅ |
|
||||
| Images (sextant) | ❌ | ❌ | ✅ |
|
||||
| Images (sixel) | ✅ | ❌ | ✅ |
|
||||
| Images (kitty) | ✅ | ✅ | ✅ |
|
||||
| Images (iterm2) | ❌ | ❌ | ✅ |
|
||||
| Video | ❌ | ❌ | ✅ |
|
||||
| Dank | 🆗 | 🆗 | ✅ |
|
||||
| Feature | libvaxis |
|
||||
| ------------------------------ | :------: |
|
||||
| RGB | ✅ |
|
||||
| Hyperlinks | ✅ |
|
||||
| Bracketed Paste | ✅ |
|
||||
| Kitty Keyboard | ✅ |
|
||||
| Styled Underlines | ✅ |
|
||||
| Mouse Shapes (OSC 22) | ✅ |
|
||||
| System Clipboard (OSC 52) | ✅ |
|
||||
| System Notifications (OSC 9) | ✅ |
|
||||
| System Notifications (OSC 777) | ✅ |
|
||||
| Synchronized Output (DEC 2026) | ✅ |
|
||||
| Unicode Core (DEC 2027) | ✅ |
|
||||
| Color Mode Updates (DEC 2031) | ✅ |
|
||||
| Images (kitty) | ✅ |
|
||||
|
||||
## Usage
|
||||
|
||||
[Documentation](https://rockorager.github.io/libvaxis/#vaxis.Vaxis)
|
||||
|
||||
The below example can be run using `zig build run 2>log`. stderr must be
|
||||
redirected in order to not print to the same screen.
|
||||
Vaxis requires three basic primitives to operate:
|
||||
|
||||
1. A TTY instance
|
||||
2. An instance of Vaxis
|
||||
3. An event loop
|
||||
|
||||
The library provides a general purpose posix TTY implementation, as well as a
|
||||
multi-threaded event loop implementation. Users of the library are encouraged to
|
||||
use the event loop of their choice. The event loop is responsible for reading
|
||||
the TTY, passing the read bytes to the vaxis parser, and handling events.
|
||||
|
||||
A core feature of Vaxis is it's ability to detect features via terminal queries
|
||||
instead of relying on a terminfo database. This requires that the event loop
|
||||
also handle these query responses and update the Vaxis.caps struct accordingly.
|
||||
See the `Loop` implementation to see how this is done if writing your own event
|
||||
loop.
|
||||
|
||||
## Example
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
|
@ -76,21 +84,35 @@ pub fn main() !void {
|
|||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
// Initialize a tty
|
||||
var tty = try vaxis.Tty.init();
|
||||
defer tty.deinit();
|
||||
|
||||
// Initialize Vaxis
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
// deinit takes an optional allocator. If your program is exiting, you can
|
||||
// choose to pass a null allocator to save some exit time.
|
||||
defer vx.deinit(alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{};
|
||||
// The event loop requires an intrusive init. We create an instance with
|
||||
// stable points to Vaxis and our TTY, then init the instance. Doing so
|
||||
// installs a signal handler for SIGWINCH on posix TTYs
|
||||
//
|
||||
// This event loop is thread safe. It reads the tty in a separate thread
|
||||
var loop: vaxis.Loop(Event) = .{
|
||||
.tty = &tty,
|
||||
.vaxis = &vaxis,
|
||||
};
|
||||
try loop.init();
|
||||
|
||||
// Start the read loop. This puts the terminal in raw mode and begins
|
||||
// reading user input
|
||||
try loop.run();
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
|
||||
// Optionally enter the alternate screen
|
||||
try vx.enterAltScreen();
|
||||
try vx.enterAltScreen(tty.anyWriter());
|
||||
|
||||
// We'll adjust the color index every keypress for the border
|
||||
var color_idx: u8 = 0;
|
||||
|
@ -100,12 +122,10 @@ pub fn main() !void {
|
|||
var text_input = TextInput.init(alloc);
|
||||
defer text_input.deinit();
|
||||
|
||||
// Sends queries to terminal to detect certain features. This should
|
||||
// _always_ be called, but is left to the application to decide when
|
||||
try vx.queryTerminal();
|
||||
// Sends queries to terminal to detect certain features. This should always
|
||||
// be called after entering the alt screen, if you are using the alt screen
|
||||
try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
|
||||
|
||||
// The main event loop. Vaxis provides a thread safe, blocking, buffered
|
||||
// queue which can serve as the primary event queue for an application
|
||||
while (true) {
|
||||
// nextEvent blocks until an event is in the queue
|
||||
const event = loop.nextEvent();
|
||||
|
@ -141,7 +161,7 @@ pub fn main() !void {
|
|||
// more than one byte will incur an allocation on the first render
|
||||
// after it is drawn. Thereafter, it will not allocate unless the
|
||||
// screen is resized
|
||||
.winsize => |ws| try vx.resize(alloc, ws),
|
||||
.winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
|
||||
else => {},
|
||||
}
|
||||
|
||||
|
@ -175,8 +195,9 @@ pub fn main() !void {
|
|||
// Draw the text_input in the child window
|
||||
text_input.draw(child);
|
||||
|
||||
// Render the screen
|
||||
try vx.render();
|
||||
// Render the screen. Using a buffered writer will offer much better
|
||||
// performance, but is not required
|
||||
try vx.render(tty.anyWriter());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -14,15 +14,19 @@ pub fn main() !void {
|
|||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
var tty = try vaxis.Tty.init();
|
||||
defer tty.deinit();
|
||||
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
|
||||
try loop.init();
|
||||
|
||||
try loop.run();
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
|
||||
try vx.queryTerminal();
|
||||
try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
|
||||
|
||||
var text_input = TextInput.init(alloc, &vx.unicode);
|
||||
defer text_input.deinit();
|
||||
|
@ -70,7 +74,7 @@ pub fn main() !void {
|
|||
}
|
||||
},
|
||||
.winsize => |ws| {
|
||||
try vx.resize(alloc, ws);
|
||||
try vx.resize(alloc, tty.anyWriter(), ws);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
@ -91,7 +95,7 @@ pub fn main() !void {
|
|||
_ = try win.print(&seg, .{ .row_offset = j + 1 });
|
||||
}
|
||||
}
|
||||
try vx.render();
|
||||
try vx.render(tty.anyWriter());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,24 +18,27 @@ pub fn main() !void {
|
|||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
var tty = try vaxis.Tty.init();
|
||||
defer tty.deinit();
|
||||
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
|
||||
try loop.init();
|
||||
|
||||
try loop.run();
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
|
||||
try vx.enterAltScreen();
|
||||
|
||||
try vx.queryTerminal();
|
||||
try vx.enterAltScreen(tty.anyWriter());
|
||||
try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
|
||||
|
||||
const imgs = [_]vaxis.Image{
|
||||
try vx.loadImage(alloc, .{ .path = "examples/zig.png" }),
|
||||
try vx.loadImage(alloc, .{ .path = "examples/vaxis.png" }),
|
||||
try vx.loadImage(alloc, tty.anyWriter(), .{ .path = "examples/zig.png" }),
|
||||
try vx.loadImage(alloc, tty.anyWriter(), .{ .path = "examples/vaxis.png" }),
|
||||
};
|
||||
defer vx.freeImage(imgs[0].id);
|
||||
defer vx.freeImage(imgs[1].id);
|
||||
defer vx.freeImage(tty.anyWriter(), imgs[0].id);
|
||||
defer vx.freeImage(tty.anyWriter(), imgs[1].id);
|
||||
|
||||
var n: usize = 0;
|
||||
|
||||
|
@ -54,7 +57,7 @@ pub fn main() !void {
|
|||
else if (key.matches('k', .{}))
|
||||
clip_y -|= 1;
|
||||
},
|
||||
.winsize => |ws| try vx.resize(alloc, ws),
|
||||
.winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
|
||||
}
|
||||
|
||||
n = (n + 1) % imgs.len;
|
||||
|
@ -68,6 +71,6 @@ pub fn main() !void {
|
|||
.y = clip_y,
|
||||
} });
|
||||
|
||||
try vx.render();
|
||||
try vx.render(tty.anyWriter());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,19 +14,20 @@ pub fn main() !void {
|
|||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
// Initialize Vaxis
|
||||
var tty = try vaxis.Tty.init();
|
||||
defer tty.deinit();
|
||||
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
|
||||
try loop.init();
|
||||
|
||||
// Start the read loop. This puts the terminal in raw mode and begins
|
||||
// reading user input
|
||||
try loop.run();
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
|
||||
// Optionally enter the alternate screen
|
||||
try vx.enterAltScreen();
|
||||
try vx.enterAltScreen(tty.anyWriter());
|
||||
|
||||
// We'll adjust the color index every keypress
|
||||
var color_idx: u8 = 0;
|
||||
|
@ -51,7 +52,7 @@ pub fn main() !void {
|
|||
}
|
||||
},
|
||||
.winsize => |ws| {
|
||||
try vx.resize(alloc, ws);
|
||||
try vx.resize(alloc, tty.anyWriter(), ws);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ pub fn main() !void {
|
|||
child.writeCell(i, 0, cell);
|
||||
}
|
||||
// Render the screen
|
||||
try vx.render();
|
||||
try vx.render(tty.anyWriter());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,18 +23,22 @@ pub fn main() !void {
|
|||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
var tty = try vaxis.Tty.init();
|
||||
defer tty.deinit();
|
||||
|
||||
// Initialize Vaxis
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
|
||||
try loop.init();
|
||||
|
||||
try loop.run();
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
|
||||
// Optionally enter the alternate screen
|
||||
try vx.enterAltScreen();
|
||||
try vx.queryTerminal();
|
||||
// try vx.enterAltScreen(tty.anyWriter());
|
||||
try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
|
||||
|
||||
var nvim = try vaxis.widgets.nvim.Nvim(Event).init(alloc, &loop);
|
||||
try nvim.spawn();
|
||||
|
@ -53,7 +57,7 @@ pub fn main() !void {
|
|||
try nvim.update(.{ .key_press = key });
|
||||
},
|
||||
.winsize => |ws| {
|
||||
try vx.resize(alloc, ws);
|
||||
try vx.resize(alloc, tty.anyWriter(), ws);
|
||||
},
|
||||
.nvim => |nvim_event| {
|
||||
switch (nvim_event) {
|
||||
|
@ -74,6 +78,6 @@ pub fn main() !void {
|
|||
},
|
||||
);
|
||||
try nvim.draw(child);
|
||||
try vx.render();
|
||||
try vx.render(tty.anyWriter());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
const std = @import("std");
|
||||
const vaxis = @import("vaxis");
|
||||
const Cell = vaxis.Cell;
|
||||
|
||||
const log = std.log.scoped(.main);
|
||||
|
||||
const Event = union(enum) {
|
||||
winsize: vaxis.Winsize,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const alloc = gpa.allocator();
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
|
||||
try loop.run();
|
||||
defer loop.stop();
|
||||
try vx.enterAltScreen();
|
||||
try vx.queryTerminal();
|
||||
|
||||
while (true) {
|
||||
const event = loop.nextEvent();
|
||||
switch (event) {
|
||||
.winsize => |ws| {
|
||||
try vx.resize(alloc, ws);
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const timer_start = std.time.microTimestamp();
|
||||
var iter: usize = 0;
|
||||
while (iter < 10_000) : (iter += 1) {
|
||||
const win = vx.window();
|
||||
const child = win.initChild(0, 0, .{ .limit = 20 }, .{ .limit = 20 });
|
||||
win.clear();
|
||||
var row: usize = 0;
|
||||
while (row < child.height) : (row += 1) {
|
||||
var col: usize = 0;
|
||||
while (col < child.width) : (col += 1) {
|
||||
child.writeCell(col, row, .{
|
||||
.char = .{
|
||||
.grapheme = " ",
|
||||
.width = 1,
|
||||
},
|
||||
.style = .{
|
||||
.bg = .{ .index = @truncate(col + iter) },
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
try vx.render();
|
||||
}
|
||||
try vx.exitAltScreen();
|
||||
const took = std.time.microTimestamp() - timer_start;
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
try stdout.print("\r\ntook {d}ms to render 10,000 times\r\n", .{@divTrunc(took, std.time.us_per_ms)});
|
||||
}
|
|
@ -31,20 +31,17 @@ pub fn main() !void {
|
|||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
// Initialize Vaxis with our event type
|
||||
var vx = try vaxis.init(Event, .{});
|
||||
// deinit takes an optional allocator. If your program is exiting, you can
|
||||
// choose to pass a null allocator to save some exit time.
|
||||
defer vx.deinit(alloc);
|
||||
var tty = try vaxis.Tty.init();
|
||||
defer tty.deinit();
|
||||
|
||||
// Start the read loop. This puts the terminal in raw mode and begins
|
||||
// reading user input
|
||||
try vx.startReadThread();
|
||||
defer vx.stopReadThread();
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
// Optionally enter the alternate screen
|
||||
try vx.enterAltScreen();
|
||||
defer vx.exitAltScreen() catch {};
|
||||
var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
|
||||
try loop.init();
|
||||
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
|
||||
// We'll adjust the color index every keypress for the border
|
||||
var color_idx: u8 = 0;
|
||||
|
@ -56,7 +53,7 @@ pub fn main() !void {
|
|||
|
||||
// Sends queries to terminal to detect certain features. This should
|
||||
// _always_ be called, but is left to the application to decide when
|
||||
try vx.queryTerminal();
|
||||
try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
|
||||
|
||||
try vx.setMouseMode(true);
|
||||
|
||||
|
@ -78,8 +75,6 @@ pub fn main() !void {
|
|||
break;
|
||||
} else if (key.matches('l', .{ .ctrl = true })) {
|
||||
vx.queueRefresh();
|
||||
} else if (key.matches('n', .{ .ctrl = true })) {
|
||||
try vx.notify("vaxis", "hello from vaxis");
|
||||
} else if (key.matches('z', .{ .ctrl = true })) {
|
||||
try openDirVim(alloc, &vx, "examples");
|
||||
} else {
|
||||
|
@ -102,7 +97,7 @@ pub fn main() !void {
|
|||
// more than one byte will incur an allocation on the first render
|
||||
// after it is drawn. Thereafter, it will not allocate unless the
|
||||
// screen is resized
|
||||
.winsize => |ws| try vx.resize(alloc, ws),
|
||||
.winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
|
||||
else => {},
|
||||
}
|
||||
|
||||
|
@ -128,7 +123,7 @@ pub fn main() !void {
|
|||
text_input.draw(border.all(child, style));
|
||||
|
||||
// Render the screen
|
||||
try vx.render();
|
||||
try vx.render(tty.anyWriter());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
const std = @import("std");
|
||||
const vaxis = @import("vaxis");
|
||||
const Cell = vaxis.Cell;
|
||||
const TextInput = vaxis.widgets.TextInput;
|
||||
const border = vaxis.widgets.border;
|
||||
|
||||
const log = std.log.scoped(.main);
|
||||
|
||||
const Event = union(enum) {
|
||||
key_press: vaxis.Key,
|
||||
winsize: vaxis.Winsize,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer {
|
||||
const deinit_status = gpa.deinit();
|
||||
//fail test; can't try in defer as defer is executed after we return
|
||||
if (deinit_status == .leak) {
|
||||
log.err("memory leak", .{});
|
||||
}
|
||||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
var line: ?[]const u8 = null;
|
||||
defer {
|
||||
// do this in defer so that vaxis cleans up terminal state before we
|
||||
// print to stdout
|
||||
if (line) |_| {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("\n{s}\n", .{line.?}) catch {};
|
||||
alloc.free(line.?);
|
||||
}
|
||||
}
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
try loop.run();
|
||||
defer loop.stop();
|
||||
|
||||
var text_input = TextInput.init(alloc, &vx.unicode);
|
||||
defer text_input.deinit();
|
||||
|
||||
try vx.queryTerminal();
|
||||
|
||||
const prompt: vaxis.Segment = .{ .text = "$ " };
|
||||
|
||||
while (true) {
|
||||
const event = loop.nextEvent();
|
||||
switch (event) {
|
||||
.key_press => |key| {
|
||||
if (key.matches('c', .{ .ctrl = true })) {
|
||||
break;
|
||||
} else if (key.matches(vaxis.Key.enter, .{})) {
|
||||
line = try text_input.toOwnedSlice();
|
||||
text_input.clearAndFree();
|
||||
break;
|
||||
} else {
|
||||
try text_input.update(.{ .key_press = key });
|
||||
}
|
||||
},
|
||||
.winsize => |ws| try vx.resize(alloc, ws),
|
||||
}
|
||||
|
||||
const win = vx.window();
|
||||
|
||||
win.clear();
|
||||
_ = try win.printSegment(prompt, .{});
|
||||
|
||||
const input_win = win.child(.{ .x_off = 2 });
|
||||
text_input.draw(input_win);
|
||||
try vx.render();
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
const std = @import("std");
|
||||
const vaxis = @import("vaxis");
|
||||
const Cell = vaxis.Cell;
|
||||
const TextInput = vaxis.widgets.TextInput;
|
||||
|
||||
const log = std.log.scoped(.main);
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer {
|
||||
const deinit_status = gpa.deinit();
|
||||
if (deinit_status == .leak) {
|
||||
log.err("memory leak", .{});
|
||||
}
|
||||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
|
||||
try loop.run();
|
||||
defer loop.stop();
|
||||
|
||||
try vx.queryTerminal();
|
||||
|
||||
var text_input = TextInput.init(alloc, &vx.unicode);
|
||||
defer text_input.deinit();
|
||||
|
||||
var selected_option: ?usize = null;
|
||||
|
||||
const options = [_][]const u8{
|
||||
"yes",
|
||||
"no",
|
||||
};
|
||||
|
||||
// The main event loop. Vaxis provides a thread safe, blocking, buffered
|
||||
// queue which can serve as the primary event queue for an application
|
||||
while (true) {
|
||||
// nextEvent blocks until an event is in the queue
|
||||
const event = loop.nextEvent();
|
||||
// exhaustive switching ftw. Vaxis will send events if your Event
|
||||
// enum has the fields for those events (ie "key_press", "winsize")
|
||||
switch (event) {
|
||||
.key_press => |key| {
|
||||
if (key.codepoint == 'c' and key.mods.ctrl) {
|
||||
break;
|
||||
} else if (key.matches(vaxis.Key.tab, .{})) {
|
||||
if (selected_option == null) {
|
||||
selected_option = 0;
|
||||
} else {
|
||||
selected_option.? = @min(options.len - 1, selected_option.? + 1);
|
||||
}
|
||||
} else if (key.matches(vaxis.Key.tab, .{ .shift = true })) {
|
||||
if (selected_option == null) {
|
||||
selected_option = 0;
|
||||
} else {
|
||||
selected_option.? = selected_option.? -| 1;
|
||||
}
|
||||
} else if (key.matches(vaxis.Key.enter, .{})) {
|
||||
if (selected_option) |i| {
|
||||
log.err("enter", .{});
|
||||
try text_input.insertSliceAtCursor(options[i]);
|
||||
selected_option = null;
|
||||
}
|
||||
} else {
|
||||
if (selected_option == null)
|
||||
try text_input.update(.{ .key_press = key });
|
||||
}
|
||||
},
|
||||
.winsize => |ws| {
|
||||
try vx.resize(alloc, ws);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
const win = vx.window();
|
||||
win.clear();
|
||||
|
||||
const right_win = win.child(.{
|
||||
.x_off = win.width - 4,
|
||||
});
|
||||
const left_win = win.child(.{
|
||||
.width = .{ .limit = 8 },
|
||||
});
|
||||
var right_prompt = [_]vaxis.Segment{
|
||||
.{ .text = "👩🚀🏳️🌈" },
|
||||
};
|
||||
var left_prompt = [_]vaxis.Segment{
|
||||
.{ .text = "👩🚀🏳️🌈~ ", .style = .{ .fg = .{ .index = 4 } } },
|
||||
.{ .text = "", .style = .{ .fg = .{ .index = 5 } } },
|
||||
};
|
||||
_ = try right_win.print(&right_prompt, .{});
|
||||
_ = try left_win.print(&left_prompt, .{});
|
||||
|
||||
const input_win = win.child(.{
|
||||
.x_off = 8,
|
||||
.width = .{ .limit = win.width - 12 },
|
||||
});
|
||||
|
||||
text_input.draw(input_win);
|
||||
|
||||
if (selected_option) |i| {
|
||||
win.hideCursor();
|
||||
for (options, 0..) |opt, j| {
|
||||
log.err("i = {d}, j = {d}, opt = {s}", .{ i, j, opt });
|
||||
var seg = [_]vaxis.Segment{.{
|
||||
.text = opt,
|
||||
.style = if (j == i) .{ .reverse = true } else .{},
|
||||
}};
|
||||
_ = try win.print(&seg, .{ .row_offset = j + 1 });
|
||||
}
|
||||
}
|
||||
try vx.render();
|
||||
}
|
||||
}
|
||||
|
||||
// Our Event. This can contain internal events as well as Vaxis events.
|
||||
// Internal events can be posted into the same queue as vaxis events to allow
|
||||
// for a single event loop with exhaustive switching. Booya
|
||||
const Event = union(enum) {
|
||||
key_press: vaxis.Key,
|
||||
winsize: vaxis.Winsize,
|
||||
focus_in,
|
||||
foo: u8,
|
||||
};
|
|
@ -24,18 +24,20 @@ pub fn main() !void {
|
|||
const user_list = std.ArrayList(User).fromOwnedSlice(alloc, users_buf);
|
||||
defer user_list.deinit();
|
||||
|
||||
var tty = try vaxis.Tty.init();
|
||||
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
var loop: vaxis.Loop(union(enum) {
|
||||
key_press: vaxis.Key,
|
||||
winsize: vaxis.Winsize,
|
||||
}) = .{ .vaxis = &vx };
|
||||
}) = .{ .tty = &tty, .vaxis = &vx };
|
||||
|
||||
try loop.run();
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
try vx.enterAltScreen();
|
||||
try vx.queryTerminal();
|
||||
try vx.enterAltScreen(tty.anyWriter());
|
||||
try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
|
||||
|
||||
const logo =
|
||||
\\░█░█░█▀█░█░█░▀█▀░█▀▀░░░▀█▀░█▀█░█▀▄░█░░░█▀▀░
|
||||
|
@ -145,7 +147,7 @@ pub fn main() !void {
|
|||
}
|
||||
moving = false;
|
||||
},
|
||||
.winsize => |ws| try vx.resize(alloc, ws),
|
||||
.winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
|
||||
//else => {},
|
||||
}
|
||||
|
||||
|
@ -203,7 +205,7 @@ pub fn main() !void {
|
|||
cmd_input.draw(bottom_bar);
|
||||
|
||||
// Render the screen
|
||||
try vx.render();
|
||||
try vx.render(tty.anyWriter());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ pub fn main() !void {
|
|||
|
||||
// Initialize Vaxis
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(tty.anyWriter(), alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{
|
||||
.vaxis = &vx,
|
||||
|
@ -120,7 +120,7 @@ pub fn main() !void {
|
|||
// more than one byte will incur an allocation on the first render
|
||||
// after it is drawn. Thereafter, it will not allocate unless the
|
||||
// screen is resized
|
||||
.winsize => |ws| try vx.resize(alloc, ws, tty.anyWriter()),
|
||||
.winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
|
||||
else => {},
|
||||
}
|
||||
|
||||
|
|
|
@ -18,16 +18,18 @@ pub fn main() !void {
|
|||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
var tty = try vaxis.Tty.init();
|
||||
var vx = try vaxis.init(alloc, .{});
|
||||
defer vx.deinit(alloc);
|
||||
defer vx.deinit(alloc, tty.anyWriter());
|
||||
|
||||
var loop: vaxis.Loop(Event) = .{ .vaxis = &vx };
|
||||
var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
|
||||
try loop.init();
|
||||
|
||||
try loop.run();
|
||||
try loop.start();
|
||||
defer loop.stop();
|
||||
|
||||
try vx.enterAltScreen();
|
||||
try vx.queryTerminal();
|
||||
try vx.enterAltScreen(tty.anyWriter());
|
||||
try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);
|
||||
|
||||
const lower_limit = 30;
|
||||
var color_idx: u8 = lower_limit;
|
||||
|
@ -42,7 +44,7 @@ pub fn main() !void {
|
|||
switch (event) {
|
||||
.key_press => |key| if (key.matches('c', .{ .ctrl = true })) return,
|
||||
.winsize => |ws| {
|
||||
try vx.resize(alloc, ws);
|
||||
try vx.resize(alloc, tty.anyWriter(), ws);
|
||||
break;
|
||||
},
|
||||
}
|
||||
|
@ -52,7 +54,7 @@ pub fn main() !void {
|
|||
while (loop.tryEvent()) |event| {
|
||||
switch (event) {
|
||||
.key_press => |key| if (key.matches('c', .{ .ctrl = true })) return,
|
||||
.winsize => |ws| try vx.resize(alloc, ws),
|
||||
.winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +69,7 @@ pub fn main() !void {
|
|||
};
|
||||
const center = vaxis.widgets.alignment.center(win, 28, 4);
|
||||
_ = try center.printSegment(segment, .{ .wrap = .grapheme });
|
||||
try vx.render();
|
||||
try vx.render(tty.anyWriter());
|
||||
std.time.sleep(8 * std.time.ns_per_ms);
|
||||
switch (dir) {
|
||||
.up => {
|
||||
|
|
305
src/Vaxis.zig
305
src/Vaxis.zig
|
@ -9,7 +9,6 @@ const InternalScreen = @import("InternalScreen.zig");
|
|||
const Key = @import("Key.zig");
|
||||
const Mouse = @import("Mouse.zig");
|
||||
const Screen = @import("Screen.zig");
|
||||
const tty = @import("tty.zig");
|
||||
const Unicode = @import("Unicode.zig");
|
||||
const Window = @import("Window.zig");
|
||||
|
||||
|
@ -18,7 +17,7 @@ const Hyperlink = Cell.Hyperlink;
|
|||
const KittyFlags = Key.KittyFlags;
|
||||
const Shape = Mouse.Shape;
|
||||
const Style = Cell.Style;
|
||||
const Winsize = tty.Winsize;
|
||||
const Winsize = @import("tty.zig").Winsize;
|
||||
|
||||
const ctlseqs = @import("ctlseqs.zig");
|
||||
const gwidth = @import("gwidth.zig");
|
||||
|
@ -57,6 +56,7 @@ opts: Options = .{},
|
|||
/// if we should redraw the entire screen on the next render
|
||||
refresh: bool = false,
|
||||
|
||||
// FIXME: remove before committing
|
||||
/// blocks the main thread until a DA1 query has been received, or the
|
||||
/// futex times out
|
||||
query_futex: atomic.Value(u32) = atomic.Value(u32).init(0),
|
||||
|
@ -106,40 +106,49 @@ pub fn init(alloc: std.mem.Allocator, opts: Options) !Vaxis {
|
|||
/// passed, this will free resources associated with Vaxis. This is left as an
|
||||
/// optional so applications can choose to not free resources when the
|
||||
/// application will be exiting anyways
|
||||
pub fn deinit(self: *Vaxis, writer: AnyWriter, alloc: ?std.mem.Allocator) void {
|
||||
self.resetState(writer) catch {};
|
||||
pub fn deinit(self: *Vaxis, alloc: ?std.mem.Allocator, tty: AnyWriter) void {
|
||||
self.resetState(tty) catch {};
|
||||
|
||||
// always show the cursor on exit
|
||||
writer.writeAll(ctlseqs.show_cursor) catch {};
|
||||
tty.writeAll(ctlseqs.show_cursor) catch {};
|
||||
if (alloc) |a| {
|
||||
self.screen.deinit(a);
|
||||
self.screen_last.deinit(a);
|
||||
}
|
||||
if (self.renders > 0) {
|
||||
const tpr = @divTrunc(self.render_dur, self.renders);
|
||||
log.debug("total renders = {d}", .{self.renders});
|
||||
log.debug("microseconds per render = {d}", .{tpr});
|
||||
log.debug("total renders = {d}\r", .{self.renders});
|
||||
log.debug("microseconds per render = {d}\r", .{tpr});
|
||||
}
|
||||
self.unicode.deinit();
|
||||
}
|
||||
|
||||
/// resets enabled features
|
||||
pub fn resetState(self: *Vaxis, writer: AnyWriter) !void {
|
||||
/// resets enabled features, sends cursor to home and clears below cursor
|
||||
pub fn resetState(self: *Vaxis, tty: AnyWriter) !void {
|
||||
if (self.state.kitty_keyboard) {
|
||||
try writer.writeAll(ctlseqs.csi_u_pop);
|
||||
try tty.writeAll(ctlseqs.csi_u_pop);
|
||||
self.state.kitty_keyboard = false;
|
||||
}
|
||||
if (self.state.mouse) {
|
||||
try self.setMouseMode(writer, false);
|
||||
try self.setMouseMode(tty, false);
|
||||
}
|
||||
if (self.state.bracketed_paste) {
|
||||
try self.setBracketedPaste(writer, false);
|
||||
try self.setBracketedPaste(tty, false);
|
||||
}
|
||||
if (self.state.alt_screen) {
|
||||
try self.exitAltScreen(writer);
|
||||
try tty.writeAll(ctlseqs.home);
|
||||
try tty.writeAll(ctlseqs.erase_below_cursor);
|
||||
try self.exitAltScreen(tty);
|
||||
} else {
|
||||
try tty.writeByte('\r');
|
||||
var i: usize = 0;
|
||||
while (i < self.state.cursor.row) : (i += 1) {
|
||||
try tty.writeAll(ctlseqs.ri);
|
||||
}
|
||||
try tty.writeAll(ctlseqs.erase_below_cursor);
|
||||
}
|
||||
if (self.state.color_scheme_updates) {
|
||||
try writer.writeAll(ctlseqs.color_scheme_reset);
|
||||
try tty.writeAll(ctlseqs.color_scheme_reset);
|
||||
self.state.color_scheme_updates = false;
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +157,12 @@ pub fn resetState(self: *Vaxis, writer: AnyWriter) !void {
|
|||
/// required to display the screen (ie width x height). Any previous screen is
|
||||
/// freed when resizing. The cursor will be sent to it's home position and a
|
||||
/// hardware clear-below-cursor will be sent
|
||||
pub fn resize(self: *Vaxis, alloc: std.mem.Allocator, winsize: Winsize, writer: AnyWriter) !void {
|
||||
pub fn resize(
|
||||
self: *Vaxis,
|
||||
alloc: std.mem.Allocator,
|
||||
tty: AnyWriter,
|
||||
winsize: Winsize,
|
||||
) !void {
|
||||
log.debug("resizing screen: width={d} height={d}", .{ winsize.cols, winsize.rows });
|
||||
self.screen.deinit(alloc);
|
||||
self.screen = try Screen.init(alloc, winsize, &self.unicode);
|
||||
|
@ -159,15 +173,15 @@ pub fn resize(self: *Vaxis, alloc: std.mem.Allocator, winsize: Winsize, writer:
|
|||
self.screen_last.deinit(alloc);
|
||||
self.screen_last = try InternalScreen.init(alloc, winsize.cols, winsize.rows);
|
||||
if (self.state.alt_screen)
|
||||
try writer.writeAll(ctlseqs.home)
|
||||
try tty.writeAll(ctlseqs.home)
|
||||
else {
|
||||
try writer.writeByte('\r');
|
||||
try tty.writeByte('\r');
|
||||
var i: usize = 0;
|
||||
while (i < self.state.cursor.row) : (i += 1) {
|
||||
try writer.writeAll(ctlseqs.ri);
|
||||
try tty.writeAll(ctlseqs.ri);
|
||||
}
|
||||
}
|
||||
try writer.writeAll(ctlseqs.erase_below_cursor);
|
||||
try tty.writeAll(ctlseqs.erase_below_cursor);
|
||||
}
|
||||
|
||||
/// returns a Window comprising of the entire terminal screen
|
||||
|
@ -183,33 +197,34 @@ pub fn window(self: *Vaxis) Window {
|
|||
|
||||
/// enter the alternate screen. The alternate screen will automatically
|
||||
/// be exited if calling deinit while in the alt screen
|
||||
pub fn enterAltScreen(self: *Vaxis, writer: AnyWriter) !void {
|
||||
try writer.writeAll(ctlseqs.smcup);
|
||||
pub fn enterAltScreen(self: *Vaxis, tty: AnyWriter) !void {
|
||||
try tty.writeAll(ctlseqs.smcup);
|
||||
self.state.alt_screen = true;
|
||||
}
|
||||
|
||||
/// exit the alternate screen
|
||||
pub fn exitAltScreen(self: *Vaxis, writer: AnyWriter) !void {
|
||||
try writer.writeAll(ctlseqs.rmcup);
|
||||
pub fn exitAltScreen(self: *Vaxis, tty: AnyWriter) !void {
|
||||
try tty.writeAll(ctlseqs.rmcup);
|
||||
self.state.alt_screen = false;
|
||||
}
|
||||
|
||||
/// write queries to the terminal to determine capabilities. Individual
|
||||
/// capabilities will be delivered to the client and possibly intercepted by
|
||||
/// Vaxis to enable features
|
||||
pub fn queryTerminal(self: *Vaxis) !void {
|
||||
try self.queryTerminalSend();
|
||||
|
||||
/// Vaxis to enable features.
|
||||
///
|
||||
/// This call will block until Vaxis.query_futex is woken up, or the timeout.
|
||||
/// Event loops can wake up this futex when cap_da1 is received
|
||||
pub fn queryTerminal(self: *Vaxis, tty: AnyWriter, timeout_ns: u64) !void {
|
||||
try self.queryTerminalSend(tty);
|
||||
// 1 second timeout
|
||||
std.Thread.Futex.timedWait(&self.query_futex, 0, 1 * std.time.ns_per_s) catch {};
|
||||
|
||||
try self.enableDetectedFeatures();
|
||||
std.Thread.Futex.timedWait(&self.query_futex, 0, timeout_ns) catch {};
|
||||
try self.enableDetectedFeatures(tty);
|
||||
}
|
||||
|
||||
/// write queries to the terminal to determine capabilities. This function
|
||||
/// is only for use with a custom main loop. Call Vaxis.queryTerminal() if
|
||||
/// you are using Loop.run()
|
||||
pub fn queryTerminalSend(_: Vaxis, writer: AnyWriter) !void {
|
||||
pub fn queryTerminalSend(_: Vaxis, tty: AnyWriter) !void {
|
||||
|
||||
// TODO: re-enable this
|
||||
// const colorterm = std.posix.getenv("COLORTERM") orelse "";
|
||||
|
@ -221,30 +236,24 @@ pub fn queryTerminalSend(_: Vaxis, writer: AnyWriter) !void {
|
|||
// }
|
||||
// }
|
||||
|
||||
// TODO: XTGETTCAP queries ("RGB", "Smulx")
|
||||
// TODO: decide if we actually want to query for focus and sync. It
|
||||
// doesn't hurt to blindly use them
|
||||
// _ = try tty.write(ctlseqs.decrqm_focus);
|
||||
// _ = try tty.write(ctlseqs.decrqm_sync);
|
||||
try writer.writeAll(ctlseqs.decrqm_sgr_pixels);
|
||||
try writer.writeAll(ctlseqs.decrqm_unicode);
|
||||
try writer.writeAll(ctlseqs.decrqm_color_scheme);
|
||||
// TODO: XTVERSION has a DCS response. uncomment when we can parse
|
||||
// that
|
||||
// _ = try tty.write(ctlseqs.xtversion);
|
||||
try writer.writeAll(ctlseqs.csi_u_query);
|
||||
try writer.writeAll(ctlseqs.kitty_graphics_query);
|
||||
// TODO: sixel geometry query interferes with F4 keys.
|
||||
// _ = try tty.write(ctlseqs.sixel_geometry_query);
|
||||
|
||||
// TODO: XTGETTCAP queries ("RGB", "Smulx")
|
||||
|
||||
try writer.writeAll(ctlseqs.primary_device_attrs);
|
||||
try tty.writeAll(ctlseqs.decrqm_sgr_pixels ++
|
||||
ctlseqs.decrqm_unicode ++
|
||||
ctlseqs.decrqm_color_scheme ++
|
||||
ctlseqs.xtversion ++
|
||||
ctlseqs.csi_u_query ++
|
||||
ctlseqs.kitty_graphics_query ++
|
||||
ctlseqs.primary_device_attrs);
|
||||
}
|
||||
|
||||
/// Enable features detected by responses to queryTerminal. This function
|
||||
/// is only for use with a custom main loop. Call Vaxis.queryTerminal() if
|
||||
/// you are using Loop.run()
|
||||
pub fn enableDetectedFeatures(self: *Vaxis) !void {
|
||||
pub fn enableDetectedFeatures(self: *Vaxis, tty: AnyWriter) !void {
|
||||
// Apply any environment variables
|
||||
if (std.posix.getenv("ASCIINEMA_REC")) |_|
|
||||
self.sgr = .legacy;
|
||||
|
@ -263,10 +272,10 @@ pub fn enableDetectedFeatures(self: *Vaxis) !void {
|
|||
|
||||
// enable detected features
|
||||
if (self.caps.kitty_keyboard) {
|
||||
try self.enableKittyKeyboard(self.opts.kitty_keyboard_flags);
|
||||
try self.enableKittyKeyboard(tty, self.opts.kitty_keyboard_flags);
|
||||
}
|
||||
if (self.caps.unicode == .unicode) {
|
||||
_ = try tty.write(ctlseqs.unicode_set);
|
||||
try tty.writeAll(ctlseqs.unicode_set);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +285,7 @@ pub fn queueRefresh(self: *Vaxis) void {
|
|||
}
|
||||
|
||||
/// draws the screen to the terminal
|
||||
pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
||||
pub fn render(self: *Vaxis, tty: AnyWriter) !void {
|
||||
self.renders += 1;
|
||||
self.render_timer.reset();
|
||||
defer {
|
||||
|
@ -289,24 +298,21 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
// TODO: optimize sync so we only sync _when we have changes_. This
|
||||
// requires a smarter buffered writer, we'll probably have to write
|
||||
// our own
|
||||
try writer.writeAll(ctlseqs.sync_set);
|
||||
defer writer.writeAll(ctlseqs.sync_reset) catch {};
|
||||
try tty.writeAll(ctlseqs.sync_set);
|
||||
defer tty.writeAll(ctlseqs.sync_reset) catch {};
|
||||
|
||||
// Send the cursor to 0,0
|
||||
// TODO: this needs to move after we optimize writes. We only do
|
||||
// this if we have an update to make. We also need to hide cursor
|
||||
// and then reshow it if needed
|
||||
try writer.writeAll(ctlseqs.hide_cursor);
|
||||
try tty.writeAll(ctlseqs.hide_cursor);
|
||||
if (self.state.alt_screen)
|
||||
try writer.writeAll(ctlseqs.home)
|
||||
try tty.writeAll(ctlseqs.home)
|
||||
else {
|
||||
try writer.writeAll("\r");
|
||||
var i: usize = 0;
|
||||
while (i < self.state.cursor.row) : (i += 1) {
|
||||
try writer.writeAll(ctlseqs.ri);
|
||||
}
|
||||
try tty.writeByte('\r');
|
||||
try tty.writeBytesNTimes(ctlseqs.ri, self.state.cursor.row);
|
||||
}
|
||||
try writer.writeAll(ctlseqs.sgr_reset);
|
||||
try tty.writeAll(ctlseqs.sgr_reset);
|
||||
|
||||
// initialize some variables
|
||||
var reposition: bool = false;
|
||||
|
@ -321,7 +327,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
|
||||
// Clear all images
|
||||
if (self.caps.kitty_graphics)
|
||||
try writer.writeAll(ctlseqs.kitty_graphics_clear);
|
||||
try tty.writeAll(ctlseqs.kitty_graphics_clear);
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < self.screen.buf.len) {
|
||||
|
@ -357,7 +363,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
// Close any osc8 sequence we might be in before
|
||||
// repositioning
|
||||
if (link.uri.len > 0) {
|
||||
try writer.writeAll(ctlseqs.osc8_clear);
|
||||
try tty.writeAll(ctlseqs.osc8_clear);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -373,52 +379,53 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
if (reposition) {
|
||||
reposition = false;
|
||||
if (self.state.alt_screen)
|
||||
try writer.print(ctlseqs.cup, .{ row + 1, col + 1 })
|
||||
try tty.print(ctlseqs.cup, .{ row + 1, col + 1 })
|
||||
else {
|
||||
if (cursor_pos.row == row) {
|
||||
const n = col - cursor_pos.col;
|
||||
try writer.print(ctlseqs.cuf, .{n});
|
||||
if (n > 0)
|
||||
try tty.print(ctlseqs.cuf, .{n});
|
||||
} else {
|
||||
try writer.writeByte('\r');
|
||||
try tty.writeByte('\r');
|
||||
const n = row - cursor_pos.row;
|
||||
try writer.writeByteNTimes('\n', n);
|
||||
try tty.writeByteNTimes('\n', n);
|
||||
if (col > 0)
|
||||
try tty.print(ctlseqs.cuf, .{col});
|
||||
}
|
||||
if (col > 0)
|
||||
try writer.print(ctlseqs.cuf, .{col});
|
||||
}
|
||||
}
|
||||
|
||||
if (cell.image) |img| {
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
ctlseqs.kitty_graphics_preamble,
|
||||
.{img.img_id},
|
||||
);
|
||||
if (img.options.pixel_offset) |offset| {
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
",X={d},Y={d}",
|
||||
.{ offset.x, offset.y },
|
||||
);
|
||||
}
|
||||
if (img.options.clip_region) |clip| {
|
||||
if (clip.x) |x|
|
||||
try writer.print(",x={d}", .{x});
|
||||
try tty.print(",x={d}", .{x});
|
||||
if (clip.y) |y|
|
||||
try writer.print(",y={d}", .{y});
|
||||
try tty.print(",y={d}", .{y});
|
||||
if (clip.width) |width|
|
||||
try writer.print(",w={d}", .{width});
|
||||
try tty.print(",w={d}", .{width});
|
||||
if (clip.height) |height|
|
||||
try writer.print(",h={d}", .{height});
|
||||
try tty.print(",h={d}", .{height});
|
||||
}
|
||||
if (img.options.size) |size| {
|
||||
if (size.rows) |rows|
|
||||
try writer.print(",r={d}", .{rows});
|
||||
try tty.print(",r={d}", .{rows});
|
||||
if (size.cols) |cols|
|
||||
try writer.print(",c={d}", .{cols});
|
||||
try tty.print(",c={d}", .{cols});
|
||||
}
|
||||
if (img.options.z_index) |z| {
|
||||
try writer.print(",z={d}", .{z});
|
||||
try tty.print(",z={d}", .{z});
|
||||
}
|
||||
try writer.writeAll(ctlseqs.kitty_graphics_closing);
|
||||
try tty.writeAll(ctlseqs.kitty_graphics_closing);
|
||||
}
|
||||
|
||||
// something is different, so let's loop through everything and
|
||||
|
@ -427,23 +434,23 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
// foreground
|
||||
if (!Cell.Color.eql(cursor.fg, cell.style.fg)) {
|
||||
switch (cell.style.fg) {
|
||||
.default => try writer.writeAll(ctlseqs.fg_reset),
|
||||
.default => try tty.writeAll(ctlseqs.fg_reset),
|
||||
.index => |idx| {
|
||||
switch (idx) {
|
||||
0...7 => try writer.print(ctlseqs.fg_base, .{idx}),
|
||||
8...15 => try writer.print(ctlseqs.fg_bright, .{idx - 8}),
|
||||
0...7 => try tty.print(ctlseqs.fg_base, .{idx}),
|
||||
8...15 => try tty.print(ctlseqs.fg_bright, .{idx - 8}),
|
||||
else => {
|
||||
switch (self.sgr) {
|
||||
.standard => try writer.print(ctlseqs.fg_indexed, .{idx}),
|
||||
.legacy => try writer.print(ctlseqs.fg_indexed_legacy, .{idx}),
|
||||
.standard => try tty.print(ctlseqs.fg_indexed, .{idx}),
|
||||
.legacy => try tty.print(ctlseqs.fg_indexed_legacy, .{idx}),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.rgb => |rgb| {
|
||||
switch (self.sgr) {
|
||||
.standard => try writer.print(ctlseqs.fg_rgb, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.legacy => try writer.print(ctlseqs.fg_rgb_legacy, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.standard => try tty.print(ctlseqs.fg_rgb, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.legacy => try tty.print(ctlseqs.fg_rgb_legacy, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -451,23 +458,23 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
// background
|
||||
if (!Cell.Color.eql(cursor.bg, cell.style.bg)) {
|
||||
switch (cell.style.bg) {
|
||||
.default => try writer.writeAll(ctlseqs.bg_reset),
|
||||
.default => try tty.writeAll(ctlseqs.bg_reset),
|
||||
.index => |idx| {
|
||||
switch (idx) {
|
||||
0...7 => try writer.print(ctlseqs.bg_base, .{idx}),
|
||||
8...15 => try writer.print(ctlseqs.bg_bright, .{idx - 8}),
|
||||
0...7 => try tty.print(ctlseqs.bg_base, .{idx}),
|
||||
8...15 => try tty.print(ctlseqs.bg_bright, .{idx - 8}),
|
||||
else => {
|
||||
switch (self.sgr) {
|
||||
.standard => try writer.print(ctlseqs.bg_indexed, .{idx}),
|
||||
.legacy => try writer.print(ctlseqs.bg_indexed_legacy, .{idx}),
|
||||
.standard => try tty.print(ctlseqs.bg_indexed, .{idx}),
|
||||
.legacy => try tty.print(ctlseqs.bg_indexed_legacy, .{idx}),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.rgb => |rgb| {
|
||||
switch (self.sgr) {
|
||||
.standard => try writer.print(ctlseqs.bg_rgb, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.legacy => try writer.print(ctlseqs.bg_rgb_legacy, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.standard => try tty.print(ctlseqs.bg_rgb, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.legacy => try tty.print(ctlseqs.bg_rgb_legacy, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -475,17 +482,17 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
// underline color
|
||||
if (!Cell.Color.eql(cursor.ul, cell.style.ul)) {
|
||||
switch (cell.style.bg) {
|
||||
.default => try writer.writeAll(ctlseqs.ul_reset),
|
||||
.default => try tty.writeAll(ctlseqs.ul_reset),
|
||||
.index => |idx| {
|
||||
switch (self.sgr) {
|
||||
.standard => try writer.print(ctlseqs.ul_indexed, .{idx}),
|
||||
.legacy => try writer.print(ctlseqs.ul_indexed_legacy, .{idx}),
|
||||
.standard => try tty.print(ctlseqs.ul_indexed, .{idx}),
|
||||
.legacy => try tty.print(ctlseqs.ul_indexed_legacy, .{idx}),
|
||||
}
|
||||
},
|
||||
.rgb => |rgb| {
|
||||
switch (self.sgr) {
|
||||
.standard => try writer.print(ctlseqs.ul_rgb, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.legacy => try writer.print(ctlseqs.ul_rgb_legacy, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.standard => try tty.print(ctlseqs.ul_rgb, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
.legacy => try tty.print(ctlseqs.ul_rgb_legacy, .{ rgb[0], rgb[1], rgb[2] }),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -500,7 +507,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
.dotted => ctlseqs.ul_dotted,
|
||||
.dashed => ctlseqs.ul_dashed,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
}
|
||||
// bold
|
||||
if (cursor.bold != cell.style.bold) {
|
||||
|
@ -508,9 +515,9 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
true => ctlseqs.bold_set,
|
||||
false => ctlseqs.bold_dim_reset,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
if (cell.style.dim) {
|
||||
try writer.writeAll(ctlseqs.dim_set);
|
||||
try tty.writeAll(ctlseqs.dim_set);
|
||||
}
|
||||
}
|
||||
// dim
|
||||
|
@ -519,9 +526,9 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
true => ctlseqs.dim_set,
|
||||
false => ctlseqs.bold_dim_reset,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
if (cell.style.bold) {
|
||||
try writer.writeAll(ctlseqs.bold_set);
|
||||
try tty.writeAll(ctlseqs.bold_set);
|
||||
}
|
||||
}
|
||||
// dim
|
||||
|
@ -530,7 +537,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
true => ctlseqs.italic_set,
|
||||
false => ctlseqs.italic_reset,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
}
|
||||
// dim
|
||||
if (cursor.blink != cell.style.blink) {
|
||||
|
@ -538,7 +545,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
true => ctlseqs.blink_set,
|
||||
false => ctlseqs.blink_reset,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
}
|
||||
// reverse
|
||||
if (cursor.reverse != cell.style.reverse) {
|
||||
|
@ -546,7 +553,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
true => ctlseqs.reverse_set,
|
||||
false => ctlseqs.reverse_reset,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
}
|
||||
// invisible
|
||||
if (cursor.invisible != cell.style.invisible) {
|
||||
|
@ -554,7 +561,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
true => ctlseqs.invisible_set,
|
||||
false => ctlseqs.invisible_reset,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
}
|
||||
// strikethrough
|
||||
if (cursor.strikethrough != cell.style.strikethrough) {
|
||||
|
@ -562,7 +569,7 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
true => ctlseqs.strikethrough_set,
|
||||
false => ctlseqs.strikethrough_reset,
|
||||
};
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
}
|
||||
|
||||
// url
|
||||
|
@ -573,15 +580,15 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
// a url
|
||||
ps = "";
|
||||
}
|
||||
try writer.print(ctlseqs.osc8, .{ ps, cell.link.uri });
|
||||
try tty.print(ctlseqs.osc8, .{ ps, cell.link.uri });
|
||||
}
|
||||
try writer.writeAll(cell.char.grapheme);
|
||||
try tty.writeAll(cell.char.grapheme);
|
||||
cursor_pos.col = col + w;
|
||||
cursor_pos.row = row;
|
||||
}
|
||||
if (self.screen.cursor_vis) {
|
||||
if (self.state.alt_screen) {
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
ctlseqs.cup,
|
||||
.{
|
||||
self.screen.cursor_row + 1,
|
||||
|
@ -590,30 +597,30 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
);
|
||||
} else {
|
||||
// TODO: position cursor relative to current location
|
||||
try writer.writeByte('\r');
|
||||
try tty.writeByte('\r');
|
||||
if (self.screen.cursor_row >= cursor_pos.row)
|
||||
try writer.writeByteNTimes('\n', self.screen.cursor_row - cursor_pos.row)
|
||||
try tty.writeByteNTimes('\n', self.screen.cursor_row - cursor_pos.row)
|
||||
else
|
||||
try writer.writeBytesNTimes(ctlseqs.ri, cursor_pos.row - self.screen.cursor_row);
|
||||
try tty.writeBytesNTimes(ctlseqs.ri, cursor_pos.row - self.screen.cursor_row);
|
||||
if (self.screen.cursor_col > 0)
|
||||
try writer.print(ctlseqs.cuf, .{self.screen.cursor_col});
|
||||
try tty.print(ctlseqs.cuf, .{self.screen.cursor_col});
|
||||
}
|
||||
self.state.cursor.row = self.screen.cursor_row;
|
||||
self.state.cursor.col = self.screen.cursor_col;
|
||||
try writer.writeAll(ctlseqs.show_cursor);
|
||||
try tty.writeAll(ctlseqs.show_cursor);
|
||||
} else {
|
||||
self.state.cursor.row = cursor_pos.row;
|
||||
self.state.cursor.col = cursor_pos.col;
|
||||
}
|
||||
if (self.screen.mouse_shape != self.screen_last.mouse_shape) {
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
ctlseqs.osc22_mouse_shape,
|
||||
.{@tagName(self.screen.mouse_shape)},
|
||||
);
|
||||
self.screen_last.mouse_shape = self.screen.mouse_shape;
|
||||
}
|
||||
if (self.screen.cursor_shape != self.screen_last.cursor_shape) {
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
ctlseqs.cursor_shape,
|
||||
.{@intFromEnum(self.screen.cursor_shape)},
|
||||
);
|
||||
|
@ -621,34 +628,34 @@ pub fn render(self: *Vaxis, writer: AnyWriter) !void {
|
|||
}
|
||||
}
|
||||
|
||||
fn enableKittyKeyboard(self: *Vaxis, writer: AnyWriter, flags: Key.KittyFlags) !void {
|
||||
fn enableKittyKeyboard(self: *Vaxis, tty: AnyWriter, flags: Key.KittyFlags) !void {
|
||||
const flag_int: u5 = @bitCast(flags);
|
||||
try writer.print(ctlseqs.csi_u_push, .{flag_int});
|
||||
try tty.print(ctlseqs.csi_u_push, .{flag_int});
|
||||
self.state.kitty_keyboard = true;
|
||||
}
|
||||
|
||||
/// send a system notification
|
||||
pub fn notify(_: *Vaxis, writer: AnyWriter, title: ?[]const u8, body: []const u8) !void {
|
||||
pub fn notify(_: *Vaxis, tty: AnyWriter, title: ?[]const u8, body: []const u8) !void {
|
||||
if (title) |t|
|
||||
try writer.print(ctlseqs.osc777_notify, .{ t, body })
|
||||
try tty.print(ctlseqs.osc777_notify, .{ t, body })
|
||||
else
|
||||
try writer.print(ctlseqs.osc9_notify, .{body});
|
||||
try tty.print(ctlseqs.osc9_notify, .{body});
|
||||
}
|
||||
|
||||
/// sets the window title
|
||||
pub fn setTitle(_: *Vaxis, writer: AnyWriter, title: []const u8) !void {
|
||||
try writer.print(ctlseqs.osc2_set_title, .{title});
|
||||
pub fn setTitle(_: *Vaxis, tty: AnyWriter, title: []const u8) !void {
|
||||
try tty.print(ctlseqs.osc2_set_title, .{title});
|
||||
}
|
||||
|
||||
// turn bracketed paste on or off. An event will be sent at the
|
||||
// beginning and end of a detected paste. All keystrokes between these
|
||||
// events were pasted
|
||||
pub fn setBracketedPaste(self: *Vaxis, writer: AnyWriter, enable: bool) !void {
|
||||
pub fn setBracketedPaste(self: *Vaxis, tty: AnyWriter, enable: bool) !void {
|
||||
const seq = if (enable)
|
||||
ctlseqs.bp_set
|
||||
else
|
||||
ctlseqs.bp_reset;
|
||||
try writer.writeAll(seq);
|
||||
try tty.writeAll(seq);
|
||||
self.state.bracketed_paste = enable;
|
||||
}
|
||||
|
||||
|
@ -658,19 +665,19 @@ pub fn setMouseShape(self: *Vaxis, shape: Shape) void {
|
|||
}
|
||||
|
||||
/// Change the mouse reporting mode
|
||||
pub fn setMouseMode(self: *Vaxis, writer: AnyWriter, enable: bool) !void {
|
||||
pub fn setMouseMode(self: *Vaxis, tty: AnyWriter, enable: bool) !void {
|
||||
if (enable) {
|
||||
self.state.mouse = true;
|
||||
if (self.caps.sgr_pixels) {
|
||||
log.debug("enabling mouse mode: pixel coordinates", .{});
|
||||
self.state.pixel_mouse = true;
|
||||
try writer.writeAll(ctlseqs.mouse_set_pixels);
|
||||
try tty.writeAll(ctlseqs.mouse_set_pixels);
|
||||
} else {
|
||||
log.debug("enabling mouse mode: cell coordinates", .{});
|
||||
try writer.writeAll(ctlseqs.mouse_set);
|
||||
try tty.writeAll(ctlseqs.mouse_set);
|
||||
}
|
||||
} else {
|
||||
try writer.writeAll(ctlseqs.mouse_reset);
|
||||
try tty.writeAll(ctlseqs.mouse_reset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,7 +716,7 @@ pub fn translateMouse(self: Vaxis, mouse: Mouse) Mouse {
|
|||
pub fn loadImage(
|
||||
self: *Vaxis,
|
||||
alloc: std.mem.Allocator,
|
||||
writer: AnyWriter,
|
||||
tty: AnyWriter,
|
||||
src: Image.Source,
|
||||
) !Image {
|
||||
if (!self.caps.kitty_graphics) return error.NoGraphicsCapability;
|
||||
|
@ -730,7 +737,7 @@ pub fn loadImage(
|
|||
const id = self.next_img_id;
|
||||
|
||||
if (encoded.len < 4096) {
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
"\x1b_Gf=100,i={d};{s}\x1b\\",
|
||||
.{
|
||||
id,
|
||||
|
@ -740,14 +747,14 @@ pub fn loadImage(
|
|||
} else {
|
||||
var n: usize = 4096;
|
||||
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
"\x1b_Gf=100,i={d},m=1;{s}\x1b\\",
|
||||
.{ id, encoded[0..n] },
|
||||
);
|
||||
while (n < encoded.len) : (n += 4096) {
|
||||
const end: usize = @min(n + 4096, encoded.len);
|
||||
const m: u2 = if (end == encoded.len) 0 else 1;
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
"\x1b_Gm={d};{s}\x1b\\",
|
||||
.{
|
||||
m,
|
||||
|
@ -764,28 +771,28 @@ pub fn loadImage(
|
|||
}
|
||||
|
||||
/// deletes an image from the terminal's memory
|
||||
pub fn freeImage(_: Vaxis, writer: AnyWriter, id: u32) void {
|
||||
writer.print("\x1b_Ga=d,d=I,i={d};\x1b\\", .{id}) catch |err| {
|
||||
pub fn freeImage(_: Vaxis, tty: AnyWriter, id: u32) void {
|
||||
tty.print("\x1b_Ga=d,d=I,i={d};\x1b\\", .{id}) catch |err| {
|
||||
log.err("couldn't delete image {d}: {}", .{ id, err });
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn copyToSystemClipboard(_: Vaxis, writer: AnyWriter, text: []const u8, encode_allocator: std.mem.Allocator) !void {
|
||||
pub fn copyToSystemClipboard(_: Vaxis, tty: AnyWriter, text: []const u8, encode_allocator: std.mem.Allocator) !void {
|
||||
const encoder = std.base64.standard.Encoder;
|
||||
const size = encoder.calcSize(text.len);
|
||||
const buf = try encode_allocator.alloc(u8, size);
|
||||
const b64 = encoder.encode(buf, text);
|
||||
defer encode_allocator.free(buf);
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
ctlseqs.osc52_clipboard_copy,
|
||||
.{b64},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn requestSystemClipboard(self: Vaxis, writer: AnyWriter) !void {
|
||||
pub fn requestSystemClipboard(self: Vaxis, tty: AnyWriter) !void {
|
||||
if (self.opts.system_clipboard_allocator == null) return error.NoClipboardAllocator;
|
||||
try writer.print(
|
||||
try tty.print(
|
||||
ctlseqs.osc52_clipboard_request,
|
||||
.{},
|
||||
);
|
||||
|
@ -794,12 +801,12 @@ pub fn requestSystemClipboard(self: Vaxis, writer: AnyWriter) !void {
|
|||
/// Request a color report from the terminal. Note: not all terminals support
|
||||
/// reporting colors. It is always safe to try, but you may not receive a
|
||||
/// response.
|
||||
pub fn queryColor(_: Vaxis, writer: AnyWriter, kind: Cell.Color.Kind) !void {
|
||||
pub fn queryColor(_: Vaxis, tty: AnyWriter, kind: Cell.Color.Kind) !void {
|
||||
switch (kind) {
|
||||
.fg => try writer.writeAll(ctlseqs.osc10_query),
|
||||
.bg => try writer.writeAll(ctlseqs.osc11_query),
|
||||
.cursor => try writer.writeAll(ctlseqs.osc12_query),
|
||||
.index => |idx| try writer.print(ctlseqs.osc4_query, .{idx}),
|
||||
.fg => try tty.writeAll(ctlseqs.osc10_query),
|
||||
.bg => try tty.writeAll(ctlseqs.osc11_query),
|
||||
.cursor => try tty.writeAll(ctlseqs.osc12_query),
|
||||
.index => |idx| try tty.print(ctlseqs.osc4_query, .{idx}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -808,12 +815,12 @@ pub fn queryColor(_: Vaxis, writer: AnyWriter, kind: Cell.Color.Kind) !void {
|
|||
/// capability. Support can be detected by checking the value of
|
||||
/// vaxis.caps.color_scheme_updates. The initial scheme will be reported when
|
||||
/// subscribing.
|
||||
pub fn subscribeToColorSchemeUpdates(self: Vaxis, writer: AnyWriter) !void {
|
||||
try writer.writeAll(ctlseqs.color_scheme_request);
|
||||
try writer.writeAll(ctlseqs.color_scheme_set);
|
||||
pub fn subscribeToColorSchemeUpdates(self: Vaxis, tty: AnyWriter) !void {
|
||||
try tty.writeAll(ctlseqs.color_scheme_request);
|
||||
try tty.writeAll(ctlseqs.color_scheme_set);
|
||||
self.state.color_scheme_updates = true;
|
||||
}
|
||||
|
||||
pub fn deviceStatusReport(_: Vaxis, writer: AnyWriter) !void {
|
||||
try writer.writeAll(ctlseqs.device_status_report);
|
||||
pub fn deviceStatusReport(_: Vaxis, tty: AnyWriter) !void {
|
||||
try tty.writeAll(ctlseqs.device_status_report);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue