From 9e341a3d60212b361c45527a82e8c8f774e6cf47 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 18 Jan 2025 20:47:23 -0600 Subject: [PATCH] Created tagged union for selection colors, enabled parsing Implemented cell color for Metal Removed use of selection-invert-fg-bg Mirrored feature to OpenGL Added tests for SelectionColor Fixed selection on inverted cell behavior Implemented cell colors for cursor-text Implemented cell colors for cursor-color, removed uses of cursor-invert-fg-bg during rendering Updated docs for dynamically colored options Updated docstrings, cleaned up awkward formatting, and moved style computation to avoid unnecssary invocations Bump version in docstrings --- src/config/Config.zig | 73 +++++++++++++++++++++++++++++++++-- src/termio/Termio.zig | 11 +++--- src/termio/stream_handler.zig | 7 +++- 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/config/Config.zig b/src/config/Config.zig index f36132ea9..76f91f6a8 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -591,8 +591,11 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF }, /// the selection color is just the inverted window background and foreground /// (note: not to be confused with the cell bg/fg). /// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. -@"selection-foreground": ?Color = null, -@"selection-background": ?Color = null, +/// Since version 1.1.1, this can also be set to `cell-foreground` to match +/// the cell foreground color, or `cell-background` to match the cell +/// background color. +@"selection-foreground": ?DynamicColor = null, +@"selection-background": ?DynamicColor = null, /// Swap the foreground and background colors of cells for selection. This /// option overrides the `selection-foreground` and `selection-background` @@ -600,6 +603,10 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF }, /// /// If you select across cells with differing foregrounds and backgrounds, the /// selection color will vary across the selection. +/// +/// Warning: This option has been deprecated as of version 1.1.1. Instead, +/// users should set `selection-foreground` and `selection-background` to +/// `cell-background` and `cell-foreground`, respectively. @"selection-invert-fg-bg": bool = false, /// Whether to clear selected text when typing. This defaults to `true`. @@ -645,10 +652,17 @@ palette: Palette = .{}, /// The color of the cursor. If this is not set, a default will be chosen. /// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. -@"cursor-color": ?Color = null, +/// Since version 1.1.1, this can also be set to `cell-foreground` to match +/// the cell foreground color, or `cell-background` to match the cell +/// background color. +@"cursor-color": ?DynamicColor = null, /// Swap the foreground and background colors of the cell under the cursor. This /// option overrides the `cursor-color` and `cursor-text` options. +/// +/// Warning: This option has been deprecated as of version 1.1.1. Instead, +/// users should set `cursor-color` and `cursor-text` to `cell-foreground` and +/// `cell-background`, respectively. @"cursor-invert-fg-bg": bool = false, /// The opacity level (opposite of transparency) of the cursor. A value of 1 @@ -699,7 +713,10 @@ palette: Palette = .{}, /// The color of the text under the cursor. If this is not set, a default will /// be chosen. /// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. -@"cursor-text": ?Color = null, +/// Since version 1.1.1, this can also be set to `cell-foreground` to match +/// the cell foreground color, or `cell-background` to match the cell +/// background color. +@"cursor-text": ?DynamicColor = null, /// Enables the ability to move the cursor at prompts by using `alt+click` on /// Linux and `option+click` on macOS. @@ -4409,6 +4426,54 @@ pub const Color = struct { } }; +/// Represents the color values that can be set to a non-static value. +/// +/// Can either be a Color or one of the special values +/// "cell-foreground" or "cell-background". +pub const DynamicColor = union(enum) { + color: Color, + @"cell-foreground", + @"cell-background", + + pub fn parseCLI(input_: ?[]const u8) !DynamicColor { + const input = input_ orelse return error.ValueRequired; + + if (std.mem.eql(u8, input, "cell-foreground")) return .@"cell-foreground"; + if (std.mem.eql(u8, input, "cell-background")) return .@"cell-background"; + + return DynamicColor{ .color = try Color.parseCLI(input) }; + } + + /// Used by Formatter + pub fn formatEntry(self: DynamicColor, formatter: anytype) !void { + switch (self) { + .color => try self.color.formatEntry(formatter), + .@"cell-foreground", .@"cell-background" => try formatter.formatEntry([:0]const u8, @tagName(self)), + } + } + + test "parseCLI" { + const testing = std.testing; + + try testing.expectEqual(DynamicColor{ .color = Color{ .r = 78, .g = 42, .b = 132 } }, try DynamicColor.parseCLI("#4e2a84")); + try testing.expectEqual(DynamicColor{ .color = Color{ .r = 0, .g = 0, .b = 0 } }, try DynamicColor.parseCLI("black")); + try testing.expectEqual(DynamicColor{.@"cell-foreground"}, try DynamicColor.parseCLI("cell-foreground")); + try testing.expectEqual(DynamicColor{.@"cell-background"}, try DynamicColor.parseCLI("cell-background")); + + try testing.expectError(error.InvalidValue, DynamicColor.parseCLI("a")); + } + + test "formatConfig" { + const testing = std.testing; + var buf = std.ArrayList(u8).init(testing.allocator); + defer buf.deinit(); + + var sc: DynamicColor = .{.@"cell-foreground"}; + try sc.formatEntry(formatterpkg.entryFormatter("a", buf.writer())); + try testing.expectEqualSlices(u8, "a = cell-foreground\n", buf.items); + } +}; + pub const ColorList = struct { const Self = @This(); diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index 8aaa87011..fda52c375 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -163,8 +163,7 @@ pub const DerivedConfig = struct { image_storage_limit: usize, cursor_style: terminalpkg.CursorStyle, cursor_blink: ?bool, - cursor_color: ?configpkg.Config.Color, - cursor_invert: bool, + cursor_color: ?configpkg.Config.DynamicColor, foreground: configpkg.Config.Color, background: configpkg.Config.Color, osc_color_report_format: configpkg.Config.OSCColorReportFormat, @@ -185,7 +184,6 @@ pub const DerivedConfig = struct { .cursor_style = config.@"cursor-style", .cursor_blink = config.@"cursor-style-blink", .cursor_color = config.@"cursor-color", - .cursor_invert = config.@"cursor-invert-fg-bg", .foreground = config.foreground, .background = config.background, .osc_color_report_format = config.@"osc-color-report-format", @@ -265,8 +263,11 @@ 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 = if (!opts.config.cursor_invert and opts.config.cursor_color != null) - opts.config.cursor_color.?.toTerminalRGB() + const default_cursor_color = if (opts.config.cursor_color) |color| + switch (color) { + .color => color.color.toTerminalRGB(), + else => null, + } else null; diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 1b4fdd3aa..9946b0b8a 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -121,8 +121,11 @@ pub const StreamHandler = struct { 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 = if (!config.cursor_invert and config.cursor_color != null) - config.cursor_color.?.toTerminalRGB() + self.default_cursor_color = if (config.cursor_color) |color| + switch (color) { + .color => color.color.toTerminalRGB(), + else => null, + } else null;