mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Implement Kitty Color Protocol (OSC 21)
Kitty 0.36.0 added support for a new OSC escape sequence for quering, setting, and resetting the terminal colors. Details can be found [here](https://sw.kovidgoyal.net/kitty/color-stack/#setting-and-querying-colors). This fully parses the OSC 21 escape sequences, but only supports actually querying and changing the foreground color, the background color, and the cursor color because that's what Ghostty currently supports. Adding support for the other settings that Kitty supports changing ranges from easy (cursor text) to difficult (visual bell, second transparent background color).
This commit is contained in:
@ -259,6 +259,11 @@ pub const VTEvent = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.Struct => try md.put(
|
||||||
|
key,
|
||||||
|
try alloc.dupeZ(u8, @typeName(Value)),
|
||||||
|
),
|
||||||
|
|
||||||
else => switch (Value) {
|
else => switch (Value) {
|
||||||
u8 => try md.put(
|
u8 => try md.put(
|
||||||
key,
|
key,
|
||||||
|
@ -208,7 +208,7 @@ pub const RGB = struct {
|
|||||||
/// where <red>, <green>, and <blue> are floating point values between
|
/// where <red>, <green>, and <blue> are floating point values between
|
||||||
/// 0.0 and 1.0 (inclusive).
|
/// 0.0 and 1.0 (inclusive).
|
||||||
///
|
///
|
||||||
/// 3. #hhhhhh
|
/// 3. #hhh, #hhhhhh, #hhhhhhhhh #hhhhhhhhhhhh
|
||||||
///
|
///
|
||||||
/// where `h` is a single hexadecimal digit.
|
/// where `h` is a single hexadecimal digit.
|
||||||
pub fn parse(value: []const u8) !RGB {
|
pub fn parse(value: []const u8) !RGB {
|
||||||
@ -217,15 +217,30 @@ pub const RGB = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (value[0] == '#') {
|
if (value[0] == '#') {
|
||||||
if (value.len != 7) {
|
switch (value.len) {
|
||||||
return error.InvalidFormat;
|
4 => return RGB{
|
||||||
}
|
.r = try RGB.fromHex(value[1..2]),
|
||||||
|
.g = try RGB.fromHex(value[2..3]),
|
||||||
|
.b = try RGB.fromHex(value[3..4]),
|
||||||
|
},
|
||||||
|
7 => return RGB{
|
||||||
|
.r = try RGB.fromHex(value[1..3]),
|
||||||
|
.g = try RGB.fromHex(value[3..5]),
|
||||||
|
.b = try RGB.fromHex(value[5..7]),
|
||||||
|
},
|
||||||
|
10 => return RGB{
|
||||||
|
.r = try RGB.fromHex(value[1..4]),
|
||||||
|
.g = try RGB.fromHex(value[4..7]),
|
||||||
|
.b = try RGB.fromHex(value[7..10]),
|
||||||
|
},
|
||||||
|
13 => return RGB{
|
||||||
|
.r = try RGB.fromHex(value[1..5]),
|
||||||
|
.g = try RGB.fromHex(value[5..9]),
|
||||||
|
.b = try RGB.fromHex(value[9..13]),
|
||||||
|
},
|
||||||
|
|
||||||
return RGB{
|
else => return error.InvalidFormat,
|
||||||
.r = try RGB.fromHex(value[1..3]),
|
}
|
||||||
.g = try RGB.fromHex(value[3..5]),
|
|
||||||
.b = try RGB.fromHex(value[5..7]),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for X11 named colors. We allow whitespace around the edges
|
// Check for X11 named colors. We allow whitespace around the edges
|
||||||
@ -308,6 +323,9 @@ test "RGB.parse" {
|
|||||||
try testing.expectEqual(RGB{ .r = 127, .g = 160, .b = 0 }, try RGB.parse("rgb:7f/a0a0/0"));
|
try testing.expectEqual(RGB{ .r = 127, .g = 160, .b = 0 }, try RGB.parse("rgb:7f/a0a0/0"));
|
||||||
try testing.expectEqual(RGB{ .r = 255, .g = 255, .b = 255 }, try RGB.parse("rgb:f/ff/fff"));
|
try testing.expectEqual(RGB{ .r = 255, .g = 255, .b = 255 }, try RGB.parse("rgb:f/ff/fff"));
|
||||||
try testing.expectEqual(RGB{ .r = 255, .g = 255, .b = 255 }, try RGB.parse("#ffffff"));
|
try testing.expectEqual(RGB{ .r = 255, .g = 255, .b = 255 }, try RGB.parse("#ffffff"));
|
||||||
|
try testing.expectEqual(RGB{ .r = 255, .g = 255, .b = 255 }, try RGB.parse("#fff"));
|
||||||
|
try testing.expectEqual(RGB{ .r = 255, .g = 255, .b = 255 }, try RGB.parse("#fffffffff"));
|
||||||
|
try testing.expectEqual(RGB{ .r = 255, .g = 255, .b = 255 }, try RGB.parse("#ffffffffffff"));
|
||||||
try testing.expectEqual(RGB{ .r = 255, .g = 0, .b = 16 }, try RGB.parse("#ff0010"));
|
try testing.expectEqual(RGB{ .r = 255, .g = 0, .b = 16 }, try RGB.parse("#ff0010"));
|
||||||
|
|
||||||
try testing.expectEqual(RGB{ .r = 0, .g = 0, .b = 0 }, try RGB.parse("black"));
|
try testing.expectEqual(RGB{ .r = 0, .g = 0, .b = 0 }, try RGB.parse("black"));
|
||||||
|
@ -9,6 +9,7 @@ const std = @import("std");
|
|||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
const RGB = @import("color.zig").RGB;
|
||||||
|
|
||||||
const log = std.log.scoped(.osc);
|
const log = std.log.scoped(.osc);
|
||||||
|
|
||||||
@ -137,6 +138,10 @@ pub const Command = union(enum) {
|
|||||||
value: []const u8,
|
value: []const u8,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Kitty color protocl, OSC 21
|
||||||
|
/// https://sw.kovidgoyal.net/kitty/color-stack/#id1
|
||||||
|
kitty_color_protocol: KittyColorProtocol,
|
||||||
|
|
||||||
/// Show a desktop notification (OSC 9 or OSC 777)
|
/// Show a desktop notification (OSC 9 or OSC 777)
|
||||||
show_desktop_notification: struct {
|
show_desktop_notification: struct {
|
||||||
title: []const u8,
|
title: []const u8,
|
||||||
@ -167,6 +172,34 @@ pub const Command = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const KittyColorProtocol = struct {
|
||||||
|
const Kind = enum {
|
||||||
|
foreground,
|
||||||
|
background,
|
||||||
|
selection_foreground,
|
||||||
|
selection_background,
|
||||||
|
cursor,
|
||||||
|
cursor_text,
|
||||||
|
visual_bell,
|
||||||
|
second_transparent_background,
|
||||||
|
};
|
||||||
|
const Request = union(enum) {
|
||||||
|
query: Kind,
|
||||||
|
set: struct {
|
||||||
|
key: Kind,
|
||||||
|
color: RGB,
|
||||||
|
},
|
||||||
|
reset: Kind,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// list of requests
|
||||||
|
list: std.ArrayList(Request),
|
||||||
|
|
||||||
|
/// We must reply with the same string terminator (ST) as used in the
|
||||||
|
/// request.
|
||||||
|
terminator: Terminator = .st,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The terminator used to end an OSC command. For OSC commands that demand
|
/// The terminator used to end an OSC command. For OSC commands that demand
|
||||||
@ -251,6 +284,7 @@ pub const Parser = struct {
|
|||||||
@"13",
|
@"13",
|
||||||
@"133",
|
@"133",
|
||||||
@"2",
|
@"2",
|
||||||
|
@"21",
|
||||||
@"22",
|
@"22",
|
||||||
@"4",
|
@"4",
|
||||||
@"5",
|
@"5",
|
||||||
@ -310,6 +344,11 @@ pub const Parser = struct {
|
|||||||
// If the parser has no allocator then it is treated as if the
|
// If the parser has no allocator then it is treated as if the
|
||||||
// buffer is full.
|
// buffer is full.
|
||||||
allocable_string,
|
allocable_string,
|
||||||
|
|
||||||
|
// Kitty color protocol
|
||||||
|
// https://sw.kovidgoyal.net/kitty/color-stack/#id1
|
||||||
|
kitty_color_protocol_key,
|
||||||
|
kitty_color_protocol_value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This must be called to clean up any allocated memory.
|
/// This must be called to clean up any allocated memory.
|
||||||
@ -323,6 +362,9 @@ pub const Parser = struct {
|
|||||||
self.buf_start = 0;
|
self.buf_start = 0;
|
||||||
self.buf_idx = 0;
|
self.buf_idx = 0;
|
||||||
self.complete = false;
|
self.complete = false;
|
||||||
|
if (self.command == .kitty_color_protocol) {
|
||||||
|
self.command.kitty_color_protocol.list.deinit();
|
||||||
|
}
|
||||||
if (self.buf_dynamic) |ptr| {
|
if (self.buf_dynamic) |ptr| {
|
||||||
const alloc = self.alloc.?;
|
const alloc = self.alloc.?;
|
||||||
ptr.deinit(alloc);
|
ptr.deinit(alloc);
|
||||||
@ -439,6 +481,7 @@ pub const Parser = struct {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.@"2" => switch (c) {
|
.@"2" => switch (c) {
|
||||||
|
'1' => self.state = .@"21",
|
||||||
'2' => self.state = .@"22",
|
'2' => self.state = .@"22",
|
||||||
';' => {
|
';' => {
|
||||||
self.command = .{ .change_window_title = undefined };
|
self.command = .{ .change_window_title = undefined };
|
||||||
@ -450,6 +493,45 @@ pub const Parser = struct {
|
|||||||
else => self.state = .invalid,
|
else => self.state = .invalid,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.@"21" => switch (c) {
|
||||||
|
';' => {
|
||||||
|
self.command = .{
|
||||||
|
.kitty_color_protocol = .{
|
||||||
|
.list = std.ArrayList(Command.KittyColorProtocol.Request).init(self.alloc.?),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.state = .kitty_color_protocol_key;
|
||||||
|
self.complete = true;
|
||||||
|
self.buf_start = self.buf_idx;
|
||||||
|
},
|
||||||
|
else => self.state = .invalid,
|
||||||
|
},
|
||||||
|
|
||||||
|
.kitty_color_protocol_key => switch (c) {
|
||||||
|
';' => {
|
||||||
|
self.temp_state = .{ .key = self.buf[self.buf_start .. self.buf_idx - 1] };
|
||||||
|
self.endKittyColorProtocolOption(.key_only, false);
|
||||||
|
self.state = .kitty_color_protocol_key;
|
||||||
|
self.buf_start = self.buf_idx;
|
||||||
|
},
|
||||||
|
'=' => {
|
||||||
|
self.temp_state = .{ .key = self.buf[self.buf_start .. self.buf_idx - 1] };
|
||||||
|
self.state = .kitty_color_protocol_value;
|
||||||
|
self.buf_start = self.buf_idx;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
|
||||||
|
.kitty_color_protocol_value => switch (c) {
|
||||||
|
';' => {
|
||||||
|
self.endKittyColorProtocolOption(.key_and_value, false);
|
||||||
|
self.state = .kitty_color_protocol_key;
|
||||||
|
self.buf_start = self.buf_idx;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
|
||||||
.@"22" => switch (c) {
|
.@"22" => switch (c) {
|
||||||
';' => {
|
';' => {
|
||||||
self.command = .{ .mouse_shape = undefined };
|
self.command = .{ .mouse_shape = undefined };
|
||||||
@ -936,6 +1018,56 @@ pub const Parser = struct {
|
|||||||
self.temp_state.str.* = self.buf[self.buf_start..self.buf_idx];
|
self.temp_state.str.* = self.buf[self.buf_start..self.buf_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn endKittyColorProtocolOption(self: *Parser, kind: enum { key_only, key_and_value }, final: bool) void {
|
||||||
|
if (self.temp_state.key.len == 0) {
|
||||||
|
log.warn("zero length key in kitty color protocol", .{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = std.meta.stringToEnum(Command.KittyColorProtocol.Kind, self.temp_state.key) orelse {
|
||||||
|
log.warn("unknown key in kitty color protocol: {s}", .{self.temp_state.key});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = value: {
|
||||||
|
if (self.buf_start == self.buf_idx) break :value "";
|
||||||
|
if (final) break :value std.mem.trim(u8, self.buf[self.buf_start..self.buf_idx], " ");
|
||||||
|
break :value std.mem.trim(u8, self.buf[self.buf_start .. self.buf_idx - 1], " ");
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (self.command) {
|
||||||
|
.kitty_color_protocol => |*v| {
|
||||||
|
if (kind == .key_only) {
|
||||||
|
v.list.append(.{ .reset = key }) catch unreachable;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.len == 0) {
|
||||||
|
v.list.append(.{ .reset = key }) catch unreachable;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mem.eql(u8, "?", value)) {
|
||||||
|
v.list.append(.{ .query = key }) catch unreachable;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
v.list.append(
|
||||||
|
.{
|
||||||
|
.set = .{
|
||||||
|
.key = key,
|
||||||
|
.color = RGB.parse(value) catch |err| switch (err) {
|
||||||
|
error.InvalidFormat => {
|
||||||
|
log.err("invalid color format in kitty color protocol: {s}", .{value});
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
) catch unreachable;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn endAllocableString(self: *Parser) void {
|
fn endAllocableString(self: *Parser) void {
|
||||||
const list = self.buf_dynamic.?;
|
const list = self.buf_dynamic.?;
|
||||||
self.temp_state.str.* = list.items;
|
self.temp_state.str.* = list.items;
|
||||||
@ -958,11 +1090,14 @@ pub const Parser = struct {
|
|||||||
.hyperlink_uri => self.endHyperlink(),
|
.hyperlink_uri => self.endHyperlink(),
|
||||||
.string => self.endString(),
|
.string => self.endString(),
|
||||||
.allocable_string => self.endAllocableString(),
|
.allocable_string => self.endAllocableString(),
|
||||||
|
.kitty_color_protocol_key => self.endKittyColorProtocolOption(.key_only, true),
|
||||||
|
.kitty_color_protocol_value => self.endKittyColorProtocolOption(.key_and_value, true),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (self.command) {
|
switch (self.command) {
|
||||||
.report_color => |*c| c.terminator = Terminator.init(terminator_ch),
|
.report_color => |*c| c.terminator = Terminator.init(terminator_ch),
|
||||||
|
.kitty_color_protocol => |*c| c.terminator = Terminator.init(terminator_ch),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1497,3 +1632,40 @@ test "OSC: hyperlink end" {
|
|||||||
const cmd = p.end('\x1b').?;
|
const cmd = p.end('\x1b').?;
|
||||||
try testing.expect(cmd == .hyperlink_end);
|
try testing.expect(cmd == .hyperlink_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "OSC: kitty color protocol" {
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var p: Parser = .{ .alloc = std.testing.allocator };
|
||||||
|
defer p.deinit();
|
||||||
|
|
||||||
|
const input = "21;foreground=?;background=rgb:f0/f8/ff;cursor=aliceblue;cursor_text;visual_bell=;selection_foreground=#xxxyyzz;selection_background=?;selection_background=#aabbcc";
|
||||||
|
for (input) |ch| p.next(ch);
|
||||||
|
|
||||||
|
const cmd = p.end('\x1b').?;
|
||||||
|
try testing.expect(cmd == .kitty_color_protocol);
|
||||||
|
try testing.expectEqual(@as(usize, 7), cmd.kitty_color_protocol.list.items.len);
|
||||||
|
try testing.expect(cmd.kitty_color_protocol.list.items[0] == .query);
|
||||||
|
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, .foreground), cmd.kitty_color_protocol.list.items[0].query);
|
||||||
|
try testing.expect(cmd.kitty_color_protocol.list.items[1] == .set);
|
||||||
|
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, .background), cmd.kitty_color_protocol.list.items[1].set.key);
|
||||||
|
try testing.expectEqual(@as(u8, 0xf0), cmd.kitty_color_protocol.list.items[1].set.color.r);
|
||||||
|
try testing.expectEqual(@as(u8, 0xf8), cmd.kitty_color_protocol.list.items[1].set.color.g);
|
||||||
|
try testing.expectEqual(@as(u8, 0xff), cmd.kitty_color_protocol.list.items[1].set.color.b);
|
||||||
|
try testing.expect(cmd.kitty_color_protocol.list.items[2] == .set);
|
||||||
|
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, .cursor), cmd.kitty_color_protocol.list.items[2].set.key);
|
||||||
|
try testing.expectEqual(@as(u8, 0xf0), cmd.kitty_color_protocol.list.items[2].set.color.r);
|
||||||
|
try testing.expectEqual(@as(u8, 0xf8), cmd.kitty_color_protocol.list.items[2].set.color.g);
|
||||||
|
try testing.expectEqual(@as(u8, 0xff), cmd.kitty_color_protocol.list.items[2].set.color.b);
|
||||||
|
try testing.expect(cmd.kitty_color_protocol.list.items[3] == .reset);
|
||||||
|
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, .cursor_text), cmd.kitty_color_protocol.list.items[3].reset);
|
||||||
|
try testing.expect(cmd.kitty_color_protocol.list.items[4] == .reset);
|
||||||
|
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, .visual_bell), cmd.kitty_color_protocol.list.items[4].reset);
|
||||||
|
try testing.expect(cmd.kitty_color_protocol.list.items[5] == .query);
|
||||||
|
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, .selection_background), cmd.kitty_color_protocol.list.items[5].query);
|
||||||
|
try testing.expect(cmd.kitty_color_protocol.list.items[6] == .set);
|
||||||
|
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, .selection_background), cmd.kitty_color_protocol.list.items[6].set.key);
|
||||||
|
try testing.expectEqual(@as(u8, 0xaa), cmd.kitty_color_protocol.list.items[6].set.color.r);
|
||||||
|
try testing.expectEqual(@as(u8, 0xbb), cmd.kitty_color_protocol.list.items[6].set.color.g);
|
||||||
|
try testing.expectEqual(@as(u8, 0xcc), cmd.kitty_color_protocol.list.items[6].set.color.b);
|
||||||
|
}
|
||||||
|
@ -1393,6 +1393,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.kitty_color_protocol => |v| {
|
||||||
|
if (@hasDecl(T, "sendKittyColorReport")) {
|
||||||
|
try self.handler.sendKittyColorReport(v);
|
||||||
|
return;
|
||||||
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
|
},
|
||||||
|
|
||||||
.show_desktop_notification => |v| {
|
.show_desktop_notification => |v| {
|
||||||
if (@hasDecl(T, "showDesktopNotification")) {
|
if (@hasDecl(T, "showDesktopNotification")) {
|
||||||
try self.handler.showDesktopNotification(v.title, v.body);
|
try self.handler.showDesktopNotification(v.title, v.body);
|
||||||
|
@ -1269,4 +1269,97 @@ pub const StreamHandler = struct {
|
|||||||
.csi_21_t => self.surfaceMessageWriter(.{ .report_title = .csi_21_t }),
|
.csi_21_t => self.surfaceMessageWriter(.{ .report_title = .csi_21_t }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sendKittyColorReport(self: *StreamHandler, request: terminal.osc.Command.KittyColorProtocol) !void {
|
||||||
|
var buf = std.ArrayList(u8).init(self.alloc);
|
||||||
|
errdefer buf.deinit();
|
||||||
|
const writer = buf.writer();
|
||||||
|
try writer.writeAll("\x1b[21");
|
||||||
|
|
||||||
|
for (request.list.items) |item| {
|
||||||
|
switch (item) {
|
||||||
|
.query => |key| {
|
||||||
|
const color = switch (key) {
|
||||||
|
.foreground => self.foreground_color,
|
||||||
|
.background => self.background_color,
|
||||||
|
.cursor => self.cursor_color,
|
||||||
|
else => {
|
||||||
|
log.warn("ignoring unsupported kitty color protocol key: {s}", .{@tagName(key)});
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
} orelse {
|
||||||
|
log.warn("no color configured for: {s}", .{@tagName(key)});
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
try writer.print(
|
||||||
|
";rgb:{x:0>2}/{x:0>2}/{x:0>2}",
|
||||||
|
.{
|
||||||
|
@as(u16, color.r),
|
||||||
|
@as(u16, color.g),
|
||||||
|
@as(u16, color.b),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
.set => |v| switch (v.key) {
|
||||||
|
.foreground => {
|
||||||
|
self.foreground_color = v.color;
|
||||||
|
_ = self.renderer_mailbox.push(.{
|
||||||
|
.foreground_color = v.color,
|
||||||
|
}, .{ .forever = {} });
|
||||||
|
},
|
||||||
|
.background => {
|
||||||
|
self.background_color = v.color;
|
||||||
|
_ = self.renderer_mailbox.push(.{
|
||||||
|
.background_color = v.color,
|
||||||
|
}, .{ .forever = {} });
|
||||||
|
},
|
||||||
|
.cursor => {
|
||||||
|
self.cursor_color = v.color;
|
||||||
|
_ = self.renderer_mailbox.push(.{
|
||||||
|
.cursor_color = v.color,
|
||||||
|
}, .{ .forever = {} });
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
log.warn("ignoring unsupported kitty color protocol key: {s}", .{@tagName(v.key)});
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.reset => |key| switch (key) {
|
||||||
|
.foreground => {
|
||||||
|
self.foreground_color = self.default_foreground_color;
|
||||||
|
_ = self.renderer_mailbox.push(.{
|
||||||
|
.foreground_color = self.foreground_color,
|
||||||
|
}, .{ .forever = {} });
|
||||||
|
},
|
||||||
|
.background => {
|
||||||
|
self.background_color = self.default_background_color;
|
||||||
|
_ = self.renderer_mailbox.push(.{
|
||||||
|
.background_color = self.background_color,
|
||||||
|
}, .{ .forever = {} });
|
||||||
|
},
|
||||||
|
.cursor => {
|
||||||
|
self.cursor_color = self.default_cursor_color;
|
||||||
|
_ = self.renderer_mailbox.push(.{
|
||||||
|
.cursor_color = self.cursor_color,
|
||||||
|
}, .{ .forever = {} });
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
log.warn("ignoring unsupported kitty color protocol key: {s}", .{@tagName(key)});
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try writer.writeAll(request.terminator.string());
|
||||||
|
|
||||||
|
const msg = termio.Message{
|
||||||
|
.write_alloc = .{
|
||||||
|
.alloc = self.alloc,
|
||||||
|
.data = try buf.toOwnedSlice(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.messageWriter(msg);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user