Merge pull request #1989 from gpanders/cursor-invert-fg-bg

config: add cursor-invert-fg-bg option
This commit is contained in:
Mitchell Hashimoto
2024-07-31 19:39:27 -07:00
committed by GitHub
5 changed files with 91 additions and 38 deletions

View File

@ -295,6 +295,10 @@ palette: Palette = .{},
/// The color of the cursor. If this is not set, a default will be chosen. /// The color of the cursor. If this is not set, a default will be chosen.
@"cursor-color": ?Color = null, @"cursor-color": ?Color = null,
/// Swap the foreground and background colors of the cell under the cursor. This
/// option overrides the `cursor-color` and `cursor-text` options.
@"cursor-invert-fg-bg": bool = false,
/// The opacity level (opposite of transparency) of the cursor. A value of 1 /// The opacity level (opposite of transparency) of the cursor. A value of 1
/// is fully opaque and a value of 0 is fully transparent. A value less than 0 /// is fully opaque and a value of 0 is fully transparent. A value less than 0
/// or greater than 1 will be clamped to the nearest valid value. Note that a /// or greater than 1 will be clamped to the nearest valid value. Note that a

View File

@ -91,6 +91,11 @@ background_color: terminal.color.RGB,
/// by a terminal application /// by a terminal application
cursor_color: ?terminal.color.RGB, 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.
cursor_invert: bool,
/// The current frame background color. This is only updated during /// The current frame background color. This is only updated during
/// the updateFrame method. /// the updateFrame method.
current_background_color: terminal.color.RGB, current_background_color: terminal.color.RGB,
@ -329,6 +334,7 @@ pub const DerivedConfig = struct {
font_features: std.ArrayListUnmanaged([:0]const u8), font_features: std.ArrayListUnmanaged([:0]const u8),
font_styles: font.CodepointResolver.StyleStatus, font_styles: font.CodepointResolver.StyleStatus,
cursor_color: ?terminal.color.RGB, cursor_color: ?terminal.color.RGB,
cursor_invert: bool,
cursor_opacity: f64, cursor_opacity: f64,
cursor_text: ?terminal.color.RGB, cursor_text: ?terminal.color.RGB,
background: terminal.color.RGB, background: terminal.color.RGB,
@ -369,17 +375,21 @@ pub const DerivedConfig = struct {
config.link.links.items, config.link.links.items,
); );
const cursor_invert = config.@"cursor-invert-fg-bg";
return .{ return .{
.background_opacity = @max(0, @min(1, config.@"background-opacity")), .background_opacity = @max(0, @min(1, config.@"background-opacity")),
.font_thicken = config.@"font-thicken", .font_thicken = config.@"font-thicken",
.font_features = font_features, .font_features = font_features,
.font_styles = font_styles, .font_styles = font_styles,
.cursor_color = if (config.@"cursor-color") |col| .cursor_color = if (!cursor_invert and config.@"cursor-color" != null)
col.toTerminalRGB() config.@"cursor-color".?.toTerminalRGB()
else else
null, null,
.cursor_invert = cursor_invert,
.cursor_text = if (config.@"cursor-text") |txt| .cursor_text = if (config.@"cursor-text") |txt|
txt.toTerminalRGB() txt.toTerminalRGB()
else else
@ -603,6 +613,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
.foreground_color = options.config.foreground, .foreground_color = options.config.foreground,
.background_color = options.config.background, .background_color = options.config.background,
.cursor_color = options.config.cursor_color, .cursor_color = options.config.cursor_color,
.cursor_invert = options.config.cursor_invert,
.current_background_color = options.config.background, .current_background_color = options.config.background,
// Render state // Render state
@ -1900,7 +1911,8 @@ pub fn changeConfig(self: *Metal, config: *DerivedConfig) !void {
// Set our new colors // Set our new colors
self.background_color = config.background; self.background_color = config.background;
self.foreground_color = config.foreground; self.foreground_color = config.foreground;
self.cursor_color = config.cursor_color; self.cursor_invert = config.cursor_invert;
self.cursor_color = if (!config.cursor_invert) config.cursor_color else null;
self.config.deinit(); self.config.deinit();
self.config = config.*; self.config = config.*;
@ -2218,7 +2230,16 @@ fn rebuildCells(
// Prepare the cursor cell contents. // Prepare the cursor cell contents.
const style = cursor_style_ orelse break :cursor; const style = cursor_style_ orelse break :cursor;
self.addCursor(screen, style); const cursor_color = self.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;
} else {
break :color self.foreground_color;
}
};
self.addCursor(screen, style, cursor_color);
// If the cursor is visible then we set our uniforms. // If the cursor is visible then we set our uniforms.
if (style == .block and screen.viewportIsBottom()) { if (style == .block and screen.viewportIsBottom()) {
@ -2226,15 +2247,19 @@ fn rebuildCells(
screen.cursor.x, screen.cursor.x,
screen.cursor.y, screen.cursor.y,
}; };
self.uniforms.cursor_color = if (self.config.cursor_text) |txt| .{
txt.r, const uniform_color = if (self.cursor_invert) blk: {
txt.g, const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
txt.b, break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color;
255, } else if (self.config.cursor_text) |txt|
} else .{ txt
self.background_color.r, else
self.background_color.g, self.background_color;
self.background_color.b,
self.uniforms.cursor_color = .{
uniform_color.r,
uniform_color.g,
uniform_color.b,
255, 255,
}; };
} }
@ -2495,6 +2520,7 @@ fn addCursor(
self: *Metal, self: *Metal,
screen: *terminal.Screen, screen: *terminal.Screen,
cursor_style: renderer.CursorStyle, cursor_style: renderer.CursorStyle,
cursor_color: terminal.color.RGB,
) void { ) void {
// Add the cursor. We render the cursor over the wide character if // Add the cursor. We render the cursor over the wide character if
// we're on the wide characer tail. // we're on the wide characer tail.
@ -2510,7 +2536,6 @@ fn addCursor(
break :cell .{ prev_cell.wide == .wide, screen.cursor.x - 1 }; break :cell .{ prev_cell.wide == .wide, screen.cursor.x - 1 };
}; };
const color = self.cursor_color orelse self.foreground_color;
const alpha: u8 = if (!self.focused) 255 else alpha: { const alpha: u8 = if (!self.focused) 255 else alpha: {
const alpha = 255 * self.config.cursor_opacity; const alpha = 255 * self.config.cursor_opacity;
break :alpha @intFromFloat(@ceil(alpha)); break :alpha @intFromFloat(@ceil(alpha));
@ -2540,7 +2565,7 @@ fn addCursor(
.mode = .cursor, .mode = .cursor,
.grid_pos = .{ x, screen.cursor.y }, .grid_pos = .{ x, screen.cursor.y },
.cell_width = if (wide) 2 else 1, .cell_width = if (wide) 2 else 1,
.color = .{ color.r, color.g, color.b, alpha }, .color = .{ cursor_color.r, cursor_color.g, cursor_color.b, alpha },
.bg_color = .{ 0, 0, 0, 0 }, .bg_color = .{ 0, 0, 0, 0 },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
.glyph_size = .{ render.glyph.width, render.glyph.height }, .glyph_size = .{ render.glyph.width, render.glyph.height },

View File

@ -95,6 +95,11 @@ background_color: terminal.color.RGB,
/// by a terminal application /// by a terminal application
cursor_color: ?terminal.color.RGB, 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.
cursor_invert: bool,
/// Padding options /// Padding options
padding: renderer.Options.Padding, padding: renderer.Options.Padding,
@ -236,6 +241,7 @@ pub const DerivedConfig = struct {
font_features: std.ArrayListUnmanaged([:0]const u8), font_features: std.ArrayListUnmanaged([:0]const u8),
font_styles: font.CodepointResolver.StyleStatus, font_styles: font.CodepointResolver.StyleStatus,
cursor_color: ?terminal.color.RGB, cursor_color: ?terminal.color.RGB,
cursor_invert: bool,
cursor_text: ?terminal.color.RGB, cursor_text: ?terminal.color.RGB,
cursor_opacity: f64, cursor_opacity: f64,
background: terminal.color.RGB, background: terminal.color.RGB,
@ -275,17 +281,21 @@ pub const DerivedConfig = struct {
config.link.links.items, config.link.links.items,
); );
const cursor_invert = config.@"cursor-invert-fg-bg";
return .{ return .{
.background_opacity = @max(0, @min(1, config.@"background-opacity")), .background_opacity = @max(0, @min(1, config.@"background-opacity")),
.font_thicken = config.@"font-thicken", .font_thicken = config.@"font-thicken",
.font_features = font_features, .font_features = font_features,
.font_styles = font_styles, .font_styles = font_styles,
.cursor_color = if (config.@"cursor-color") |col| .cursor_color = if (!cursor_invert and config.@"cursor-color" != null)
col.toTerminalRGB() config.@"cursor-color".?.toTerminalRGB()
else else
null, null,
.cursor_invert = cursor_invert,
.cursor_text = if (config.@"cursor-text") |txt| .cursor_text = if (config.@"cursor-text") |txt|
txt.toTerminalRGB() txt.toTerminalRGB()
else else
@ -355,6 +365,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
.foreground_color = options.config.foreground, .foreground_color = options.config.foreground,
.background_color = options.config.background, .background_color = options.config.background,
.cursor_color = options.config.cursor_color, .cursor_color = options.config.cursor_color,
.cursor_invert = options.config.cursor_invert,
.padding = options.padding, .padding = options.padding,
.surface_mailbox = options.surface_mailbox, .surface_mailbox = options.surface_mailbox,
.deferred_font_size = .{ .metrics = grid.metrics }, .deferred_font_size = .{ .metrics = grid.metrics },
@ -1233,20 +1244,30 @@ pub fn rebuildCells(
break :cursor_style; break :cursor_style;
} }
_ = try self.addCursor(screen, cursor_style); const cursor_color = self.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;
} else {
break :color self.foreground_color;
}
};
_ = try self.addCursor(screen, cursor_style, cursor_color);
if (cursor_cell) |*cell| { if (cursor_cell) |*cell| {
if (cell.mode == .fg or cell.mode == .fg_constrained) { if (cell.mode == .fg or cell.mode == .fg_constrained) {
if (self.config.cursor_text) |txt| { const cell_color = if (self.cursor_invert) blk: {
cell.r = txt.r; const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
cell.g = txt.g; break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color;
cell.b = txt.b; } else if (self.config.cursor_text) |txt|
cell.a = 255; txt
} else { else
cell.r = self.background_color.r; self.background_color;
cell.g = self.background_color.g;
cell.b = self.background_color.b; cell.r = cell_color.r;
cell.a = 255; cell.g = cell_color.g;
} cell.b = cell_color.b;
cell.a = 255;
} }
try self.cells.append(self.alloc, cell.*); try self.cells.append(self.alloc, cell.*);
} }
@ -1334,6 +1355,7 @@ fn addCursor(
self: *OpenGL, self: *OpenGL,
screen: *terminal.Screen, screen: *terminal.Screen,
cursor_style: renderer.CursorStyle, cursor_style: renderer.CursorStyle,
cursor_color: terminal.color.RGB,
) !?*const CellProgram.Cell { ) !?*const CellProgram.Cell {
// Add the cursor. We render the cursor over the wide character if // Add the cursor. We render the cursor over the wide character if
// we're on the wide characer tail. // we're on the wide characer tail.
@ -1349,7 +1371,6 @@ fn addCursor(
break :cell .{ prev_cell.wide == .wide, screen.cursor.x - 1 }; break :cell .{ prev_cell.wide == .wide, screen.cursor.x - 1 };
}; };
const color = self.cursor_color orelse self.foreground_color;
const alpha: u8 = if (!self.focused) 255 else alpha: { const alpha: u8 = if (!self.focused) 255 else alpha: {
const alpha = 255 * self.config.cursor_opacity; const alpha = 255 * self.config.cursor_opacity;
break :alpha @intFromFloat(@ceil(alpha)); break :alpha @intFromFloat(@ceil(alpha));
@ -1380,9 +1401,9 @@ fn addCursor(
.grid_col = @intCast(x), .grid_col = @intCast(x),
.grid_row = @intCast(screen.cursor.y), .grid_row = @intCast(screen.cursor.y),
.grid_width = if (wide) 2 else 1, .grid_width = if (wide) 2 else 1,
.r = color.r, .r = cursor_color.r,
.g = color.g, .g = cursor_color.g,
.b = color.b, .b = cursor_color.b,
.a = alpha, .a = alpha,
.bg_r = 0, .bg_r = 0,
.bg_g = 0, .bg_g = 0,
@ -1699,7 +1720,8 @@ pub fn changeConfig(self: *OpenGL, config: *DerivedConfig) !void {
// Set our new colors // Set our new colors
self.background_color = config.background; self.background_color = config.background;
self.foreground_color = config.foreground; self.foreground_color = config.foreground;
self.cursor_color = config.cursor_color; self.cursor_invert = config.cursor_invert;
self.cursor_color = if (!config.cursor_invert) config.cursor_color else null;
// Update our uniforms // Update our uniforms
self.deferred_config = .{}; self.deferred_config = .{};

View File

@ -82,6 +82,7 @@ pub const DerivedConfig = struct {
cursor_style: terminal.CursorStyle, cursor_style: terminal.CursorStyle,
cursor_blink: ?bool, cursor_blink: ?bool,
cursor_color: ?configpkg.Config.Color, cursor_color: ?configpkg.Config.Color,
cursor_invert: bool,
foreground: configpkg.Config.Color, foreground: configpkg.Config.Color,
background: configpkg.Config.Color, background: configpkg.Config.Color,
osc_color_report_format: configpkg.Config.OSCColorReportFormat, osc_color_report_format: configpkg.Config.OSCColorReportFormat,
@ -103,6 +104,7 @@ pub const DerivedConfig = struct {
.cursor_style = config.@"cursor-style", .cursor_style = config.@"cursor-style",
.cursor_blink = config.@"cursor-style-blink", .cursor_blink = config.@"cursor-style-blink",
.cursor_color = config.@"cursor-color", .cursor_color = config.@"cursor-color",
.cursor_invert = config.@"cursor-invert-fg-bg",
.foreground = config.foreground, .foreground = config.foreground,
.background = config.background, .background = config.background,
.osc_color_report_format = config.@"osc-color-report-format", .osc_color_report_format = config.@"osc-color-report-format",
@ -176,8 +178,8 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
// Create our stream handler. This points to memory in self so it // Create our stream handler. This points to memory in self so it
// isn't safe to use until self.* is set. // isn't safe to use until self.* is set.
const handler: StreamHandler = handler: { const handler: StreamHandler = handler: {
const default_cursor_color = if (opts.config.cursor_color) |col| const default_cursor_color = if (!opts.config.cursor_invert and opts.config.cursor_color != null)
col.toTerminalRGB() opts.config.cursor_color.?.toTerminalRGB()
else else
null; null;

View File

@ -115,8 +115,8 @@ pub const StreamHandler = struct {
self.default_background_color = config.background.toTerminalRGB(); self.default_background_color = config.background.toTerminalRGB();
self.default_cursor_style = config.cursor_style; self.default_cursor_style = config.cursor_style;
self.default_cursor_blink = config.cursor_blink; self.default_cursor_blink = config.cursor_blink;
self.default_cursor_color = if (config.cursor_color) |col| self.default_cursor_color = if (!config.cursor_invert and config.cursor_color != null)
col.toTerminalRGB() config.cursor_color.?.toTerminalRGB()
else else
null; null;