mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
respond to ESC [ c for primary attributes
This commit is contained in:
@ -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}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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, // =
|
||||||
|
};
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
Reference in New Issue
Block a user