mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 07:46:12 +03:00
Added bold-color option (#7168)
As discussed in https://github.com/ghostty-org/ghostty/discussions/3134 To allow for the option to render bold text in a different colour for better visibility as an extension of `bold-is-bright`. This is a feature that is available in other terminals.
This commit is contained in:
@ -14,6 +14,7 @@ pub const entryFormatter = formatter.entryFormatter;
|
||||
pub const formatEntry = formatter.formatEntry;
|
||||
|
||||
// Field types
|
||||
pub const BoldColor = Config.BoldColor;
|
||||
pub const ClipboardAccess = Config.ClipboardAccess;
|
||||
pub const Command = Config.Command;
|
||||
pub const ConfirmCloseSurface = Config.ConfirmCloseSurface;
|
||||
|
@ -69,6 +69,10 @@ pub const compatibility = std.StaticStringMap(
|
||||
// this behavior. This applies to selection too.
|
||||
.{ "cursor-invert-fg-bg", compatCursorInvertFgBg },
|
||||
.{ "selection-invert-fg-bg", compatSelectionInvertFgBg },
|
||||
|
||||
// Ghostty 1.2 merged `bold-is-bright` into the new `bold-color`
|
||||
// by setting the value to "bright".
|
||||
.{ "bold-is-bright", compatBoldIsBright },
|
||||
});
|
||||
|
||||
/// The font families to use.
|
||||
@ -2804,8 +2808,24 @@ else
|
||||
/// notifications using certain escape sequences such as OSC 9 or OSC 777.
|
||||
@"desktop-notifications": bool = true,
|
||||
|
||||
/// If `true`, the bold text will use the bright color palette.
|
||||
@"bold-is-bright": bool = false,
|
||||
/// Modifies the color used for bold text in the terminal.
|
||||
///
|
||||
/// This can be set to a specific color, using the same format as
|
||||
/// `background` or `foreground` (e.g. `#RRGGBB` but other formats
|
||||
/// are also supported; see the aforementioned documentation). If a
|
||||
/// specific color is set, this color will always be used for all
|
||||
/// bold text regardless of the terminal's color scheme.
|
||||
///
|
||||
/// This can also be set to `bright`, which uses the bright color palette
|
||||
/// for bold text. For example, if the text is red, then the bold will
|
||||
/// use the bright red color. The terminal palette is set with `palette`
|
||||
/// but can also be overridden by the terminal application itself using
|
||||
/// escape sequences such as OSC 4. (Since Ghostty 1.2.0, the previous
|
||||
/// configuration `bold-is-bright` is deprecated and replaced by this
|
||||
/// usage).
|
||||
///
|
||||
/// Available since Ghostty 1.2.0.
|
||||
@"bold-color": ?BoldColor = null,
|
||||
|
||||
/// This will be used to set the `TERM` environment variable.
|
||||
/// HACK: We set this with an `xterm` prefix because vim uses that to enable key
|
||||
@ -3910,6 +3930,23 @@ fn compatSelectionInvertFgBg(
|
||||
return true;
|
||||
}
|
||||
|
||||
fn compatBoldIsBright(
|
||||
self: *Config,
|
||||
alloc: Allocator,
|
||||
key: []const u8,
|
||||
value_: ?[]const u8,
|
||||
) bool {
|
||||
_ = alloc;
|
||||
assert(std.mem.eql(u8, key, "bold-is-bright"));
|
||||
|
||||
const set = cli.args.parseBool(value_ orelse "t") catch return false;
|
||||
if (set) {
|
||||
self.@"bold-color" = .bright;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Create a shallow copy of this config. This will share all the memory
|
||||
/// allocated with the previous config but will have a new arena for
|
||||
/// any changes or new allocations. The config should have `deinit`
|
||||
@ -4537,6 +4574,58 @@ pub const TerminalColor = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents color values that can be used for bold. See `bold-color`.
|
||||
pub const BoldColor = union(enum) {
|
||||
color: Color,
|
||||
bright,
|
||||
|
||||
pub fn parseCLI(input_: ?[]const u8) !BoldColor {
|
||||
const input = input_ orelse return error.ValueRequired;
|
||||
if (std.mem.eql(u8, input, "bright")) return .bright;
|
||||
return .{ .color = try Color.parseCLI(input) };
|
||||
}
|
||||
|
||||
/// Used by Formatter
|
||||
pub fn formatEntry(self: BoldColor, formatter: anytype) !void {
|
||||
switch (self) {
|
||||
.color => try self.color.formatEntry(formatter),
|
||||
.bright => try formatter.formatEntry(
|
||||
[:0]const u8,
|
||||
@tagName(self),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
test "parseCLI" {
|
||||
const testing = std.testing;
|
||||
|
||||
try testing.expectEqual(
|
||||
BoldColor{ .color = Color{ .r = 78, .g = 42, .b = 132 } },
|
||||
try BoldColor.parseCLI("#4e2a84"),
|
||||
);
|
||||
try testing.expectEqual(
|
||||
BoldColor{ .color = Color{ .r = 0, .g = 0, .b = 0 } },
|
||||
try BoldColor.parseCLI("black"),
|
||||
);
|
||||
try testing.expectEqual(
|
||||
BoldColor.bright,
|
||||
try BoldColor.parseCLI("bright"),
|
||||
);
|
||||
|
||||
try testing.expectError(error.InvalidValue, BoldColor.parseCLI("a"));
|
||||
}
|
||||
|
||||
test "formatConfig" {
|
||||
const testing = std.testing;
|
||||
var buf = std.ArrayList(u8).init(testing.allocator);
|
||||
defer buf.deinit();
|
||||
|
||||
var sc: BoldColor = .bright;
|
||||
try sc.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
|
||||
try testing.expectEqualSlices(u8, "a = bright\n", buf.items);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ColorList = struct {
|
||||
const Self = @This();
|
||||
|
||||
@ -8236,3 +8325,23 @@ test "compatibility: removed selection-invert-fg-bg" {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
test "compatibility: removed bold-is-bright" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
{
|
||||
var cfg = try Config.default(alloc);
|
||||
defer cfg.deinit();
|
||||
var it: TestIterator = .{ .data = &.{
|
||||
"--bold-is-bright",
|
||||
} };
|
||||
try cfg.loadIter(alloc, &it);
|
||||
try cfg.finalize();
|
||||
|
||||
try testing.expectEqual(
|
||||
BoldColor.bright,
|
||||
cfg.@"bold-color",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -519,7 +519,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||
foreground: terminal.color.RGB,
|
||||
selection_background: ?configpkg.Config.TerminalColor,
|
||||
selection_foreground: ?configpkg.Config.TerminalColor,
|
||||
bold_is_bright: bool,
|
||||
bold_color: ?configpkg.BoldColor,
|
||||
min_contrast: f32,
|
||||
padding_color: configpkg.WindowPaddingColor,
|
||||
custom_shaders: configpkg.RepeatablePath,
|
||||
@ -580,7 +580,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||
|
||||
.background = config.background.toTerminalRGB(),
|
||||
.foreground = config.foreground.toTerminalRGB(),
|
||||
.bold_is_bright = config.@"bold-is-bright",
|
||||
.bold_color = config.@"bold-color",
|
||||
|
||||
.min_contrast = @floatCast(config.@"minimum-contrast"),
|
||||
.padding_color = config.@"window-padding-color",
|
||||
|
||||
@ -2540,10 +2541,11 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||
// the cell style (SGR), before applying any additional
|
||||
// configuration, inversions, selections, etc.
|
||||
const bg_style = style.bg(cell, color_palette);
|
||||
const fg_style = style.fg(
|
||||
color_palette,
|
||||
self.config.bold_is_bright,
|
||||
) orelse self.foreground_color orelse self.default_foreground_color;
|
||||
const fg_style = style.fg(.{
|
||||
.default = self.foreground_color orelse self.default_foreground_color,
|
||||
.palette = color_palette,
|
||||
.bold = self.config.bold_color,
|
||||
});
|
||||
|
||||
// The final background color for the cell.
|
||||
const bg = bg: {
|
||||
@ -2801,10 +2803,11 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||
.@"cell-background",
|
||||
=> |_, tag| {
|
||||
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
||||
const fg_style = sty.fg(
|
||||
color_palette,
|
||||
self.config.bold_is_bright,
|
||||
) orelse self.foreground_color orelse self.default_foreground_color;
|
||||
const fg_style = sty.fg(.{
|
||||
.default = self.foreground_color orelse self.default_foreground_color,
|
||||
.palette = color_palette,
|
||||
.bold = self.config.bold_color,
|
||||
});
|
||||
const bg_style = sty.bg(
|
||||
screen.cursor.page_cell,
|
||||
color_palette,
|
||||
@ -2852,7 +2855,11 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||
}
|
||||
|
||||
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
||||
const fg_style = sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
|
||||
const fg_style = sty.fg(.{
|
||||
.default = self.foreground_color orelse self.default_foreground_color,
|
||||
.palette = color_palette,
|
||||
.bold = self.config.bold_color,
|
||||
});
|
||||
const bg_style = sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color;
|
||||
|
||||
break :blk switch (txt) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const configpkg = @import("../config.zig");
|
||||
const color = @import("color.zig");
|
||||
const sgr = @import("sgr.zig");
|
||||
const page = @import("page.zig");
|
||||
@ -115,24 +116,68 @@ pub const Style = struct {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the fg color for a cell with this style given the palette.
|
||||
pub const Fg = struct {
|
||||
/// The default color to use if the style doesn't specify a
|
||||
/// foreground color and no configuration options override
|
||||
/// it.
|
||||
default: color.RGB,
|
||||
|
||||
/// The current color palette. Required to map palette indices to
|
||||
/// real color values.
|
||||
palette: *const color.Palette,
|
||||
|
||||
/// If specified, the color to use for bold text.
|
||||
bold: ?configpkg.BoldColor = null,
|
||||
};
|
||||
|
||||
/// Returns the fg color for a cell with this style given the palette
|
||||
/// and various configuration options.
|
||||
pub fn fg(
|
||||
self: Style,
|
||||
palette: *const color.Palette,
|
||||
bold_is_bright: bool,
|
||||
) ?color.RGB {
|
||||
opts: Fg,
|
||||
) color.RGB {
|
||||
// Note we don't pull the bold check to the top-level here because
|
||||
// we don't want to duplicate the conditional multiple times since
|
||||
// certain colors require more checks (e.g. `bold_is_bright`).
|
||||
|
||||
return switch (self.fg_color) {
|
||||
.none => null,
|
||||
.palette => |idx| palette: {
|
||||
if (bold_is_bright and self.flags.bold) {
|
||||
const bright_offset = @intFromEnum(color.Name.bright_black);
|
||||
if (idx < bright_offset)
|
||||
break :palette palette[idx + bright_offset];
|
||||
.none => default: {
|
||||
if (self.flags.bold) {
|
||||
if (opts.bold) |bold| switch (bold) {
|
||||
.bright => {},
|
||||
.color => |v| break :default v.toTerminalRGB(),
|
||||
};
|
||||
}
|
||||
|
||||
break :palette palette[idx];
|
||||
break :default opts.default;
|
||||
},
|
||||
|
||||
.palette => |idx| palette: {
|
||||
if (self.flags.bold) {
|
||||
if (opts.bold) |bold| switch (bold) {
|
||||
.color => |v| break :palette v.toTerminalRGB(),
|
||||
.bright => {
|
||||
const bright_offset = @intFromEnum(color.Name.bright_black);
|
||||
if (idx < bright_offset) {
|
||||
break :palette opts.palette[idx + bright_offset];
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
break :palette opts.palette[idx];
|
||||
},
|
||||
|
||||
.rgb => |rgb| rgb: {
|
||||
if (self.flags.bold and rgb.eql(opts.default)) {
|
||||
if (opts.bold) |bold| switch (bold) {
|
||||
.color => |v| break :rgb v.toTerminalRGB(),
|
||||
.bright => {},
|
||||
};
|
||||
}
|
||||
|
||||
break :rgb rgb;
|
||||
},
|
||||
.rgb => |rgb| rgb,
|
||||
};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user