core: implement OSC 12 and OSC 112 to query/set/reset cursor color

This commit is contained in:
Gregory Anders
2023-11-09 16:10:43 -06:00
parent 33753f59c8
commit 171292a063
7 changed files with 93 additions and 10 deletions

View File

@ -72,6 +72,10 @@ foreground_color: terminal.color.RGB,
/// changed by a terminal application
background_color: terminal.color.RGB,
/// The actual cursor color. May differ from the config cursor color if changed
/// by a terminal application
cursor_color: ?terminal.color.RGB,
/// The current set of cells to render. This is rebuilt on every frame
/// but we keep this around so that we don't reallocate. Each set of
/// cells goes into a separate shader.
@ -264,6 +268,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
.focused = true,
.foreground_color = options.config.foreground,
.background_color = options.config.background,
.cursor_color = options.config.cursor_color,
// Render state
.cells_bg = .{},
@ -1444,7 +1449,7 @@ fn addCursor(
), screen.cursor.x - 1 };
};
const color = self.config.cursor_color orelse self.foreground_color;
const color = self.cursor_color orelse self.foreground_color;
const alpha: u8 = if (!self.focused) 255 else alpha: {
const alpha = 255 * self.config.cursor_opacity;
break :alpha @intFromFloat(@ceil(alpha));

View File

@ -75,6 +75,10 @@ foreground_color: terminal.color.RGB,
/// changed by a terminal application
background_color: terminal.color.RGB,
/// The actual cursor color. May differ from the config cursor color if changed
/// by a terminal application
cursor_color: ?terminal.color.RGB,
/// Padding options
padding: renderer.Options.Padding,
@ -320,6 +324,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
.focused = true,
.foreground_color = options.config.foreground,
.background_color = options.config.background,
.cursor_color = options.config.cursor_color,
.padding = options.padding,
.surface_mailbox = options.surface_mailbox,
.deferred_font_size = .{ .metrics = metrics },
@ -888,7 +893,7 @@ fn addCursor(
), screen.cursor.x - 1 };
};
const color = self.config.cursor_color orelse self.foreground_color;
const color = self.cursor_color orelse self.foreground_color;
const alpha: u8 = if (!self.focused) 255 else alpha: {
const alpha = 255 * self.config.cursor_opacity;
break :alpha @intFromFloat(@ceil(alpha));

View File

@ -270,6 +270,10 @@ fn drainMailbox(self: *Thread) !void {
self.renderer.background_color = color;
},
.cursor_color => |color| {
self.renderer.cursor_color = color;
},
.resize => |v| {
try self.renderer.setScreenSize(v.screen_size, v.padding);
},

View File

@ -29,6 +29,10 @@ pub const Message = union(enum) {
/// the config file in response to an OSC 11 command.
background_color: terminal.color.RGB,
/// Change the cursor color. This can be done separately from changing the
/// config file in response to an OSC 12 command.
cursor_color: ?terminal.color.RGB,
/// Changes the screen size.
resize: struct {
/// The full screen (drawable) size. This does NOT include padding.

View File

@ -827,7 +827,8 @@ test "osc: 112 incomplete sequence" {
try testing.expect(a[2] == null);
const cmd = a[0].?.osc_dispatch;
try testing.expect(cmd == .reset_cursor_color);
try testing.expect(cmd == .reset_color);
try testing.expectEqual(cmd.reset_color.kind, .cursor);
}
}

View File

@ -64,10 +64,6 @@ pub const Command = union(enum) {
// TODO: err option
},
/// Reset the color for the cursor. This reverts changes made with
/// change/read cursor color.
reset_cursor_color: void,
/// Set or get clipboard contents. If data is null, then the current
/// clipboard contents are sent to the pty. If data is set, this
/// contents is set on the clipboard.
@ -129,12 +125,14 @@ pub const Command = union(enum) {
palette: u8,
foreground,
background,
cursor,
pub fn code(self: ColorKind) []const u8 {
return switch (self) {
.palette => "4",
.foreground => "10",
.background => "11",
.cursor => "12",
};
}
};
@ -218,6 +216,7 @@ pub const Parser = struct {
@"1",
@"10",
@"11",
@"12",
@"13",
@"133",
@"2",
@ -233,6 +232,9 @@ pub const Parser = struct {
// OSC 11 is used to query or set the current background color.
query_bg_color,
// OSC 12 is used to query or set the current cursor color.
query_cursor_color,
// We're in a semantic prompt OSC command but we aren't sure
// what the command is yet, i.e. `133;`
semantic_prompt,
@ -326,6 +328,7 @@ pub const Parser = struct {
.@"1" => switch (c) {
'0' => self.state = .@"10",
'1' => self.state = .@"11",
'2' => self.state = .@"12",
'3' => self.state = .@"13",
else => self.state = .invalid,
},
@ -357,13 +360,18 @@ pub const Parser = struct {
self.state = .invalid;
},
'2' => {
self.command = .{ .reset_color = .{ .kind = .cursor, .value = undefined } };
self.complete = true;
self.command = .{ .reset_cursor_color = {} };
self.state = .invalid;
},
else => self.state = .invalid,
},
.@"12" => switch (c) {
';' => self.state = .query_cursor_color,
else => self.state = .invalid,
},
.@"13" => switch (c) {
'3' => self.state = .@"133",
else => self.state = .invalid,
@ -534,6 +542,24 @@ pub const Parser = struct {
},
},
.query_cursor_color => switch (c) {
'?' => {
self.command = .{ .report_color = .{ .kind = .cursor } };
self.complete = true;
self.state = .invalid;
},
else => {
self.command = .{ .set_color = .{
.kind = .cursor,
.value = "",
} };
self.state = .string;
self.temp_state = .{ .str = &self.command.set_color.value };
self.buf_start = self.buf_idx - 1;
},
},
.semantic_prompt => switch (c) {
'A' => {
self.state = .semantic_option_start;
@ -912,7 +938,7 @@ test "OSC: end_of_input" {
try testing.expect(cmd == .end_of_input);
}
test "OSC: reset_cursor_color" {
test "OSC: reset cursor color" {
const testing = std.testing;
var p: Parser = .{};
@ -921,7 +947,8 @@ test "OSC: reset_cursor_color" {
for (input) |ch| p.next(ch);
const cmd = p.end(null).?;
try testing.expect(cmd == .reset_cursor_color);
try testing.expect(cmd == .reset_color);
try testing.expectEqual(cmd.reset_color.kind, .cursor);
}
test "OSC: get/set clipboard" {

View File

@ -69,6 +69,10 @@ grid_size: renderer.GridSize,
/// it when a CSI q with default is called.
default_cursor_style: terminal.Cursor.Style,
default_cursor_blink: ?bool,
default_cursor_color: ?terminal.color.RGB,
/// Actual cursor color
cursor_color: ?terminal.color.RGB,
/// Default foreground color as set by the config file
default_foreground_color: terminal.color.RGB,
@ -96,6 +100,7 @@ pub const DerivedConfig = struct {
image_storage_limit: usize,
cursor_style: terminal.Cursor.Style,
cursor_blink: ?bool,
cursor_color: ?configpkg.Config.Color,
foreground: configpkg.Config.Color,
background: configpkg.Config.Color,
osc_color_report_format: configpkg.Config.OSCColorReportFormat,
@ -112,6 +117,7 @@ pub const DerivedConfig = struct {
.image_storage_limit = config.@"image-storage-limit",
.cursor_style = config.@"cursor-style",
.cursor_blink = config.@"cursor-style-blink",
.cursor_color = config.@"cursor-color",
.foreground = config.foreground,
.background = config.background,
.osc_color_report_format = config.@"osc-color-report-format",
@ -175,6 +181,14 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
.grid_size = opts.grid_size,
.default_cursor_style = opts.config.cursor_style,
.default_cursor_blink = opts.config.cursor_blink,
.default_cursor_color = if (opts.config.cursor_color) |col|
col.toTerminalRGB()
else
null,
.cursor_color = if (opts.config.cursor_color) |col|
col.toTerminalRGB()
else
null,
.default_foreground_color = config.foreground.toTerminalRGB(),
.default_background_color = config.background.toTerminalRGB(),
.foreground_color = config.foreground.toTerminalRGB(),
@ -244,6 +258,8 @@ pub fn threadEnter(self: *Exec, thread: *termio.Thread) !ThreadData {
.grid_size = &self.grid_size,
.default_cursor_style = self.default_cursor_style,
.default_cursor_blink = self.default_cursor_blink,
.default_cursor_color = self.default_cursor_color,
.cursor_color = self.cursor_color,
.default_foreground_color = self.default_foreground_color,
.default_background_color = self.default_background_color,
.foreground_color = self.foreground_color,
@ -337,6 +353,10 @@ pub fn changeConfig(self: *Exec, config: *DerivedConfig) !void {
// Update our default cursor style
self.default_cursor_style = config.cursor_style;
self.default_cursor_blink = config.cursor_blink;
self.default_cursor_color = if (config.cursor_color) |col|
col.toTerminalRGB()
else
null;
// Update default foreground and background colors
self.default_foreground_color = config.foreground.toTerminalRGB();
@ -1340,6 +1360,10 @@ const StreamHandler = struct {
default_cursor: bool = true,
default_cursor_style: terminal.Cursor.Style,
default_cursor_blink: ?bool,
default_cursor_color: ?terminal.color.RGB,
/// Actual cursor color. This can be changed with OSC 12.
cursor_color: ?terminal.color.RGB,
/// The default foreground and background color are those set by the user's
/// config file. These can be overridden by terminal applications using OSC
@ -2188,6 +2212,7 @@ const StreamHandler = struct {
.palette => |i| self.terminal.color_palette.colors[i],
.foreground => self.foreground_color,
.background => self.background_color,
.cursor => self.cursor_color orelse self.foreground_color,
};
var msg: termio.Message = .{ .write_small = .{} };
@ -2246,6 +2271,12 @@ const StreamHandler = struct {
.background_color = color,
}, .{ .forever = {} });
},
.cursor => {
self.cursor_color = color;
_ = self.ev.renderer_mailbox.push(.{
.cursor_color = color,
}, .{ .forever = {} });
},
}
}
@ -2295,6 +2326,12 @@ const StreamHandler = struct {
.background_color = self.background_color,
}, .{ .forever = {} });
},
.cursor => {
self.cursor_color = self.default_cursor_color;
_ = self.ev.renderer_mailbox.push(.{
.cursor_color = self.cursor_color,
}, .{ .forever = {} });
},
}
}
};