respond to ESC [ c for primary attributes

This commit is contained in:
Mitchell Hashimoto
2022-05-15 20:04:14 -07:00
parent 0d30cc1656
commit d5858dd0cd
4 changed files with 62 additions and 10 deletions

View File

@ -67,8 +67,7 @@ pty_stream: libuv.Tty,
write_req_pool: SegmentedPool(libuv.WriteReq.T, WRITE_REQ_PREALLOC) = .{}, write_req_pool: SegmentedPool(libuv.WriteReq.T, WRITE_REQ_PREALLOC) = .{},
/// The pool of available buffers for writing to the pty. /// The pool of available buffers for writing to the pty.
/// TODO: [1]u8 is probably not right. write_buf_pool: SegmentedPool([64]u8, WRITE_REQ_PREALLOC) = .{},
write_buf_pool: SegmentedPool([1]u8, WRITE_REQ_PREALLOC) = .{},
/// Set this to true whenver an event occurs that we may want to wake up /// Set this to true whenver an event occurs that we may want to wake up
/// the event loop. Only set this from the main thread. /// the event loop. Only set this from the main thread.
@ -246,6 +245,26 @@ pub fn shouldClose(self: Window) bool {
return self.window.shouldClose(); return self.window.shouldClose();
} }
/// Queue a write to the pty.
fn queueWrite(self: *Window, data: []const u8) !void {
// We go through and chunk the data if necessary to fit into
// our cached buffers that we can queue to the stream.
var i: usize = 0;
while (i < data.len) {
const req = try self.write_req_pool.get();
const buf = try self.write_buf_pool.get();
const end = @minimum(data.len, i + buf.len);
std.mem.copy(u8, buf, data[i..end]);
try self.pty_stream.write(
.{ .req = req },
&[1][]u8{buf[0..(end - i)]},
ttyWrite,
);
i += end;
}
}
fn sizeCallback(window: glfw.Window, width: i32, height: i32) void { fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -288,14 +307,7 @@ fn charCallback(window: glfw.Window, codepoint: u21) void {
const win = window.getUserPointer(Window) orelse return; const win = window.getUserPointer(Window) orelse return;
// Write the character to the pty // Write the character to the pty
const req = win.write_req_pool.get() catch unreachable; win.queueWrite(&[1]u8{@intCast(u8, codepoint)}) catch unreachable;
const buf = win.write_buf_pool.get() catch unreachable;
buf[0] = @intCast(u8, codepoint);
win.pty_stream.write(
.{ .req = req },
&[1][]u8{buf[0..1]},
ttyWrite,
) catch unreachable;
} }
fn keyCallback( fn keyCallback(
@ -597,3 +609,17 @@ pub fn setAttribute(self: *Window, attr: terminal.Attribute) !void {
log.warn("error setting attribute {}: {}", .{ attr, err }), log.warn("error setting attribute {}: {}", .{ attr, err }),
} }
} }
pub fn deviceAttributes(
self: *Window,
req: terminal.DeviceAttributeReq,
params: []const u16,
) !void {
_ = params;
switch (req) {
.primary => self.queueWrite("\x1B[?6c") catch |err|
log.warn("error queueing device attr response: {}", .{err}),
else => log.warn("unimplemented device attributes req: {}", .{req}),
}
}

View File

@ -42,3 +42,10 @@ pub const Mode = enum(u16) {
// Non-exhaustive so that @intToEnum never fails for unsupported modes. // Non-exhaustive so that @intToEnum never fails for unsupported modes.
_, _,
}; };
/// The device attribute request type (ESC [ c).
pub const DeviceAttributeReq = enum {
primary, // Blank
secondary, // >
tertiary, // =
};

View File

@ -6,6 +6,7 @@ const sgr = @import("sgr.zig");
pub const Terminal = @import("Terminal.zig"); pub const Terminal = @import("Terminal.zig");
pub const Parser = @import("Parser.zig"); pub const Parser = @import("Parser.zig");
pub const Stream = stream.Stream; pub const Stream = stream.Stream;
pub const DeviceAttributeReq = ansi.DeviceAttributeReq;
pub const Mode = ansi.Mode; pub const Mode = ansi.Mode;
pub const EraseDisplay = csi.EraseDisplay; pub const EraseDisplay = csi.EraseDisplay;
pub const EraseLine = csi.EraseLine; pub const EraseLine = csi.EraseLine;

View File

@ -235,6 +235,24 @@ pub fn Stream(comptime Handler: type) type {
}, },
) else log.warn("unimplemented CSI callback: {}", .{action}), ) else log.warn("unimplemented CSI callback: {}", .{action}),
// c - Device Attributes (DA1)
'c' => if (@hasDecl(T, "deviceAttributes")) {
const req: ansi.DeviceAttributeReq = switch (action.intermediates.len) {
0 => ansi.DeviceAttributeReq.primary,
1 => switch (action.intermediates[0]) {
'>' => ansi.DeviceAttributeReq.secondary,
'=' => ansi.DeviceAttributeReq.tertiary,
else => null,
},
else => @as(?ansi.DeviceAttributeReq, null),
} orelse {
log.warn("invalid device attributes command: {}", .{action});
return;
};
try self.handler.deviceAttributes(req, action.params);
} else log.warn("unimplemented CSI callback: {}", .{action}),
// VPA - Cursor Vertical Position Absolute // VPA - Cursor Vertical Position Absolute
'd' => if (@hasDecl(T, "setCursorRow")) try self.handler.setCursorRow( 'd' => if (@hasDecl(T, "setCursorRow")) try self.handler.setCursorRow(
switch (action.params.len) { switch (action.params.len) {