vaxis: add sync and refresh

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
This commit is contained in:
Tim Culverhouse 2024-01-23 07:36:44 -06:00
parent 5d8f78ccd2
commit 59470f18e8
3 changed files with 50 additions and 17 deletions

View file

@ -34,6 +34,8 @@ pub fn main() !void {
var text_input = TextInput.init(alloc);
defer text_input.deinit();
try vx.queryTerminal();
// The main event loop. Vaxis provides a thread safe, blocking, buffered
// queue which can serve as the primary event queue for an application
outer: while (true) {
@ -49,9 +51,12 @@ pub fn main() !void {
else => color_idx + 1,
};
try text_input.update(.{ .key_press = key });
if (key.codepoint == 'c' and key.mods.ctrl) {
if (key.matches('c', .{ .ctrl = true })) {
break :outer;
}
if (key.matches('l', .{ .ctrl = true })) {
vx.queueRefresh();
}
},
.winsize => |ws| {
try vx.resize(alloc, ws);

View file

@ -10,6 +10,10 @@ pub const csi_u_query = "\x1b[?u";
pub const kitty_graphics_query = "\x1b_Gi=1,a=q\x1b\\";
pub const sixel_geometry_query = "\x1b[?2;1;0S";
// sync
pub const sync_set = "\x1b[?2026h";
pub const sync_reset = "\x1b[?2026l";
// Key encoding
pub const csi_u_push = "\x1b[>{d}u";
pub const csi_u_pop = "\x1b[<u";

View file

@ -36,13 +36,18 @@ pub fn Vaxis(comptime T: type) type {
tty: ?Tty,
/// the screen we write to
screen: Screen,
// The last screen we drew. We keep this so we can efficiently update on
// the next render
/// The last screen we drew. We keep this so we can efficiently update on
/// the next render
screen_last: InternalScreen = undefined,
/// alt_screen state. We track so we can exit on deinit
alt_screen: bool,
/// if we should redraw the entire screen on the next render
refresh: bool = false,
// statistics
renders: usize = 0,
render_dur: i128 = 0,
@ -161,26 +166,37 @@ pub fn Vaxis(comptime T: type) type {
var tty = self.tty orelse return;
const colorterm = std.os.getenv("COLORTERM") orelse "";
if (std.mem.eql(u8, colorterm, "truecolor" or
std.mem.eql(u8, colorterm, "24bit")))
if (std.mem.eql(u8, colorterm, "truecolor") or
std.mem.eql(u8, colorterm, "24bit"))
{
// TODO: Notify rgb support
}
const writer = tty.buffered_writer.writer();
_ = try writer.write(ctlseqs.decrqm_focus);
_ = try writer.write(ctlseqs.decrqm_sync);
_ = try writer.write(ctlseqs.decrqm_unicode);
_ = try writer.write(ctlseqs.decrqm_color_theme);
_ = try writer.write(ctlseqs.xtversion);
_ = try writer.write(ctlseqs.csi_u_query);
_ = try writer.write(ctlseqs.kitty_graphics_query);
_ = try writer.write(ctlseqs.sixel_geometry_query);
// 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 tty.write(ctlseqs.decrqm_unicode);
_ = try tty.write(ctlseqs.decrqm_color_theme);
// TODO: XTVERSION has a DCS response. uncomment when we can parse
// that
// _ = try tty.write(ctlseqs.xtversion);
_ = try tty.write(ctlseqs.csi_u_query);
// TODO: KITTY_GRAPHICS has an APC response. uncomment when we can
// parse that
// that
// _ = try tty.write(ctlseqs.kitty_graphics_query);
_ = try tty.write(ctlseqs.sixel_geometry_query);
// TODO: XTGETTCAP queries ("RGB", "Smulx")
_ = try writer.write(ctlseqs.primary_device_attrs);
try writer.flush();
_ = try tty.write(ctlseqs.primary_device_attrs);
try tty.flush();
}
// the next render call will refresh the entire screen
pub fn queueRefresh(self: *Self) void {
self.refresh = true;
}
/// draws the screen to the terminal
@ -192,8 +208,16 @@ pub fn Vaxis(comptime T: type) type {
self.render_dur += std.time.microTimestamp() - timer_start;
}
defer self.refresh = false;
defer tty.flush() catch {};
// Set up sync before we write anything
// 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 tty.write(ctlseqs.sync_set);
defer _ = tty.write(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
@ -218,7 +242,7 @@ pub fn Vaxis(comptime T: type) type {
}
// If cell is the same as our last frame, we don't need to do
// anything
if (self.screen_last.buf[i].eql(cell)) {
if (!self.refresh and self.screen_last.buf[i].eql(cell)) {
reposition = true;
// Close any osc8 sequence we might be in before
// repositioning