terminal: kitty color

pull/9342/head
Mitchell Hashimoto 2025-10-25 06:40:14 -07:00
parent a85ad0e4f8
commit e13f9b9e8c
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
4 changed files with 34 additions and 15 deletions

View File

@ -1,4 +1,6 @@
const std = @import("std");
const build_options = @import("terminal_options");
const LibEnum = @import("../../lib/enum.zig").Enum;
const terminal = @import("../main.zig");
const RGB = terminal.color.RGB;
const Terminator = terminal.osc.Terminator;
@ -16,6 +18,13 @@ pub const OSC = struct {
/// We must reply with the same string terminator (ST) as used in the
/// request.
terminator: Terminator = .st,
/// We don't currently support encoding this to C in any way.
pub const C = void;
pub fn cval(_: OSC) C {
return {};
}
};
pub const Special = enum {

View File

@ -271,6 +271,8 @@ pub const Terminator = enum {
/// Some applications and terminals use BELL (0x07) as the string terminator.
bel,
pub const C = LibEnum(.c, &.{ "st", "bel" });
/// Initialize the terminator based on the last byte seen. If the
/// last byte is a BEL then we use BEL, otherwise we just assume ST.
pub fn init(ch: ?u8) Terminator {
@ -289,6 +291,13 @@ pub const Terminator = enum {
};
}
pub fn cval(self: Terminator) C {
return switch (self) {
.st => .st,
.bel => .bel,
};
}
pub fn format(
self: Terminator,
comptime _: []const u8,

View File

@ -125,6 +125,7 @@ pub const Action = union(Key) {
mouse_shape: MouseShape,
configure_charset: ConfigureCharset,
set_attribute: sgr.Attribute,
kitty_color_report: kitty.color.OSC,
pub const Key = lib.Enum(
lib_target,
@ -224,6 +225,7 @@ pub const Action = union(Key) {
"mouse_shape",
"configure_charset",
"set_attribute",
"kitty_color_report",
},
);
@ -432,24 +434,25 @@ pub const Action = union(Key) {
};
/// Returns a type that can process a stream of tty control characters.
/// This will call various callback functions on type T. Type T only has to
/// implement the callbacks it cares about; any unimplemented callbacks will
/// logged at runtime.
/// This will call the `vt` function on type T with the following signature:
///
/// To figure out what callbacks exist, search the source for "hasDecl". This
/// isn't ideal but for now that's the best approach.
/// fn(comptime action: Action.Key, value: Action.Value(action)) !void
///
/// This is implemented this way because we purposely do NOT want dynamic
/// dispatch for performance reasons. The way this is implemented forces
/// comptime resolution for all function calls.
/// The handler type T can choose to react to whatever actions it cares
/// about in its pursuit of implementing a terminal emulator or other
/// functionality.
///
/// The "comptime" key is on purpose (vs. a standard Zig tagged union)
/// because it allows the compiler to optimize away unimplemented actions.
/// e.g. you don't need to pay a conditional branching cost on every single
/// action because the Zig compiler codegens separate code paths for every
/// single action at comptime.
pub fn Stream(comptime Handler: type) type {
return struct {
const Self = @This();
pub const Action = streampkg.Action;
// We use T with @hasDecl so it needs to be a struct. Unwrap the
// pointer if we were given one.
const T = switch (@typeInfo(Handler)) {
.pointer => |p| p.child,
else => Handler,
@ -1912,10 +1915,7 @@ pub fn Stream(comptime Handler: type) type {
},
.kitty_color_protocol => |v| {
if (@hasDecl(T, "sendKittyColorReport")) {
try self.handler.sendKittyColorReport(v);
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
try self.handler.vt(.kitty_color_report, v);
},
.show_desktop_notification => |v| {

View File

@ -301,6 +301,7 @@ pub const StreamHandler = struct {
log.debug("setting kitty keyboard mode: not {}", .{value.flags});
self.terminal.screen.kitty_keyboard.set(.not, value.flags);
},
.kitty_color_report => try self.kittyColorReport(value),
.prompt_end => try self.promptEnd(),
.end_of_input => try self.endOfInput(),
.end_hyperlink => try self.endHyperlink(),
@ -1382,7 +1383,7 @@ pub const StreamHandler = struct {
}
}
pub fn sendKittyColorReport(
fn kittyColorReport(
self: *StreamHandler,
request: terminal.kitty.color.OSC,
) !void {