renderer: track if fg/bg/cursor color is explicitly set by an OSC

The renderer must track if the foreground, background, and cursor colors
are explicitly set by an OSC so that changes are not overridden when the
config file is reloaded.
This commit is contained in:
Gregory Anders
2024-12-26 18:51:59 -06:00
parent 35b9ceee21
commit eef9664ef8
4 changed files with 148 additions and 82 deletions

View File

@ -76,18 +76,30 @@ size: renderer.Size,
/// True if the window is focused
focused: bool,
/// The actual foreground color. May differ from the config foreground color if
/// changed by a terminal application
foreground_color: terminal.color.RGB,
/// The foreground color set by an OSC 10 sequence. If unset then
/// default_foreground_color is used.
foreground_color: ?terminal.color.RGB,
/// The actual background color. May differ from the config background color if
/// changed by a terminal application
background_color: terminal.color.RGB,
/// Foreground color set in the user's config file.
default_foreground_color: terminal.color.RGB,
/// The actual cursor color. May differ from the config cursor color if changed
/// by a terminal application
/// The background color set by an OSC 11 sequence. If unset then
/// default_background_color is used.
background_color: ?terminal.color.RGB,
/// Background color set in the user's config file.
default_background_color: terminal.color.RGB,
/// The cursor color set by an OSC 12 sequence. If unset then
/// default_cursor_color is used.
cursor_color: ?terminal.color.RGB,
/// Default cursor color when no color is set explicitly by an OSC 12 command.
/// This is cursor color as set in the user's config, if any. If no cursor color
/// is set in the user's config, then the cursor color is determined by the
/// current foreground color.
default_cursor_color: ?terminal.color.RGB,
/// When `cursor_color` is null, swap the foreground and background colors of
/// the cell under the cursor for the cursor color. Otherwise, use the default
/// foreground color as the cursor color.
@ -629,9 +641,12 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
.grid_metrics = font_critical.metrics,
.size = options.size,
.focused = true,
.foreground_color = options.config.foreground,
.background_color = options.config.background,
.cursor_color = options.config.cursor_color,
.foreground_color = null,
.default_foreground_color = options.config.foreground,
.background_color = null,
.default_background_color = options.config.background,
.cursor_color = null,
.default_cursor_color = options.config.cursor_color,
.cursor_invert = options.config.cursor_invert,
.current_background_color = options.config.background,
@ -919,15 +934,34 @@ pub fn updateFrame(
}
// Swap bg/fg if the terminal is reversed
const bg = self.background_color;
const fg = self.foreground_color;
const bg = self.background_color orelse self.default_background_color;
const fg = self.foreground_color orelse self.default_foreground_color;
defer {
self.background_color = bg;
self.foreground_color = fg;
if (self.background_color) |*c| {
c.* = bg;
} else {
self.default_background_color = bg;
}
if (self.foreground_color) |*c| {
c.* = fg;
} else {
self.default_foreground_color = fg;
}
}
if (state.terminal.modes.get(.reverse_colors)) {
self.background_color = fg;
self.foreground_color = bg;
if (self.background_color) |*c| {
c.* = fg;
} else {
self.default_background_color = fg;
}
if (self.foreground_color) |*c| {
c.* = bg;
} else {
self.default_foreground_color = bg;
}
}
// If our terminal screen size doesn't match our expected renderer
@ -1029,7 +1063,7 @@ pub fn updateFrame(
}
break :critical .{
.bg = self.background_color,
.bg = self.background_color orelse self.default_background_color,
.screen = screen_copy,
.screen_type = state.terminal.active_screen,
.mouse = state.mouse,
@ -1957,10 +1991,10 @@ pub fn changeConfig(self: *Metal, config: *DerivedConfig) !void {
self.uniforms.min_contrast = config.min_contrast;
// Set our new colors
self.background_color = config.background;
self.foreground_color = config.foreground;
self.default_background_color = config.background;
self.default_foreground_color = config.foreground;
self.default_cursor_color = if (!config.cursor_invert) config.cursor_color else null;
self.cursor_invert = config.cursor_invert;
self.cursor_color = if (!config.cursor_invert) config.cursor_color else null;
self.config.deinit();
self.config = config.*;
@ -2246,12 +2280,12 @@ fn rebuildCells(
.extend => if (y == 0) {
self.uniforms.padding_extend.up = !row.neverExtendBg(
color_palette,
self.background_color,
self.background_color orelse self.default_background_color,
);
} else if (y == self.cells.size.rows - 1) {
self.uniforms.padding_extend.down = !row.neverExtendBg(
color_palette,
self.background_color,
self.background_color orelse self.default_background_color,
);
},
}
@ -2360,7 +2394,7 @@ fn rebuildCells(
false;
const bg_style = style.bg(cell, color_palette);
const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color;
const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
// The final background color for the cell.
const bg = bg: {
@ -2380,7 +2414,7 @@ fn rebuildCells(
// If we don't have invert selection fg/bg set then we
// just use the selection background if set, otherwise
// the default fg color.
break :bg self.config.selection_background orelse self.foreground_color;
break :bg self.config.selection_background orelse self.foreground_color orelse self.default_foreground_color;
}
// Not selected
@ -2402,7 +2436,7 @@ fn rebuildCells(
// If we don't have invert selection fg/bg set
// then we just use the selection foreground if
// set, otherwise the default bg color.
break :fg self.config.selection_foreground orelse self.background_color;
break :fg self.config.selection_foreground orelse self.background_color orelse self.default_background_color;
}
// Whether we need to use the bg color as our fg color:
@ -2411,7 +2445,7 @@ fn rebuildCells(
// Note: if selected then invert sel fg / bg must be
// false since we separately handle it if true above.
break :fg if (style.flags.inverse != selected)
bg_style orelse self.background_color
bg_style orelse self.background_color orelse self.default_background_color
else
fg_style;
};
@ -2438,7 +2472,7 @@ fn rebuildCells(
// If we have a background and its not the default background
// then we apply background opacity
if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color)) {
if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color orelse self.default_background_color)) {
break :bg_alpha default;
}
@ -2601,12 +2635,12 @@ fn rebuildCells(
// Prepare the cursor cell contents.
const style = cursor_style_ orelse break :cursor;
const cursor_color = self.cursor_color orelse color: {
const cursor_color = self.cursor_color orelse self.default_cursor_color orelse color: {
if (self.cursor_invert) {
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color;
break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
} else {
break :color self.foreground_color;
break :color self.foreground_color orelse self.default_foreground_color;
}
};
@ -2634,11 +2668,11 @@ fn rebuildCells(
const uniform_color = if (self.cursor_invert) blk: {
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color;
break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color;
} else if (self.config.cursor_text) |txt|
txt
else
self.background_color;
self.background_color orelse self.default_background_color;
self.uniforms.cursor_color = .{
uniform_color.r,
@ -2928,8 +2962,8 @@ fn addPreeditCell(
coord: terminal.Coordinate,
) !void {
// Preedit is rendered inverted
const bg = self.foreground_color;
const fg = self.background_color;
const bg = self.foreground_color orelse self.default_foreground_color;
const fg = self.background_color orelse self.default_background_color;
// Render the glyph for our preedit text
const render_ = self.font_grid.renderCodepoint(

View File

@ -89,18 +89,30 @@ texture_color_resized: usize = 0,
/// True if the window is focused
focused: bool,
/// The actual foreground color. May differ from the config foreground color if
/// changed by a terminal application
foreground_color: terminal.color.RGB,
/// The foreground color set by an OSC 10 sequence. If unset then the default
/// value from the config file is used.
foreground_color: ?terminal.color.RGB,
/// The actual background color. May differ from the config background color if
/// changed by a terminal application
background_color: terminal.color.RGB,
/// Foreground color set in the user's config file.
default_foreground_color: terminal.color.RGB,
/// The actual cursor color. May differ from the config cursor color if changed
/// by a terminal application
/// The background color set by an OSC 11 sequence. If unset then the default
/// value from the config file is used.
background_color: ?terminal.color.RGB,
/// Background color set in the user's config file.
default_background_color: terminal.color.RGB,
/// The cursor color set by an OSC 12 sequence. If unset then
/// default_cursor_color is used.
cursor_color: ?terminal.color.RGB,
/// Default cursor color when no color is set explicitly by an OSC 12 command.
/// This is cursor color as set in the user's config, if any. If no cursor color
/// is set in the user's config, then the cursor color is determined by the
/// current foreground color.
default_cursor_color: ?terminal.color.RGB,
/// When `cursor_color` is null, swap the foreground and background colors of
/// the cell under the cursor for the cursor color. Otherwise, use the default
/// foreground color as the cursor color.
@ -386,9 +398,12 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
.font_shaper_cache = font.ShaperCache.init(),
.draw_background = options.config.background,
.focused = true,
.foreground_color = options.config.foreground,
.background_color = options.config.background,
.cursor_color = options.config.cursor_color,
.foreground_color = null,
.default_foreground_color = options.config.foreground,
.background_color = null,
.default_background_color = options.config.background,
.cursor_color = null,
.default_cursor_color = options.config.cursor_color,
.cursor_invert = options.config.cursor_invert,
.surface_mailbox = options.surface_mailbox,
.deferred_font_size = .{ .metrics = grid.metrics },
@ -701,15 +716,34 @@ pub fn updateFrame(
}
// Swap bg/fg if the terminal is reversed
const bg = self.background_color;
const fg = self.foreground_color;
const bg = self.background_color orelse self.default_background_color;
const fg = self.foreground_color orelse self.default_foreground_color;
defer {
self.background_color = bg;
self.foreground_color = fg;
if (self.background_color) |*c| {
c.* = bg;
} else {
self.default_background_color = bg;
}
if (self.foreground_color) |*c| {
c.* = fg;
} else {
self.default_foreground_color = fg;
}
}
if (state.terminal.modes.get(.reverse_colors)) {
self.background_color = fg;
self.foreground_color = bg;
if (self.background_color) |*c| {
c.* = fg;
} else {
self.default_background_color = fg;
}
if (self.foreground_color) |*c| {
c.* = bg;
} else {
self.default_foreground_color = bg;
}
}
// If our terminal screen size doesn't match our expected renderer
@ -820,7 +854,7 @@ pub fn updateFrame(
break :critical .{
.full_rebuild = full_rebuild,
.gl_bg = self.background_color,
.gl_bg = self.background_color orelse self.default_background_color,
.screen = screen_copy,
.screen_type = state.terminal.active_screen,
.mouse = state.mouse,
@ -1298,12 +1332,12 @@ pub fn rebuildCells(
.extend => if (y == 0) {
self.padding_extend_top = !row.neverExtendBg(
color_palette,
self.background_color,
self.background_color orelse self.default_background_color,
);
} else if (y == self.size.grid().rows - 1) {
self.padding_extend_bottom = !row.neverExtendBg(
color_palette,
self.background_color,
self.background_color orelse self.default_background_color,
);
},
}
@ -1412,7 +1446,7 @@ pub fn rebuildCells(
false;
const bg_style = style.bg(cell, color_palette);
const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color;
const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
// The final background color for the cell.
const bg = bg: {
@ -1432,7 +1466,7 @@ pub fn rebuildCells(
// If we don't have invert selection fg/bg set then we
// just use the selection background if set, otherwise
// the default fg color.
break :bg self.config.selection_background orelse self.foreground_color;
break :bg self.config.selection_background orelse self.foreground_color orelse self.default_foreground_color;
}
// Not selected
@ -1454,7 +1488,7 @@ pub fn rebuildCells(
// If we don't have invert selection fg/bg set
// then we just use the selection foreground if
// set, otherwise the default bg color.
break :fg self.config.selection_foreground orelse self.background_color;
break :fg self.config.selection_foreground orelse self.background_color orelse self.default_background_color;
}
// Whether we need to use the bg color as our fg color:
@ -1463,7 +1497,7 @@ pub fn rebuildCells(
// Note: if selected then invert sel fg / bg must be
// false since we separately handle it if true above.
break :fg if (style.flags.inverse != selected)
bg_style orelse self.background_color
bg_style orelse self.background_color orelse self.default_background_color
else
fg_style;
};
@ -1490,7 +1524,7 @@ pub fn rebuildCells(
// If we have a background and its not the default background
// then we apply background opacity
if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color)) {
if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color orelse self.default_background_color)) {
break :bg_alpha default;
}
@ -1699,12 +1733,12 @@ pub fn rebuildCells(
break :cursor_style;
}
const cursor_color = self.cursor_color orelse color: {
const cursor_color = self.cursor_color orelse self.default_cursor_color orelse color: {
if (self.cursor_invert) {
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color;
break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
} else {
break :color self.foreground_color;
break :color self.foreground_color orelse self.default_foreground_color;
}
};
@ -1713,11 +1747,11 @@ pub fn rebuildCells(
if (cell.mode.isFg() and cell.mode != .fg_color) {
const cell_color = if (self.cursor_invert) blk: {
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color;
break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color;
} else if (self.config.cursor_text) |txt|
txt
else
self.background_color;
self.background_color orelse self.default_background_color;
cell.r = cell_color.r;
cell.g = cell_color.g;
@ -1742,8 +1776,8 @@ fn addPreeditCell(
y: usize,
) !void {
// Preedit is rendered inverted
const bg = self.foreground_color;
const fg = self.background_color;
const bg = self.foreground_color orelse self.default_foreground_color;
const fg = self.background_color orelse self.default_background_color;
// Render the glyph for our preedit text
const render_ = self.font_grid.renderCodepoint(
@ -2122,10 +2156,10 @@ pub fn changeConfig(self: *OpenGL, config: *DerivedConfig) !void {
self.font_shaper_cache = font_shaper_cache;
// Set our new colors
self.background_color = config.background;
self.foreground_color = config.foreground;
self.default_background_color = config.background;
self.default_foreground_color = config.foreground;
self.default_cursor_color = if (!config.cursor_invert) config.cursor_color else null;
self.cursor_invert = config.cursor_invert;
self.cursor_color = if (!config.cursor_invert) config.cursor_color else null;
// Update our uniforms
self.deferred_config = .{};

View File

@ -42,13 +42,11 @@ pub const Message = union(enum) {
old_key: font.SharedGridSet.Key,
},
/// Change the foreground color. This can be done separately from changing
/// the config file in response to an OSC 10 command.
foreground_color: terminal.color.RGB,
/// Change the foreground color as set by an OSC 10 command, if any.
foreground_color: ?terminal.color.RGB,
/// Change the background color. This can be done separately from changing
/// the config file in response to an OSC 11 command.
background_color: terminal.color.RGB,
/// Change the background color as set by an OSC 11 command, if any.
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.

View File

@ -1347,7 +1347,7 @@ pub const StreamHandler = struct {
.foreground => {
self.foreground_color = null;
_ = self.renderer_mailbox.push(.{
.foreground_color = self.default_foreground_color,
.foreground_color = self.foreground_color,
}, .{ .forever = {} });
self.surfaceMessageWriter(.{ .color_change = .{
@ -1358,7 +1358,7 @@ pub const StreamHandler = struct {
.background => {
self.background_color = null;
_ = self.renderer_mailbox.push(.{
.background_color = self.default_background_color,
.background_color = self.background_color,
}, .{ .forever = {} });
self.surfaceMessageWriter(.{ .color_change = .{
@ -1370,7 +1370,7 @@ pub const StreamHandler = struct {
self.cursor_color = null;
_ = self.renderer_mailbox.push(.{
.cursor_color = self.default_cursor_color,
.cursor_color = self.cursor_color,
}, .{ .forever = {} });
if (self.default_cursor_color) |color| {
@ -1490,15 +1490,15 @@ pub const StreamHandler = struct {
const msg: renderer.Message = switch (special) {
.foreground => msg: {
self.foreground_color = null;
break :msg .{ .foreground_color = self.default_foreground_color };
break :msg .{ .foreground_color = self.foreground_color };
},
.background => msg: {
self.background_color = null;
break :msg .{ .background_color = self.default_background_color };
break :msg .{ .background_color = self.background_color };
},
.cursor => msg: {
self.cursor_color = null;
break :msg .{ .cursor_color = self.default_cursor_color };
break :msg .{ .cursor_color = self.cursor_color };
},
else => {
log.warn(