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 = .{},
|
@"shell-integration-features": ShellIntegrationFeatures = .{},
|
||||||
|
|
||||||
/// Sets the reporting format for OSC sequences that request color information.
|
/// Sets the reporting format for OSC sequences that request color information.
|
||||||
/// Ghostty currently supports OSC 10 (foreground) and OSC 11 (background) queries,
|
/// Ghostty currently supports OSC 10 (foreground), OSC 11 (background), and OSC
|
||||||
/// and by default the reported values are scaled-up RGB values, where each component
|
/// 4 (256 color palette) queries, and by default the reported values are
|
||||||
/// are 16 bits. This is how most terminals report these values. However, some legacy
|
/// scaled-up RGB values, where each component are 16 bits. This is how most
|
||||||
/// applications may require 8-bit, unscaled, components. We also support turning off
|
/// terminals report these values. However, some legacy applications may require
|
||||||
/// reporting alltogether. The components are lowercase hex values.
|
/// 8-bit, unscaled, components. We also support turning off reporting
|
||||||
|
/// alltogether. The components are lowercase hex values.
|
||||||
///
|
///
|
||||||
/// Allowable values are:
|
/// 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
|
/// * "8-bit" - Color components are return unscaled, i.e. rr/gg/bb
|
||||||
/// * "16-bit" - Color components are returned scaled, e.g. rrrr/gggg/bbbb
|
/// * "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)),
|
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) {
|
else => switch (Value) {
|
||||||
u8 => try md.put(
|
u8 => try md.put(
|
||||||
key,
|
key,
|
||||||
|
@ -94,9 +94,10 @@ pub const Command = union(enum) {
|
|||||||
value: []const u8,
|
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 {
|
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,
|
kind: DefaultColorKind,
|
||||||
|
|
||||||
/// We must reply with the same string terminator (ST) as used in the
|
/// 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,
|
terminator: Terminator = .st,
|
||||||
},
|
},
|
||||||
|
|
||||||
pub const DefaultColorKind = enum {
|
pub const DefaultColorKind = union(enum) {
|
||||||
foreground,
|
foreground,
|
||||||
background,
|
background,
|
||||||
|
palette: u8,
|
||||||
|
|
||||||
pub fn code(self: DefaultColorKind) []const u8 {
|
pub fn code(self: DefaultColorKind) []const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.foreground => "10",
|
.foreground => "10",
|
||||||
.background => "11",
|
.background => "11",
|
||||||
|
.palette => "4",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -199,6 +202,7 @@ pub const Parser = struct {
|
|||||||
@"133",
|
@"133",
|
||||||
@"2",
|
@"2",
|
||||||
@"22",
|
@"22",
|
||||||
|
@"4",
|
||||||
@"5",
|
@"5",
|
||||||
@"52",
|
@"52",
|
||||||
@"7",
|
@"7",
|
||||||
@ -224,6 +228,10 @@ pub const Parser = struct {
|
|||||||
clipboard_kind,
|
clipboard_kind,
|
||||||
clipboard_kind_end,
|
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
|
// Expect a string parameter. param_str must be set as well as
|
||||||
// buf_start.
|
// buf_start.
|
||||||
string,
|
string,
|
||||||
@ -277,6 +285,7 @@ pub const Parser = struct {
|
|||||||
'0' => self.state = .@"0",
|
'0' => self.state = .@"0",
|
||||||
'1' => self.state = .@"1",
|
'1' => self.state = .@"1",
|
||||||
'2' => self.state = .@"2",
|
'2' => self.state = .@"2",
|
||||||
|
'4' => self.state = .@"4",
|
||||||
'5' => self.state = .@"5",
|
'5' => self.state = .@"5",
|
||||||
'7' => self.state = .@"7",
|
'7' => self.state = .@"7",
|
||||||
else => self.state = .invalid,
|
else => self.state = .invalid,
|
||||||
@ -348,6 +357,39 @@ pub const Parser = struct {
|
|||||||
else => self.state = .invalid,
|
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) {
|
.@"5" => switch (c) {
|
||||||
'2' => self.state = .@"52",
|
'2' => self.state = .@"52",
|
||||||
else => self.state = .invalid,
|
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.kind, .background);
|
||||||
try testing.expectEqual(cmd.report_default_color.terminator, .bel);
|
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
|
/// Implements OSC 4, OSC 10, and OSC 11, which reports palette color,
|
||||||
/// background color respectively.
|
/// default foreground color, and background color respectively.
|
||||||
pub fn reportDefaultColor(
|
pub fn reportDefaultColor(
|
||||||
self: *StreamHandler,
|
self: *StreamHandler,
|
||||||
kind: terminal.osc.Command.DefaultColorKind,
|
kind: terminal.osc.Command.DefaultColorKind,
|
||||||
@ -2162,6 +2162,7 @@ const StreamHandler = struct {
|
|||||||
const color = switch (kind) {
|
const color = switch (kind) {
|
||||||
.foreground => self.default_foreground_color,
|
.foreground => self.default_foreground_color,
|
||||||
.background => self.default_background_color,
|
.background => self.default_background_color,
|
||||||
|
.palette => |i| self.terminal.color_palette[i],
|
||||||
};
|
};
|
||||||
|
|
||||||
var msg: termio.Message = .{ .write_small = .{} };
|
var msg: termio.Message = .{ .write_small = .{} };
|
||||||
|
Reference in New Issue
Block a user