terminal: move color state fully into the terminal for fg/bg/cursor

pull/9412/head
Mitchell Hashimoto 2025-10-30 09:26:58 -07:00
parent cabca0aca8
commit 77343bb06e
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
4 changed files with 92 additions and 114 deletions

View File

@ -4960,6 +4960,13 @@ pub const TerminalColor = union(enum) {
return .{ .color = try Color.parseCLI(input) };
}
pub fn toTerminalRGB(self: TerminalColor) ?terminal.color.RGB {
return switch (self) {
.color => |v| v.toTerminalRGB(),
.@"cell-foreground", .@"cell-background" => null,
};
}
/// Used by Formatter
pub fn formatEntry(self: TerminalColor, formatter: formatterpkg.EntryFormatter) !void {
switch (self) {

View File

@ -130,11 +130,11 @@ pub const DynamicRGB = struct {
}
pub fn set(self: *DynamicRGB, color: RGB) void {
self.current = color;
self.override = color;
}
pub fn reset(self: *DynamicRGB) void {
self.current = self.default;
self.override = self.default;
}
};

View File

@ -231,10 +231,19 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
.rows = grid_size.rows,
.max_scrollback = opts.full_config.@"scrollback-limit",
.default_modes = default_modes,
.colors = .{
.background = .init(opts.config.background.toTerminalRGB()),
.foreground = .init(opts.config.foreground.toTerminalRGB()),
.cursor = cursor: {
const color = opts.config.cursor_color orelse break :cursor .unset;
const rgb = color.toTerminalRGB() orelse break :cursor .unset;
break :cursor .init(rgb);
},
.palette = .init(opts.config.palette),
},
};
});
errdefer term.deinit(alloc);
term.colors.palette.changeDefault(opts.config.palette);
// Set the image size limits
try term.screen.kitty_images.setLimit(
@ -261,39 +270,20 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
// Create our stream handler. This points to memory in self so it
// isn't safe to use until self.* is set.
const handler: StreamHandler = handler: {
const default_cursor_color: ?terminalpkg.color.RGB = color: {
if (opts.config.cursor_color) |color| switch (color) {
.color => break :color color.color.toTerminalRGB(),
.@"cell-foreground",
.@"cell-background",
=> {},
};
break :color null;
};
break :handler .{
.alloc = alloc,
.termio_mailbox = &self.mailbox,
.surface_mailbox = opts.surface_mailbox,
.renderer_state = opts.renderer_state,
.renderer_wakeup = opts.renderer_wakeup,
.renderer_mailbox = opts.renderer_mailbox,
.size = &self.size,
.terminal = &self.terminal,
.osc_color_report_format = opts.config.osc_color_report_format,
.clipboard_write = opts.config.clipboard_write,
.enquiry_response = opts.config.enquiry_response,
.default_foreground_color = opts.config.foreground.toTerminalRGB(),
.default_background_color = opts.config.background.toTerminalRGB(),
.default_cursor_style = opts.config.cursor_style,
.default_cursor_blink = opts.config.cursor_blink,
.default_cursor_color = default_cursor_color,
.cursor_color = null,
.foreground_color = null,
.background_color = null,
};
const handler: StreamHandler = .{
.alloc = alloc,
.termio_mailbox = &self.mailbox,
.surface_mailbox = opts.surface_mailbox,
.renderer_state = opts.renderer_state,
.renderer_wakeup = opts.renderer_wakeup,
.renderer_mailbox = opts.renderer_mailbox,
.size = &self.size,
.terminal = &self.terminal,
.osc_color_report_format = opts.config.osc_color_report_format,
.clipboard_write = opts.config.clipboard_write,
.enquiry_response = opts.config.enquiry_response,
.default_cursor_style = opts.config.cursor_style,
.default_cursor_blink = opts.config.cursor_blink,
};
const thread_enter_state = try ThreadEnterState.create(
@ -448,11 +438,18 @@ pub fn changeConfig(self: *Termio, td: *ThreadData, config: *DerivedConfig) !voi
// - command, working-directory: we never restart the underlying
// process so we don't care or need to know about these.
// Update the default palette. Note this will only apply to new colors drawn
// since we decode all palette colors to RGB on usage.
// Update the default palette.
self.terminal.colors.palette.changeDefault(config.palette);
self.terminal.flags.dirty.palette = true;
// Update all our other colors
self.terminal.colors.background.default = config.background.toTerminalRGB();
self.terminal.colors.foreground.default = config.foreground.toTerminalRGB();
self.terminal.colors.cursor.default = cursor: {
const color = config.cursor_color orelse break :cursor null;
break :cursor color.toTerminalRGB() orelse break :cursor null;
};
// Set the image size limits
try self.terminal.screen.kitty_images.setLimit(
self.alloc,

View File

@ -45,22 +45,6 @@ pub const StreamHandler = struct {
default_cursor: bool = true,
default_cursor_style: terminal.CursorStyle,
default_cursor_blink: ?bool,
default_cursor_color: ?terminal.color.RGB,
/// Actual cursor color. This can be changed with OSC 12. If unset, falls
/// back to the default cursor color.
cursor_color: ?terminal.color.RGB,
/// The default foreground and background color are those set by the user's
/// config file.
default_foreground_color: terminal.color.RGB,
default_background_color: terminal.color.RGB,
/// The foreground and background color as set by an OSC 10 or OSC 11
/// sequence. If unset then the respective color falls back to the default
/// value.
foreground_color: ?terminal.color.RGB,
background_color: ?terminal.color.RGB,
/// The response to use for ENQ requests. The memory is owned by
/// whoever owns StreamHandler.
@ -114,20 +98,8 @@ pub const StreamHandler = struct {
self.osc_color_report_format = config.osc_color_report_format;
self.clipboard_write = config.clipboard_write;
self.enquiry_response = config.enquiry_response;
self.default_foreground_color = config.foreground.toTerminalRGB();
self.default_background_color = config.background.toTerminalRGB();
self.default_cursor_style = config.cursor_style;
self.default_cursor_blink = config.cursor_blink;
self.default_cursor_color = color: {
if (config.cursor_color) |color| switch (color) {
.color => break :color color.color.toTerminalRGB(),
.@"cell-foreground",
.@"cell-background",
=> {},
};
break :color null;
};
// If our cursor is the default, then we update it immediately.
if (self.default_cursor) self.setCursorStyle(.default) catch |err| {
@ -1137,19 +1109,19 @@ pub const StreamHandler = struct {
},
.dynamic => |dynamic| switch (dynamic) {
.foreground => {
self.foreground_color = set.color;
self.terminal.colors.foreground.set(set.color);
self.rendererMessageWriter(.{
.foreground_color = set.color,
});
},
.background => {
self.background_color = set.color;
self.terminal.colors.background.set(set.color);
self.rendererMessageWriter(.{
.background_color = set.color,
});
},
.cursor => {
self.cursor_color = set.color;
self.terminal.colors.cursor.set(set.color);
self.rendererMessageWriter(.{
.cursor_color = set.color,
});
@ -1189,38 +1161,42 @@ pub const StreamHandler = struct {
},
.dynamic => |dynamic| switch (dynamic) {
.foreground => {
self.foreground_color = null;
self.terminal.colors.foreground.reset();
self.rendererMessageWriter(.{
.foreground_color = self.foreground_color,
.foreground_color = null,
});
self.surfaceMessageWriter(.{ .color_change = .{
.target = target,
.color = self.default_foreground_color,
} });
},
.background => {
self.background_color = null;
self.rendererMessageWriter(.{
.background_color = self.background_color,
});
self.surfaceMessageWriter(.{ .color_change = .{
.target = target,
.color = self.default_background_color,
} });
},
.cursor => {
self.cursor_color = null;
self.rendererMessageWriter(.{
.cursor_color = self.cursor_color,
});
if (self.default_cursor_color) |color| {
if (self.terminal.colors.foreground.default) |c| {
self.surfaceMessageWriter(.{ .color_change = .{
.target = target,
.color = color,
.color = c,
} });
}
},
.background => {
self.terminal.colors.background.reset();
self.rendererMessageWriter(.{
.background_color = null,
});
if (self.terminal.colors.background.default) |c| {
self.surfaceMessageWriter(.{ .color_change = .{
.target = target,
.color = c,
} });
}
},
.cursor => {
self.terminal.colors.cursor.reset();
self.rendererMessageWriter(.{
.cursor_color = null,
});
if (self.terminal.colors.cursor.default) |c| {
self.surfaceMessageWriter(.{ .color_change = .{
.target = target,
.color = c,
} });
}
},
@ -1265,12 +1241,10 @@ pub const StreamHandler = struct {
const color = switch (kind) {
.palette => |i| self.terminal.colors.palette.current[i],
.dynamic => |dynamic| switch (dynamic) {
.foreground => self.foreground_color orelse self.default_foreground_color,
.background => self.background_color orelse self.default_background_color,
.cursor => self.cursor_color orelse
self.default_cursor_color orelse
self.foreground_color orelse
self.default_foreground_color,
.foreground => self.terminal.colors.foreground.get().?,
.background => self.terminal.colors.background.get().?,
.cursor => self.terminal.colors.cursor.get() orelse
self.terminal.colors.foreground.get().?,
.pointer_foreground,
.pointer_background,
.tektronix_foreground,
@ -1398,9 +1372,9 @@ pub const StreamHandler = struct {
const color: terminal.color.RGB = switch (key) {
.palette => |palette| self.terminal.colors.palette.current[palette],
.special => |special| switch (special) {
.foreground => self.foreground_color orelse self.default_foreground_color,
.background => self.background_color orelse self.default_background_color,
.cursor => self.cursor_color orelse self.default_cursor_color,
.foreground => self.terminal.colors.foreground.get(),
.background => self.terminal.colors.background.get(),
.cursor => self.terminal.colors.cursor.get(),
else => {
log.warn("ignoring unsupported kitty color protocol key: {f}", .{key});
continue;
@ -1425,15 +1399,15 @@ pub const StreamHandler = struct {
.special => |special| {
const msg: renderer.Message = switch (special) {
.foreground => msg: {
self.foreground_color = v.color;
self.terminal.colors.foreground.set(v.color);
break :msg .{ .foreground_color = v.color };
},
.background => msg: {
self.background_color = v.color;
self.terminal.colors.background.set(v.color);
break :msg .{ .background_color = v.color };
},
.cursor => msg: {
self.cursor_color = v.color;
self.terminal.colors.cursor.set(v.color);
break :msg .{ .cursor_color = v.color };
},
else => {
@ -1459,16 +1433,16 @@ pub const StreamHandler = struct {
.special => |special| {
const msg: renderer.Message = switch (special) {
.foreground => msg: {
self.foreground_color = null;
break :msg .{ .foreground_color = self.foreground_color };
self.terminal.colors.foreground.reset();
break :msg .{ .foreground_color = null };
},
.background => msg: {
self.background_color = null;
break :msg .{ .background_color = self.background_color };
self.terminal.colors.background.reset();
break :msg .{ .background_color = null };
},
.cursor => msg: {
self.cursor_color = null;
break :msg .{ .cursor_color = self.cursor_color };
self.terminal.colors.cursor.reset();
break :msg .{ .cursor_color = null };
},
else => {
log.warn(