summaryrefslogtreecommitdiff
path: root/src/colors.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/colors.zig')
-rw-r--r--src/colors.zig159
1 files changed, 156 insertions, 3 deletions
diff --git a/src/colors.zig b/src/colors.zig
index 5694998d..da074765 100644
--- a/src/colors.zig
+++ b/src/colors.zig
@@ -105,6 +105,25 @@ test "every native theme's separators stand off its page, and its focus tint off
}
}
+test "every faithful port meets pardes's chrome floors in its own colours, with nothing left to derive" {
+ const first = comptime indexOfTheme("lapis") + 1;
+ const last = comptime indexOfTheme("helix");
+ for (themes[first..last]) |*th| {
+ const chrome = ChromeTheme.fromTheme(th);
+ const page = th.bg.?;
+ // Written out already adjusted: the run-time lift and push leave
+ // the file's own values, so what the file says is what is drawn.
+ try std.testing.expectEqual(th.border.?, chrome.border);
+ try std.testing.expectEqual(th.tag_active_bg.?, chrome.tag_active_bg);
+ try std.testing.expect(contrast(th.border.?, page) >= separator_floor);
+ try std.testing.expect(contrast(th.tag_active_bg.?, th.tag_bg) >= focusTintFloor(th));
+ try std.testing.expect(contrast(th.tag_fg, th.tag_bg) >= 4.5);
+ try std.testing.expect(contrast(th.tag_active_fg.?, th.tag_active_bg.?) >= 4.5);
+ try std.testing.expect(contrast(th.box_dim, th.tag_bg) >= 1.5);
+ try std.testing.expect(th.palette != null);
+ }
+}
+
test "a derived separator or tint keeps the theme's own when it already stands off" {
const forge = &themes[for (themes[0..native_count], 0..) |t, i| {
if (std.mem.eql(u8, t.name, "forge")) break i;
@@ -303,10 +322,76 @@ const curated = struct {
pub const forge_black = @import("themes/forge_black.zig");
pub const forge_soft = @import("themes/forge_soft.zig");
pub const orchard_black = @import("themes/orchard_black.zig");
- pub const helix = @import("themes/helix.zig");
- pub const dark = @import("themes/dark.zig");
pub const acme = @import("themes/acme.zig");
pub const lapis = @import("themes/lapis.zig");
+ // Faithful ports of well-known themes, a family at a time (src/themes/
+ // <name>.zig says where each value came from): `theme_groups`.
+ pub const dark_plus = @import("themes/dark_plus.zig");
+ pub const solarized_dark = @import("themes/solarized_dark.zig");
+ pub const solarized_light = @import("themes/solarized_light.zig");
+ pub const dracula = @import("themes/dracula.zig");
+ pub const dracula_soft = @import("themes/dracula_soft.zig");
+ pub const alucard = @import("themes/alucard.zig");
+ pub const monokai = @import("themes/monokai.zig");
+ pub const monokai_pro = @import("themes/monokai_pro.zig");
+ pub const monokai_pro_classic = @import("themes/monokai_pro_classic.zig");
+ pub const monokai_pro_machine = @import("themes/monokai_pro_machine.zig");
+ pub const monokai_pro_octagon = @import("themes/monokai_pro_octagon.zig");
+ pub const monokai_pro_ristretto = @import("themes/monokai_pro_ristretto.zig");
+ pub const monokai_pro_spectrum = @import("themes/monokai_pro_spectrum.zig");
+ pub const monokai_pro_light = @import("themes/monokai_pro_light.zig");
+ pub const monokai_pro_light_sun = @import("themes/monokai_pro_light_sun.zig");
+ pub const tokyonight_night = @import("themes/tokyonight_night.zig");
+ pub const tokyonight_storm = @import("themes/tokyonight_storm.zig");
+ pub const tokyonight_moon = @import("themes/tokyonight_moon.zig");
+ pub const tokyonight_day = @import("themes/tokyonight_day.zig");
+ pub const rose_pine = @import("themes/rose_pine.zig");
+ pub const rose_pine_moon = @import("themes/rose_pine_moon.zig");
+ pub const rose_pine_dawn = @import("themes/rose_pine_dawn.zig");
+ pub const catppuccin_latte = @import("themes/catppuccin_latte.zig");
+ pub const catppuccin_frappe = @import("themes/catppuccin_frappe.zig");
+ pub const catppuccin_macchiato = @import("themes/catppuccin_macchiato.zig");
+ pub const catppuccin_mocha = @import("themes/catppuccin_mocha.zig");
+ pub const seoul256_dark_233 = @import("themes/seoul256_dark_233.zig");
+ pub const seoul256_dark_234 = @import("themes/seoul256_dark_234.zig");
+ pub const seoul256_dark_235 = @import("themes/seoul256_dark_235.zig");
+ pub const seoul256_dark_236 = @import("themes/seoul256_dark_236.zig");
+ pub const seoul256_dark_237 = @import("themes/seoul256_dark_237.zig");
+ pub const seoul256_dark_238 = @import("themes/seoul256_dark_238.zig");
+ pub const seoul256_dark_239 = @import("themes/seoul256_dark_239.zig");
+ pub const seoul256_light_252 = @import("themes/seoul256_light_252.zig");
+ pub const seoul256_light_253 = @import("themes/seoul256_light_253.zig");
+ pub const seoul256_light_254 = @import("themes/seoul256_light_254.zig");
+ pub const seoul256_light_255 = @import("themes/seoul256_light_255.zig");
+ pub const seoul256_light_256 = @import("themes/seoul256_light_256.zig");
+ pub const zenbones_light = @import("themes/zenbones_light.zig");
+ pub const zenbones_dark = @import("themes/zenbones_dark.zig");
+ pub const neobones_light = @import("themes/neobones_light.zig");
+ pub const neobones_dark = @import("themes/neobones_dark.zig");
+ pub const vimbones = @import("themes/vimbones.zig");
+ pub const forestbones_light = @import("themes/forestbones_light.zig");
+ pub const forestbones_dark = @import("themes/forestbones_dark.zig");
+ pub const nordbones = @import("themes/nordbones.zig");
+ pub const rosebones_light = @import("themes/rosebones_light.zig");
+ pub const rosebones_dark = @import("themes/rosebones_dark.zig");
+ pub const tokyobones_light = @import("themes/tokyobones_light.zig");
+ pub const tokyobones_dark = @import("themes/tokyobones_dark.zig");
+ pub const seoulbones_light = @import("themes/seoulbones_light.zig");
+ pub const seoulbones_dark = @import("themes/seoulbones_dark.zig");
+ pub const duckbones = @import("themes/duckbones.zig");
+ pub const zenburned = @import("themes/zenburned.zig");
+ pub const zenwritten_light = @import("themes/zenwritten_light.zig");
+ pub const zenwritten_dark = @import("themes/zenwritten_dark.zig");
+ pub const kanagawabones = @import("themes/kanagawabones.zig");
+ pub const nord = @import("themes/nord.zig");
+ pub const ayu_dark = @import("themes/ayu_dark.zig");
+ pub const ayu_mirage = @import("themes/ayu_mirage.zig");
+ pub const ayu_light = @import("themes/ayu_light.zig");
+ pub const doom_one = @import("themes/doom_one.zig");
+ pub const doom_one_light = @import("themes/doom_one_light.zig");
+ // The legacy pair last.
+ pub const helix = @import("themes/helix.zig");
+ pub const dark = @import("themes/dark.zig");
};
fn fold(comptime C: type) [@typeInfo(C).@"struct".decls.len]Theme {
@@ -338,10 +423,78 @@ fn fold(comptime C: type) [@typeInfo(C).@"struct".decls.len]Theme {
}
}
-pub const themes = fold(curated) ++ fold(@import("generated_themes"));
+/// The imported themes (tools/gen_themes.zig), less any name one of ours
+/// takes: a faithful port (`dracula`) keeps the plain name, and helix's
+/// looser copy of it is still there as `dracula_helix` (the zed ones already
+/// carry `_zed`).
+fn foldImports(comptime ours: anytype, comptime C: type) [@typeInfo(C).@"struct".decls.len]Theme {
+ comptime {
+ @setEvalBranchQuota(400000);
+ var out = fold(C);
+ for (&out) |*g| for (ours) |c| if (std.mem.eql(u8, c.name, g.name)) {
+ g.name = g.name ++ "_helix";
+ };
+ return out;
+ }
+}
+
+pub const themes = fold(curated) ++ foldImports(fold(curated), @import("generated_themes"));
/// The first `native_count` of `themes` are pardes's own; the rest imported.
pub const native_count = @typeInfo(curated).@"struct".decls.len;
+/// The picker's sections (`Themes`), in ring order, each running from
+/// the theme it names to the next section's; `NextColor` and `Theme` still
+/// see one flat ring. The current pardes themes, then the faithful ports a
+/// family at a time, then the legacy pair (`helix`, captured from an old
+/// helix setup and the boot default before orchard; `dark`, the host
+/// terminal's own ground), then everything imported.
+pub const ThemeGroup = struct { title: []const u8, first: []const u8 };
+const theme_groups = [_]ThemeGroup{
+ .{ .title = "Pardes themes", .first = "orchard" },
+ .{ .title = "Visual Studio Code", .first = "dark_plus" },
+ .{ .title = "Solarized", .first = "solarized_dark" },
+ .{ .title = "Dracula", .first = "dracula" },
+ .{ .title = "Monokai", .first = "monokai" },
+ .{ .title = "Monokai Pro", .first = "monokai_pro" },
+ .{ .title = "Tokyo Night", .first = "tokyonight_night" },
+ .{ .title = "Rosé Pine", .first = "rose_pine" },
+ .{ .title = "Catppuccin", .first = "catppuccin_latte" },
+ .{ .title = "Seoul256", .first = "seoul256_dark_233" },
+ .{ .title = "Zenbones", .first = "zenbones_light" },
+ .{ .title = "Nord", .first = "nord" },
+ .{ .title = "Ayu", .first = "ayu_dark" },
+ .{ .title = "Doom One", .first = "doom_one" },
+ .{ .title = "Legacy themes", .first = "helix" },
+};
+
+fn indexOfTheme(comptime name: []const u8) usize {
+ return comptime blk: {
+ @setEvalBranchQuota(100000);
+ for (themes[0..native_count], 0..) |t, i| if (std.mem.eql(u8, t.name, name)) break :blk i;
+ @compileError("theme_groups names " ++ name ++ ", which is not one of ours");
+ };
+}
+
+/// The heading of the picker section that starts at ring index `index`.
+pub fn groupAt(index: usize) ?[]const u8 {
+ inline for (theme_groups) |g| if (index == comptime indexOfTheme(g.first)) return g.title;
+ if (index == native_count) return "Imported themes (helix, zed)";
+ return null;
+}
+
+test "the picker's sections run in ring order and cover it" {
+ var last: usize = 0;
+ inline for (theme_groups, 0..) |g, n| {
+ const at = comptime indexOfTheme(g.first);
+ if (n == 0) try std.testing.expectEqual(@as(usize, 0), at) else try std.testing.expect(at > last);
+ last = at;
+ }
+ try std.testing.expectEqualStrings("Pardes themes", groupAt(0).?);
+ // acme is a current theme, not a legacy one.
+ try std.testing.expect(indexOfTheme("acme") < indexOfTheme("helix"));
+ try std.testing.expect(groupAt(native_count) != null);
+}
+
/// Original and classic-inspired Pardes palettes precede retained imports.
pub const native_theme_count = 15;