mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
core: implement querying with OSC 4
This commit is contained in:
@ -551,15 +551,16 @@ keybind: Keybinds = .{},
|
||||
@"shell-integration-features": ShellIntegrationFeatures = .{},
|
||||
|
||||
/// Sets the reporting format for OSC sequences that request color information.
|
||||
/// Ghostty currently supports OSC 10 (foreground) and OSC 11 (background) queries,
|
||||
/// and by default the reported values are scaled-up RGB values, where each component
|
||||
/// are 16 bits. This is how most terminals report these values. However, some legacy
|
||||
/// applications may require 8-bit, unscaled, components. We also support turning off
|
||||
/// reporting alltogether. The components are lowercase hex values.
|
||||
/// Ghostty currently supports OSC 10 (foreground), OSC 11 (background), and OSC
|
||||
/// 4 (256 color palette) queries, and by default the reported values are
|
||||
/// scaled-up RGB values, where each component are 16 bits. This is how most
|
||||
/// terminals report these values. However, some legacy applications may require
|
||||
/// 8-bit, unscaled, components. We also support turning off reporting
|
||||
/// alltogether. The components are lowercase hex values.
|
||||
///
|
||||
/// Allowable values are:
|
||||
///
|
||||
/// * "none" - OSC 10/11 queries receive no reply
|
||||
/// * "none" - OSC 4/10/11 queries receive no reply
|
||||
/// * "8-bit" - Color components are return unscaled, i.e. rr/gg/bb
|
||||
/// * "16-bit" - Color components are returned scaled, e.g. rrrr/gggg/bbbb
|
||||
///
|
||||
|
@ -241,6 +241,25 @@ pub const VTEvent = struct {
|
||||
try alloc.dupeZ(u8, @tagName(value)),
|
||||
),
|
||||
|
||||
.Union => |u| if (u.tag_type) |Tag| {
|
||||
const tag_name = @tagName(@as(Tag, value));
|
||||
inline for (u.fields) |field| {
|
||||
if (std.mem.eql(u8, field.name, tag_name)) {
|
||||
const s = if (field.type == void)
|
||||
try alloc.dupeZ(u8, tag_name)
|
||||
else
|
||||
try std.fmt.allocPrintZ(alloc, "{s}={}", .{
|
||||
tag_name,
|
||||
@field(value, field.name),
|
||||
});
|
||||
|
||||
try md.put(key, s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@compileError("Unions must have a tag");
|
||||
},
|
||||
|
||||
else => switch (Value) {
|
||||
u8 => try md.put(
|
||||
key,
|
||||
|
@ -94,9 +94,10 @@ pub const Command = union(enum) {
|
||||
value: []const u8,
|
||||
},
|
||||
|
||||
/// OSC 10 and OSC 11 default color report.
|
||||
/// OSC 4, OSC 10, and OSC 11 default color report.
|
||||
report_default_color: struct {
|
||||
/// OSC 10 requests the foreground color, OSC 11 the background color.
|
||||
/// OSC 4 requests a palette color, OSC 10 requests the foreground
|
||||
/// color, OSC 11 the background color.
|
||||
kind: DefaultColorKind,
|
||||
|
||||
/// We must reply with the same string terminator (ST) as used in the
|
||||
@ -104,14 +105,16 @@ pub const Command = union(enum) {
|
||||
terminator: Terminator = .st,
|
||||
},
|
||||
|
||||
pub const DefaultColorKind = enum {
|
||||
pub const DefaultColorKind = union(enum) {
|
||||
foreground,
|
||||
background,
|
||||
palette: u8,
|
||||
|
||||
pub fn code(self: DefaultColorKind) []const u8 {
|
||||
return switch (self) {
|
||||
.foreground => "10",
|
||||
.background => "11",
|
||||
.palette => "4",
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -199,6 +202,7 @@ pub const Parser = struct {
|
||||
@"133",
|
||||
@"2",
|
||||
@"22",
|
||||
@"4",
|
||||
@"5",
|
||||
@"52",
|
||||
@"7",
|
||||
@ -224,6 +228,10 @@ pub const Parser = struct {
|
||||
clipboard_kind,
|
||||
clipboard_kind_end,
|
||||
|
||||
// Get/set color palette index
|
||||
color_palette_index,
|
||||
color_palette_index_end,
|
||||
|
||||
// Expect a string parameter. param_str must be set as well as
|
||||
// buf_start.
|
||||
string,
|
||||
@ -277,6 +285,7 @@ pub const Parser = struct {
|
||||
'0' => self.state = .@"0",
|
||||
'1' => self.state = .@"1",
|
||||
'2' => self.state = .@"2",
|
||||
'4' => self.state = .@"4",
|
||||
'5' => self.state = .@"5",
|
||||
'7' => self.state = .@"7",
|
||||
else => self.state = .invalid,
|
||||
@ -348,6 +357,39 @@ pub const Parser = struct {
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"4" => switch (c) {
|
||||
';' => {
|
||||
self.state = .color_palette_index;
|
||||
self.buf_start = self.buf_idx;
|
||||
},
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.color_palette_index => switch (c) {
|
||||
'0'...'9' => {},
|
||||
';' => {
|
||||
if (std.fmt.parseUnsigned(u8, self.buf[self.buf_start .. self.buf_idx - 1], 10)) |num| {
|
||||
self.state = .color_palette_index_end;
|
||||
self.temp_state = .{ .num = num };
|
||||
} else |err| switch (err) {
|
||||
error.Overflow => self.state = .invalid,
|
||||
error.InvalidCharacter => unreachable,
|
||||
}
|
||||
},
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.color_palette_index_end => switch (c) {
|
||||
'?' => {
|
||||
self.command = .{ .report_default_color = .{
|
||||
.kind = .{ .palette = @intCast(self.temp_state.num) },
|
||||
} };
|
||||
|
||||
self.complete = true;
|
||||
},
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"5" => switch (c) {
|
||||
'2' => self.state = .@"52",
|
||||
else => self.state = .invalid,
|
||||
@ -921,3 +963,17 @@ test "OSC: report default background color" {
|
||||
try testing.expectEqual(cmd.report_default_color.kind, .background);
|
||||
try testing.expectEqual(cmd.report_default_color.terminator, .bel);
|
||||
}
|
||||
|
||||
test "OSC: get palette color" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .{};
|
||||
|
||||
const input = "4;1;?";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?;
|
||||
try testing.expect(cmd == .report_default_color);
|
||||
try testing.expectEqual(cmd.report_default_color.kind, .{ .palette = 1 });
|
||||
try testing.expectEqual(cmd.report_default_color.terminator, .st);
|
||||
}
|
||||
|
@ -2150,8 +2150,8 @@ const StreamHandler = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements OSC 10 and OSC 11, which reports default foreground and
|
||||
/// background color respectively.
|
||||
/// Implements OSC 4, OSC 10, and OSC 11, which reports palette color,
|
||||
/// default foreground color, and background color respectively.
|
||||
pub fn reportDefaultColor(
|
||||
self: *StreamHandler,
|
||||
kind: terminal.osc.Command.DefaultColorKind,
|
||||
@ -2162,6 +2162,7 @@ const StreamHandler = struct {
|
||||
const color = switch (kind) {
|
||||
.foreground => self.default_foreground_color,
|
||||
.background => self.default_background_color,
|
||||
.palette => |i| self.terminal.color_palette[i],
|
||||
};
|
||||
|
||||
var msg: termio.Message = .{ .write_small = .{} };
|
||||
|
Reference in New Issue
Block a user