diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index d97ef6f21..73157ea59 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -64,6 +64,14 @@ padding: renderer.Options.Padding, /// 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 actual background color. May differ from the config background color if +/// changed by a terminal application +background_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. @@ -254,6 +262,8 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal { .screen_size = null, .padding = options.padding, .focused = true, + .foreground_color = options.config.foreground, + .background_color = options.config.background, // Render state .cells_bg = .{}, @@ -461,15 +471,15 @@ pub fn render( } // Swap bg/fg if the terminal is reversed - const bg = self.config.background; - const fg = self.config.foreground; + const bg = self.background_color; + const fg = self.foreground_color; defer { - self.config.background = bg; - self.config.foreground = fg; + self.background_color = bg; + self.foreground_color = fg; } if (state.terminal.modes.get(.reverse_colors)) { - self.config.background = fg; - self.config.foreground = bg; + self.background_color = fg; + self.foreground_color = bg; } // We used to share terminal state, but we've since learned through @@ -509,7 +519,7 @@ pub fn render( } break :critical .{ - .bg = self.config.background, + .bg = self.background_color, .selection = selection, .screen = screen_copy, .preedit = if (cursor_style != null) state.preedit else null, @@ -1267,21 +1277,21 @@ pub fn updateCell( const colors: BgFg = colors: { // If we are selected, we our colors are just inverted fg/bg var selection_res: ?BgFg = if (selected) .{ - .bg = self.config.selection_background orelse self.config.foreground, - .fg = self.config.selection_foreground orelse self.config.background, + .bg = self.config.selection_background orelse self.foreground_color, + .fg = self.config.selection_foreground orelse self.background_color, } else null; const res: BgFg = selection_res orelse if (!cell.attrs.inverse) .{ // In normal mode, background and fg match the cell. We // un-optionalize the fg by defaulting to our fg color. .bg = if (cell.attrs.has_bg) cell.bg else null, - .fg = if (cell.attrs.has_fg) cell.fg else self.config.foreground, + .fg = if (cell.attrs.has_fg) cell.fg else self.foreground_color, } else .{ // In inverted mode, the background MUST be set to something // (is never null) so it is either the fg or default fg. The // fg is either the bg or default background. - .bg = if (cell.attrs.has_fg) cell.fg else self.config.foreground, - .fg = if (cell.attrs.has_bg) cell.bg else self.config.background, + .bg = if (cell.attrs.has_fg) cell.fg else self.foreground_color, + .fg = if (cell.attrs.has_bg) cell.bg else self.background_color, }; // If the cell is "invisible" then we just make fg = bg so that @@ -1289,7 +1299,7 @@ pub fn updateCell( if (cell.attrs.invisible) { break :colors BgFg{ .bg = res.bg, - .fg = res.bg orelse self.config.background, + .fg = res.bg orelse self.background_color, }; } @@ -1316,7 +1326,7 @@ pub fn updateCell( // If we have a background and its not the default background // then we apply background opacity - if (cell.attrs.has_bg and !std.meta.eql(rgb, self.config.background)) { + if (cell.attrs.has_bg and !std.meta.eql(rgb, self.background_color)) { break :bg_alpha alpha; } @@ -1434,7 +1444,7 @@ fn addCursor( ), screen.cursor.x - 1 }; }; - const color = self.config.cursor_color orelse self.config.foreground; + const color = self.config.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)); diff --git a/src/renderer/Thread.zig b/src/renderer/Thread.zig index 35d0ee089..654f370ad 100644 --- a/src/renderer/Thread.zig +++ b/src/renderer/Thread.zig @@ -263,11 +263,11 @@ fn drainMailbox(self: *Thread) !void { }, .foreground_color => |color| { - self.renderer.config.foreground = color; + self.renderer.foreground_color = color; }, .background_color => |color| { - self.renderer.config.background = color; + self.renderer.background_color = color; }, .resize => |v| { diff --git a/src/terminal/osc.zig b/src/terminal/osc.zig index f73bcb6e8..e16b4e31a 100644 --- a/src/terminal/osc.zig +++ b/src/terminal/osc.zig @@ -94,8 +94,8 @@ pub const Command = union(enum) { value: []const u8, }, - /// OSC 4, OSC 10, and OSC 11 default color report. - report_default_color: struct { + /// OSC 4, OSC 10, and OSC 11 color report. + report_color: struct { /// OSC 4 requests a palette color, OSC 10 requests the foreground /// color, OSC 11 the background color. kind: DefaultColorKind, @@ -105,7 +105,7 @@ pub const Command = union(enum) { terminator: Terminator = .st, }, - set_default_color: struct { + set_color: struct { /// OSC 4 sets a palette color, OSC 10 sets the foreground color, OSC 11 /// the background color. kind: DefaultColorKind, @@ -390,20 +390,20 @@ pub const Parser = struct { .color_palette_index_end => switch (c) { '?' => { - self.command = .{ .report_default_color = .{ + self.command = .{ .report_color = .{ .kind = .{ .palette = @intCast(self.temp_state.num) }, } }; self.complete = true; }, else => { - self.command = .{ .set_default_color = .{ + self.command = .{ .set_color = .{ .kind = .{ .palette = @intCast(self.temp_state.num) }, .value = "", } }; self.state = .string; - self.temp_state = .{ .str = &self.command.set_default_color.value }; + self.temp_state = .{ .str = &self.command.set_color.value }; self.buf_start = self.buf_idx - 1; }, }, @@ -456,34 +456,34 @@ pub const Parser = struct { .query_default_fg => switch (c) { '?' => { - self.command = .{ .report_default_color = .{ .kind = .foreground } }; + self.command = .{ .report_color = .{ .kind = .foreground } }; self.complete = true; }, else => { - self.command = .{ .set_default_color = .{ + self.command = .{ .set_color = .{ .kind = .foreground, .value = "", } }; self.state = .string; - self.temp_state = .{ .str = &self.command.set_default_color.value }; + self.temp_state = .{ .str = &self.command.set_color.value }; self.buf_start = self.buf_idx - 1; }, }, .query_default_bg => switch (c) { '?' => { - self.command = .{ .report_default_color = .{ .kind = .background } }; + self.command = .{ .report_color = .{ .kind = .background } }; self.complete = true; }, else => { - self.command = .{ .set_default_color = .{ + self.command = .{ .set_color = .{ .kind = .background, .value = "", } }; self.state = .string; - self.temp_state = .{ .str = &self.command.set_default_color.value }; + self.temp_state = .{ .str = &self.command.set_color.value }; self.buf_start = self.buf_idx - 1; }, }, @@ -694,7 +694,7 @@ pub const Parser = struct { } switch (self.command) { - .report_default_color => |*c| c.terminator = Terminator.init(terminator_ch), + .report_color => |*c| c.terminator = Terminator.init(terminator_ch), else => {}, } @@ -980,9 +980,9 @@ test "OSC: report default foreground color" { // This corresponds to ST = ESC followed by \ const cmd = p.end('\x1b').?; - try testing.expect(cmd == .report_default_color); - try testing.expectEqual(cmd.report_default_color.kind, .foreground); - try testing.expectEqual(cmd.report_default_color.terminator, .st); + try testing.expect(cmd == .report_color); + try testing.expectEqual(cmd.report_color.kind, .foreground); + try testing.expectEqual(cmd.report_color.terminator, .st); } test "OSC: set foreground color" { @@ -994,9 +994,9 @@ test "OSC: set foreground color" { for (input) |ch| p.next(ch); const cmd = p.end('\x07').?; - try testing.expect(cmd == .set_default_color); - try testing.expectEqual(cmd.set_default_color.kind, .foreground); - try testing.expectEqualStrings(cmd.set_default_color.value, "rgbi:0.0/0.5/1.0"); + try testing.expect(cmd == .set_color); + try testing.expectEqual(cmd.set_color.kind, .foreground); + try testing.expectEqualStrings(cmd.set_color.value, "rgbi:0.0/0.5/1.0"); } test "OSC: report default background color" { @@ -1009,9 +1009,9 @@ test "OSC: report default background color" { // This corresponds to ST = BEL character const cmd = p.end('\x07').?; - try testing.expect(cmd == .report_default_color); - try testing.expectEqual(cmd.report_default_color.kind, .background); - try testing.expectEqual(cmd.report_default_color.terminator, .bel); + try testing.expect(cmd == .report_color); + try testing.expectEqual(cmd.report_color.kind, .background); + try testing.expectEqual(cmd.report_color.terminator, .bel); } test "OSC: set background color" { @@ -1023,9 +1023,9 @@ test "OSC: set background color" { for (input) |ch| p.next(ch); const cmd = p.end('\x1b').?; - try testing.expect(cmd == .set_default_color); - try testing.expectEqual(cmd.set_default_color.kind, .background); - try testing.expectEqualStrings(cmd.set_default_color.value, "rgb:f/ff/ffff"); + try testing.expect(cmd == .set_color); + try testing.expectEqual(cmd.set_color.kind, .background); + try testing.expectEqualStrings(cmd.set_color.value, "rgb:f/ff/ffff"); } test "OSC: get palette color" { @@ -1037,9 +1037,9 @@ test "OSC: get palette color" { 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); + try testing.expect(cmd == .report_color); + try testing.expectEqual(cmd.report_color.kind, .{ .palette = 1 }); + try testing.expectEqual(cmd.report_color.terminator, .st); } test "OSC: set palette color" { @@ -1051,7 +1051,7 @@ test "OSC: set palette color" { for (input) |ch| p.next(ch); const cmd = p.end('\x1b').?; - try testing.expect(cmd == .set_default_color); - try testing.expectEqual(cmd.set_default_color.kind, .{ .palette = 17 }); - try testing.expectEqualStrings(cmd.set_default_color.value, "rgb:aa/bb/cc"); + try testing.expect(cmd == .set_color); + try testing.expectEqual(cmd.set_color.kind, .{ .palette = 17 }); + try testing.expectEqualStrings(cmd.set_color.value, "rgb:aa/bb/cc"); } diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 17cea8471..d7d306922 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -1045,16 +1045,16 @@ pub fn Stream(comptime Handler: type) type { } else log.warn("unimplemented OSC callback: {}", .{cmd}); }, - .report_default_color => |v| { - if (@hasDecl(T, "reportDefaultColor")) { - try self.handler.reportDefaultColor(v.kind, v.terminator); + .report_color => |v| { + if (@hasDecl(T, "reportColor")) { + try self.handler.reportColor(v.kind, v.terminator); return; } else log.warn("unimplemented OSC callback: {}", .{cmd}); }, - .set_default_color => |v| { - if (@hasDecl(T, "setDefaultColor")) { - try self.handler.setDefaultColor(v.kind, v.value); + .set_color => |v| { + if (@hasDecl(T, "setColor")) { + try self.handler.setColor(v.kind, v.value); return; } else log.warn("unimplemented OSC callback: {}", .{cmd}); }, diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index d875c6bfe..a0da3e9c4 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -70,12 +70,18 @@ grid_size: renderer.GridSize, default_cursor_style: terminal.Cursor.Style, default_cursor_blink: ?bool, -/// Default foreground color for OSC 10 reporting. +/// Default foreground color as set by the config file default_foreground_color: terminal.color.RGB, -/// Default background color for OSC 11 reporting. +/// Default background color as set by the config file default_background_color: terminal.color.RGB, +/// Actual foreground color +foreground_color: terminal.color.RGB, + +/// Actual background color +background_color: terminal.color.RGB, + /// The OSC 10/11 reply style. osc_color_report_format: configpkg.Config.OSCColorReportFormat, @@ -171,6 +177,8 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec { .default_cursor_blink = opts.config.cursor_blink, .default_foreground_color = config.foreground.toTerminalRGB(), .default_background_color = config.background.toTerminalRGB(), + .foreground_color = config.foreground.toTerminalRGB(), + .background_color = config.background.toTerminalRGB(), .osc_color_report_format = config.osc_color_report_format, .data = null, }; @@ -238,6 +246,8 @@ pub fn threadEnter(self: *Exec, thread: *termio.Thread) !ThreadData { .default_cursor_blink = self.default_cursor_blink, .default_foreground_color = self.default_foreground_color, .default_background_color = self.default_background_color, + .foreground_color = self.foreground_color, + .background_color = self.background_color, .osc_color_report_format = self.osc_color_report_format, }, @@ -328,7 +338,7 @@ pub fn changeConfig(self: *Exec, config: *DerivedConfig) !void { self.default_cursor_style = config.cursor_style; self.default_cursor_blink = config.cursor_blink; - // Update foreground and background colors + // Update default foreground and background colors self.default_foreground_color = config.foreground.toTerminalRGB(); self.default_background_color = config.background.toTerminalRGB(); @@ -1330,8 +1340,19 @@ const StreamHandler = struct { default_cursor: bool = true, default_cursor_style: terminal.Cursor.Style, default_cursor_blink: ?bool, + + /// The default foreground and background color are those set by the user's + /// config file. These can be overridden by terminal applications using OSC + /// 10 and OSC 11, respectively. default_foreground_color: terminal.color.RGB, default_background_color: terminal.color.RGB, + + /// The actual foreground and background color. Normally this will be the + /// same as the default foreground and background color, unless changed by a + /// terminal application. + foreground_color: terminal.color.RGB, + background_color: terminal.color.RGB, + osc_color_report_format: configpkg.Config.OSCColorReportFormat, pub fn deinit(self: *StreamHandler) void { @@ -2156,7 +2177,7 @@ const StreamHandler = struct { /// Implements OSC 4, OSC 10, and OSC 11, which reports palette color, /// default foreground color, and background color respectively. - pub fn reportDefaultColor( + pub fn reportColor( self: *StreamHandler, kind: terminal.osc.Command.DefaultColorKind, terminator: terminal.osc.Terminator, @@ -2164,8 +2185,8 @@ const StreamHandler = struct { if (self.osc_color_report_format == .none) return; const color = switch (kind) { - .foreground => self.default_foreground_color, - .background => self.default_background_color, + .foreground => self.foreground_color, + .background => self.background_color, .palette => |i| self.terminal.color_palette[i], }; @@ -2201,7 +2222,7 @@ const StreamHandler = struct { self.messageWriter(msg); } - pub fn setDefaultColor( + pub fn setColor( self: *StreamHandler, kind: terminal.osc.Command.DefaultColorKind, value: []const u8, @@ -2210,13 +2231,13 @@ const StreamHandler = struct { switch (kind) { .foreground => { - self.default_foreground_color = color; + self.foreground_color = color; _ = self.ev.renderer_mailbox.push(.{ .foreground_color = color, }, .{ .forever = {} }); }, .background => { - self.default_background_color = color; + self.background_color = color; _ = self.ev.renderer_mailbox.push(.{ .background_color = color, }, .{ .forever = {} });