summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/config.md9
-rw-r--r--docs/themes.md3
-rw-r--r--src/pardes.zig73
-rw-r--r--src/themes/atelier.zig3
-rw-r--r--src/themes/clay.zig3
-rw-r--r--src/themes/daybreak.zig3
-rw-r--r--src/themes/dusk.zig3
-rw-r--r--src/themes/forge.zig3
-rw-r--r--src/themes/forge_black.zig3
-rw-r--r--src/themes/forge_soft.zig3
-rw-r--r--src/themes/harvest.zig3
-rw-r--r--src/themes/ink.zig3
-rw-r--r--src/themes/lagoon.zig3
-rw-r--r--src/themes/orchard.zig3
-rw-r--r--src/themes/orchard_black.zig3
-rw-r--r--src/themes/paper.zig3
-rw-r--r--src/themes/solarium.zig3
-rw-r--r--src/themes/spectrum.zig1
-rw-r--r--test/panes.zig1
19 files changed, 109 insertions, 20 deletions
diff --git a/docs/config.md b/docs/config.md
index 53c76087..5a7a358f 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -268,7 +268,7 @@ name, thirteen required RGB roles (`sel_bg`, `sel_fg`, `tag_bg`, `tag_fg`,
`box`, `box_dim`, `kw`, `str`, `num`, `comment`, `lineno`, `scroll_track`,
`scroll_thumb`), nullable `bg`/`fg`, and either a 16-color RGB `palette` or
`null`. Optional nullable RGB roles extend this format:
-`tag_active_bg`, `tag_active_fg`, `tag_name_fg`, `border`, `lineno_active`, `search_bg`, `search_fg`,
+`tag_active_bg`, `tag_active_fg`, `tag_name_fg`, `tag_active_name_fg`, `border`, `lineno_active`, `search_bg`, `search_fg`,
`diagnostic_error`, `diagnostic_warning`, `diagnostic_info`, and
`diagnostic_hint`. Missing new roles use backward-compatible defaults, so
previously exported files remain valid. [Theme customization](themes.md)
@@ -277,8 +277,11 @@ hex literals are accepted. The original fields remain required; there is no
inheritance or partial override layer.
`tag_name_fg` gives the filename at the end of a pane's path a separate
-foreground on both normal and active tags. When omitted or `null`, it uses
-the corresponding tag foreground. Directory text and tag commands retain
+foreground. `tag_active_name_fg` can adjust that tint for active tags; it falls
+back to `tag_name_fg`. When both are omitted or `null`, the filename uses
+the corresponding tag foreground. All canonical themes use a different hue
+at similar perceived brightness to the surrounding text in both states.
+Directory text and tag commands retain
their regular colors; selecting filename text uses the selection colors.
Terminal tags use this color for `Tty`, which comes immediately after the path.
diff --git a/docs/themes.md b/docs/themes.md
index 5c7da44b..01965de5 100644
--- a/docs/themes.md
+++ b/docs/themes.md
@@ -102,7 +102,8 @@ so existing exported themes remain valid.
| Optional role | Purpose | When absent |
| --- | --- | --- |
| `tag_active_bg`, `tag_active_fg` | Focused pane tag surface and text | `tag_bg`, `tag_fg` |
-| `tag_name_fg` | Filename at the end of the pane's path, on normal and active tags | The corresponding normal or active tag foreground |
+| `tag_name_fg` | Filename or terminal `Tty` command tint | The corresponding normal or active tag foreground |
+| `tag_active_name_fg` | Filename or terminal `Tty` tint in active tags | `tag_name_fg`, then the active tag foreground |
| `border` | Quiet separators | `scroll_track` |
| `lineno_active` | Restrained current line number foreground | `lineno` |
| `search_bg`, `search_fg` | Search matches, independent of selection | `sel_bg`, `sel_fg` |
diff --git a/src/pardes.zig b/src/pardes.zig
index b6d6ed8f..51c9c3db 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -2939,8 +2939,10 @@ pub const Theme = struct {
// editor palettes keep working; ChromeTheme resolves their legacy defaults.
tag_active_bg: ?[3]u8 = null,
tag_active_fg: ?[3]u8 = null,
- /// Quiet filename/output-name accent; directories and commands keep tag ink.
+ /// Filename/output-name accent, also used by the Tty command.
tag_name_fg: ?[3]u8 = null,
+ /// Active tint; absence preserves the shared name tint or active tag ink.
+ tag_active_name_fg: ?[3]u8 = null,
border: ?[3]u8 = null,
search_bg: ?[3]u8 = null,
search_fg: ?[3]u8 = null,
@@ -3049,6 +3051,51 @@ test "native themes keep text and UI roles readable on their own surfaces" {
}
}
+test "native filename tints change hue without changing perceived lightness" {
+ const Perceptual = struct {
+ fn lab(rgb: [3]u8) [3]f64 {
+ var linear: [3]f64 = undefined;
+ for (rgb, 0..) |channel, i| {
+ const value = @as(f64, @floatFromInt(channel)) / 255;
+ linear[i] = if (value <= 0.04045) value / 12.92 else std.math.pow(f64, (value + 0.055) / 1.055, 2.4);
+ }
+ const r = linear[0];
+ const g = linear[1];
+ const b = linear[2];
+ const l = std.math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
+ const m = std.math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
+ const n = std.math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
+ return .{
+ 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * n,
+ 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * n,
+ 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * n,
+ };
+ }
+ };
+ for (themes[0..native_theme_count]) |th| {
+ try std.testing.expect(th.tag_name_fg != null and th.tag_active_name_fg != null);
+ const chrome = ChromeTheme.fromTheme(&th);
+ const pairs = [2][2][3]u8{
+ .{ chrome.tag_fg, chrome.tag_name_fg },
+ .{ chrome.tag_active_fg, chrome.tag_active_name_fg },
+ };
+ for (pairs) |pair| {
+ const base = Perceptual.lab(pair[0]);
+ const name = Perceptual.lab(pair[1]);
+ // Half a lightness point allows 8-bit quantization without a
+ // basename becoming visibly brighter or darker than its tag.
+ try std.testing.expectApproxEqAbs(base[0], name[0], 0.005);
+ const base_chroma = @sqrt(base[1] * base[1] + base[2] * base[2]);
+ const name_chroma = @sqrt(name[1] * name[1] + name[2] * name[2]);
+ try std.testing.expect(base_chroma > 0.005 and name_chroma > 0.02);
+ // A normalized dot product <= cos(60 degrees) means a clear
+ // hue difference, independent of saturation or lightness.
+ const hue_cosine = (base[1] * name[1] + base[2] * name[2]) / (base_chroma * name_chroma);
+ try std.testing.expect(hue_cosine <= 0.5);
+ }
+ }
+}
+
test "native dark palettes choose near-black or deliberately soft contrast" {
for (themes[0..native_theme_count]) |th| {
if (themeContrast(th.bg.?, .{ 0, 0, 0 }) > 10) continue; // light paper
@@ -3122,6 +3169,7 @@ test "legacy ThemeFile documents inherit Pardes UI roles without new fields" {
defer std.zon.parse.free(std.testing.allocator, parsed);
try std.testing.expectEqual(@as(?[3]u8, null), parsed.tag_active_bg);
try std.testing.expectEqual(@as(?[3]u8, null), parsed.tag_name_fg);
+ try std.testing.expectEqual(@as(?[3]u8, null), parsed.tag_active_name_fg);
try std.testing.expectEqual(@as(?[3]u8, null), parsed.search_bg);
const chrome = ChromeTheme.fromTheme(&parsed);
try std.testing.expectEqual(parsed.tag_bg, chrome.tag_active_bg);
@@ -3131,6 +3179,27 @@ test "legacy ThemeFile documents inherit Pardes UI roles without new fields" {
try std.testing.expectEqual(parsed.fg.?, chrome.diagnostic_error);
}
+test "custom filename tints preserve optional active fallback precedence" {
+ var theme = themes[0];
+ theme.tag_name_fg = null;
+ theme.tag_active_name_fg = null;
+ var chrome = ChromeTheme.fromTheme(&theme);
+ try std.testing.expectEqual(theme.tag_fg, chrome.tag_name_fg);
+ try std.testing.expectEqual(theme.tag_active_fg.?, chrome.tag_active_name_fg);
+ theme.tag_name_fg = .{ 120, 130, 140 };
+ chrome = ChromeTheme.fromTheme(&theme);
+ try std.testing.expectEqual(theme.tag_name_fg.?, chrome.tag_name_fg);
+ try std.testing.expectEqual(theme.tag_name_fg.?, chrome.tag_active_name_fg);
+ theme.tag_active_name_fg = .{ 150, 160, 170 };
+ chrome = ChromeTheme.fromTheme(&theme);
+ try std.testing.expectEqual(theme.tag_name_fg.?, chrome.tag_name_fg);
+ try std.testing.expectEqual(theme.tag_active_name_fg.?, chrome.tag_active_name_fg);
+ theme.tag_name_fg = null;
+ chrome = ChromeTheme.fromTheme(&theme);
+ try std.testing.expectEqual(theme.tag_fg, chrome.tag_name_fg);
+ try std.testing.expectEqual(theme.tag_active_name_fg.?, chrome.tag_active_name_fg);
+}
+
comptime {
if (themes.len > std.math.maxInt(u16) + 1)
@compileError("runtime config theme index no longer fits u16");
@@ -3209,7 +3278,7 @@ pub const ChromeTheme = struct {
.tag_active_bg = th.tag_active_bg orelse th.tag_bg,
.tag_active_fg = th.tag_active_fg orelse th.tag_fg,
.tag_name_fg = th.tag_name_fg orelse th.tag_fg,
- .tag_active_name_fg = th.tag_name_fg orelse (th.tag_active_fg orelse th.tag_fg),
+ .tag_active_name_fg = th.tag_active_name_fg orelse (th.tag_name_fg orelse (th.tag_active_fg orelse th.tag_fg)),
.border = th.border orelse th.scroll_track,
.search_bg = th.search_bg orelse th.sel_bg,
.search_fg = th.search_fg orelse th.sel_fg,
diff --git a/src/themes/atelier.zig b/src/themes/atelier.zig
index 01e4ef4b..bd0e9639 100644
--- a/src/themes/atelier.zig
+++ b/src/themes/atelier.zig
@@ -7,7 +7,8 @@ pub const theme = .{
.fg = .{ 0x29, 0x3f, 0x35 },
.tag_bg = .{ 0xe4, 0xf0, 0xed },
.tag_fg = .{ 0x3d, 0x60, 0x55 },
- .tag_name_fg = .{ 0x72, 0x4b, 0x78 },
+ .tag_name_fg = .{ 0x6e, 0x47, 0x74 },
+ .tag_active_name_fg = .{ 0x65, 0x3f, 0x6b },
.tag_active_bg = .{ 0xd3, 0xe7, 0xdf },
.tag_active_fg = .{ 0x35, 0x58, 0x4d },
.box = .{ 0x3e, 0x7a, 0x68 },
diff --git a/src/themes/clay.zig b/src/themes/clay.zig
index b57b6bfb..3c729dd8 100644
--- a/src/themes/clay.zig
+++ b/src/themes/clay.zig
@@ -8,7 +8,8 @@ pub const theme = .{
.fg = .{ 0xf3, 0xe5, 0xbc },
.tag_bg = .{ 0x34, 0x3f, 0x36 },
.tag_fg = .{ 0xd7, 0xd6, 0xb6 },
- .tag_name_fg = .{ 0xa9, 0xdf, 0xdf },
+ .tag_name_fg = .{ 0xaa, 0xe0, 0xe0 },
+ .tag_active_name_fg = .{ 0xb5, 0xec, 0xec },
.tag_active_bg = .{ 0x42, 0x4f, 0x40 },
.tag_active_fg = .{ 0xe3, 0xe2, 0xc2 },
.box = .{ 0x8e, 0xc0, 0x7c },
diff --git a/src/themes/daybreak.zig b/src/themes/daybreak.zig
index 518d21b6..eca2e7fc 100644
--- a/src/themes/daybreak.zig
+++ b/src/themes/daybreak.zig
@@ -7,7 +7,8 @@ pub const theme = .{
.fg = .{ 0x14, 0x2d, 0x40 },
.tag_bg = .{ 0xed, 0xf2, 0xf7 },
.tag_fg = .{ 0x29, 0x46, 0x5e },
- .tag_name_fg = .{ 0x61, 0x33, 0x6e },
+ .tag_name_fg = .{ 0x5a, 0x2d, 0x67 },
+ .tag_active_name_fg = .{ 0x52, 0x25, 0x5f },
.tag_active_bg = .{ 0xdf, 0xea, 0xf3 },
.tag_active_fg = .{ 0x21, 0x3e, 0x56 },
.box = .{ 0x07, 0x5f, 0x91 },
diff --git a/src/themes/dusk.zig b/src/themes/dusk.zig
index 1c579a40..ac3e4301 100644
--- a/src/themes/dusk.zig
+++ b/src/themes/dusk.zig
@@ -7,7 +7,8 @@ pub const theme = .{
.fg = .{ 0xc3, 0xb6, 0xc1 },
.tag_bg = .{ 0x2c, 0x26, 0x30 },
.tag_fg = .{ 0xc6, 0xb6, 0xc5 },
- .tag_name_fg = .{ 0x94, 0xc7, 0xb6 },
+ .tag_name_fg = .{ 0x96, 0xc9, 0xb8 },
+ .tag_active_name_fg = .{ 0xa1, 0xd5, 0xc4 },
.tag_active_bg = .{ 0x3b, 0x2f, 0x3b },
.tag_active_fg = .{ 0xd2, 0xc2, 0xd1 },
.box = .{ 0xe4, 0xb3, 0x9b },
diff --git a/src/themes/forge.zig b/src/themes/forge.zig
index ea871274..83273329 100644
--- a/src/themes/forge.zig
+++ b/src/themes/forge.zig
@@ -8,7 +8,8 @@ pub const theme = .{
.fg = .{ 0xe5, 0xe5, 0xe5 },
.tag_bg = .{ 0x22, 0x25, 0x2b },
.tag_fg = .{ 0xc5, 0xc9, 0xd2 },
- .tag_name_fg = .{ 0xed, 0xc0, 0x9c },
+ .tag_name_fg = .{ 0xec, 0xbf, 0x9b },
+ .tag_active_name_fg = .{ 0xf8, 0xcb, 0xa7 },
.tag_active_bg = .{ 0x2d, 0x34, 0x40 },
.tag_active_fg = .{ 0xd1, 0xd5, 0xde },
.box = .{ 0xa5, 0xc4, 0xee },
diff --git a/src/themes/forge_black.zig b/src/themes/forge_black.zig
index 1002b0d1..b9847472 100644
--- a/src/themes/forge_black.zig
+++ b/src/themes/forge_black.zig
@@ -8,7 +8,8 @@ pub const theme = .{
.fg = .{ 0xf6, 0xf6, 0xf6 },
.tag_bg = .{ 0x22, 0x25, 0x2b },
.tag_fg = .{ 0xc5, 0xc9, 0xd2 },
- .tag_name_fg = .{ 0xed, 0xc0, 0x9c },
+ .tag_name_fg = .{ 0xec, 0xbf, 0x9b },
+ .tag_active_name_fg = .{ 0xf8, 0xcb, 0xa7 },
.tag_active_bg = .{ 0x2d, 0x34, 0x40 },
.tag_active_fg = .{ 0xd1, 0xd5, 0xde },
.box = .{ 0xa5, 0xc4, 0xee },
diff --git a/src/themes/forge_soft.zig b/src/themes/forge_soft.zig
index 055709a7..b003e559 100644
--- a/src/themes/forge_soft.zig
+++ b/src/themes/forge_soft.zig
@@ -8,7 +8,8 @@ pub const theme = .{
.fg = .{ 0xbf, 0xc3, 0xcc },
.tag_bg = .{ 0x2a, 0x2d, 0x34 },
.tag_fg = .{ 0xc5, 0xc9, 0xd2 },
- .tag_name_fg = .{ 0xed, 0xc0, 0x9c },
+ .tag_name_fg = .{ 0xec, 0xbf, 0x9b },
+ .tag_active_name_fg = .{ 0xf8, 0xcb, 0xa7 },
.tag_active_bg = .{ 0x37, 0x3e, 0x49 },
.tag_active_fg = .{ 0xd1, 0xd5, 0xde },
.box = .{ 0xa5, 0xc4, 0xee },
diff --git a/src/themes/harvest.zig b/src/themes/harvest.zig
index 85f8e5b4..a2b4d619 100644
--- a/src/themes/harvest.zig
+++ b/src/themes/harvest.zig
@@ -8,7 +8,8 @@ pub const theme = .{
.fg = .{ 0xf3, 0xf2, 0xcc },
.tag_bg = .{ 0x34, 0x3b, 0x2e },
.tag_fg = .{ 0xd5, 0xd8, 0xb8 },
- .tag_name_fg = .{ 0xbb, 0xdc, 0xec },
+ .tag_name_fg = .{ 0xba, 0xdb, 0xeb },
+ .tag_active_name_fg = .{ 0xc5, 0xe7, 0xf7 },
.tag_active_bg = .{ 0x42, 0x4d, 0x38 },
.tag_active_fg = .{ 0xe1, 0xe4, 0xc4 },
.box = .{ 0xcf, 0xba, 0x8b },
diff --git a/src/themes/ink.zig b/src/themes/ink.zig
index 03c3e41b..352fd095 100644
--- a/src/themes/ink.zig
+++ b/src/themes/ink.zig
@@ -7,7 +7,8 @@ pub const theme = .{
.fg = .{ 0xf3, 0xf7, 0xfc },
.tag_bg = .{ 0x15, 0x21, 0x2c },
.tag_fg = .{ 0xd5, 0xe4, 0xf1 },
- .tag_name_fg = .{ 0xf3, 0xde, 0xaa },
+ .tag_name_fg = .{ 0xf5, 0xe0, 0xac },
+ .tag_active_name_fg = .{ 0xff, 0xea, 0xb8 },
.tag_active_bg = .{ 0x22, 0x33, 0x42 },
.tag_active_fg = .{ 0xe1, 0xee, 0xf9 },
.box = .{ 0x86, 0xd8, 0xff },
diff --git a/src/themes/lagoon.zig b/src/themes/lagoon.zig
index 49a5d28a..b19597e8 100644
--- a/src/themes/lagoon.zig
+++ b/src/themes/lagoon.zig
@@ -8,7 +8,8 @@ pub const theme = .{
.fg = .{ 0xba, 0xc9, 0xce },
.tag_bg = .{ 0x29, 0x44, 0x3f },
.tag_fg = .{ 0xbb, 0xd7, 0xcb },
- .tag_name_fg = .{ 0xe6, 0xc4, 0xee },
+ .tag_name_fg = .{ 0xe4, 0xc2, 0xec },
+ .tag_active_name_fg = .{ 0xf0, 0xce, 0xf8 },
.tag_active_bg = .{ 0x34, 0x57, 0x4d },
.tag_active_fg = .{ 0xc7, 0xe3, 0xd7 },
.box = .{ 0x89, 0xc7, 0xb4 },
diff --git a/src/themes/orchard.zig b/src/themes/orchard.zig
index 389f9b4d..3e87948c 100644
--- a/src/themes/orchard.zig
+++ b/src/themes/orchard.zig
@@ -7,7 +7,8 @@ pub const theme = .{
.fg = .{ 0xe5, 0xee, 0xe5 },
.tag_bg = .{ 0x1d, 0x28, 0x24 },
.tag_fg = .{ 0xb2, 0xc3, 0xb8 },
- .tag_name_fg = .{ 0xd4, 0xb1, 0xda },
+ .tag_name_fg = .{ 0xd3, 0xb0, 0xd9 },
+ .tag_active_name_fg = .{ 0xdf, 0xbc, 0xe5 },
.tag_active_bg = .{ 0x26, 0x36, 0x2d },
.tag_active_fg = .{ 0xbe, 0xcf, 0xc4 },
.box = .{ 0xad, 0xcc, 0x91 },
diff --git a/src/themes/orchard_black.zig b/src/themes/orchard_black.zig
index fb483e28..8440d9ac 100644
--- a/src/themes/orchard_black.zig
+++ b/src/themes/orchard_black.zig
@@ -7,7 +7,8 @@ pub const theme = .{
.fg = .{ 0xf2, 0xf8, 0xef },
.tag_bg = .{ 0x1d, 0x28, 0x24 },
.tag_fg = .{ 0xb2, 0xc3, 0xb8 },
- .tag_name_fg = .{ 0xd4, 0xb1, 0xda },
+ .tag_name_fg = .{ 0xd3, 0xb0, 0xd9 },
+ .tag_active_name_fg = .{ 0xdf, 0xbc, 0xe5 },
.tag_active_bg = .{ 0x26, 0x36, 0x2d },
.tag_active_fg = .{ 0xbe, 0xcf, 0xc4 },
.box = .{ 0xad, 0xcc, 0x91 },
diff --git a/src/themes/paper.zig b/src/themes/paper.zig
index 1caf8e58..732d3d0a 100644
--- a/src/themes/paper.zig
+++ b/src/themes/paper.zig
@@ -7,7 +7,8 @@ pub const theme = .{
.fg = .{ 0x30, 0x3b, 0x3b },
.tag_bg = .{ 0xe8, 0xea, 0xe3 },
.tag_fg = .{ 0x52, 0x62, 0x5a },
- .tag_name_fg = .{ 0x76, 0x50, 0x87 },
+ .tag_name_fg = .{ 0x72, 0x4c, 0x83 },
+ .tag_active_name_fg = .{ 0x69, 0x44, 0x7a },
.tag_active_bg = .{ 0xdc, 0xe5, 0xdc },
.tag_active_fg = .{ 0x4a, 0x5a, 0x52 },
.box = .{ 0x3c, 0x6b, 0x56 },
diff --git a/src/themes/solarium.zig b/src/themes/solarium.zig
index c3498880..c7ee2bdb 100644
--- a/src/themes/solarium.zig
+++ b/src/themes/solarium.zig
@@ -8,7 +8,8 @@ pub const theme = .{
.fg = .{ 0xa7, 0xb7, 0xae },
.tag_bg = .{ 0x12, 0x3f, 0x43 },
.tag_fg = .{ 0xc7, 0xd4, 0xbd },
- .tag_name_fg = .{ 0xed, 0xc5, 0xe4 },
+ .tag_name_fg = .{ 0xe9, 0xc1, 0xe0 },
+ .tag_active_name_fg = .{ 0xf5, 0xcd, 0xec },
.tag_active_bg = .{ 0x21, 0x4e, 0x50 },
.tag_active_fg = .{ 0xd3, 0xe0, 0xc9 },
.box = .{ 0xd5, 0xbc, 0x72 },
diff --git a/src/themes/spectrum.zig b/src/themes/spectrum.zig
index 3b7511fa..664f4d0f 100644
--- a/src/themes/spectrum.zig
+++ b/src/themes/spectrum.zig
@@ -9,6 +9,7 @@ pub const theme = .{
.tag_bg = .{ 0x3b, 0x38, 0x30 },
.tag_fg = .{ 0xdd, 0xd8, 0xbb },
.tag_name_fg = .{ 0xc5, 0xd7, 0xff },
+ .tag_active_name_fg = .{ 0xd7, 0xe3, 0xff },
.tag_active_bg = .{ 0x4d, 0x47, 0x36 },
.tag_active_fg = .{ 0xe9, 0xe4, 0xc7 },
.box = .{ 0xff, 0xd8, 0x66 },
diff --git a/test/panes.zig b/test/panes.zig
index 4ed8c1e1..72d83ce9 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -757,6 +757,7 @@ const TagNameTintTests = struct {
fn configure(p: *Pardes) void {
var theme = p.theme().*;
theme.tag_name_fg = name_fg;
+ theme.tag_active_name_fg = null;
theme.tag_fg = tag_fg;
p.custom_theme = theme;
p.chrome_animation.snap(pardes.ChromeTheme.fromTheme(p.theme()));