diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/gen_themes.zig | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/tools/gen_themes.zig b/tools/gen_themes.zig index 4fc7ab67..23bcad75 100644 --- a/tools/gen_themes.zig +++ b/tools/gen_themes.zig @@ -55,6 +55,8 @@ const Theme = struct { name: []const u8, bg: ?Rgb, fg: ?Rgb, + sel_bg: Rgb, + sel_fg: Rgb, tag_bg: Rgb, tag_fg: Rgb, box: Rgb, @@ -268,11 +270,14 @@ fn resolve(arena: std.mem.Allocator, tomls: *const std.StringHashMapUnmanaged(To /// else ink — skipping any of them that IS the page (see /// firstNotPage) /// box_dim, -/// scroll_thumb ui.selection.bg, else ui.selection.primary.bg, else +/// scroll_thumb, +/// sel_bg ui.selection.bg, else ui.selection.primary.bg, else /// ui.selection.fg, same page-skipping, else page. No selection /// colour anywhere means the author drew no selection either, /// and a dim box the colour of the page is the honest rendering /// of that — no theme in the vendored set actually gets there +/// sel_fg ui.selection.fg, unless that IS sel_bg, else whichever of +/// ink and page the highlight is farther from /// tag_bg, /// scroll_track ui.statusline.bg, else page /// tag_fg ui.statusline.fg, else ink @@ -295,12 +300,38 @@ fn helixTheme(arena: std.mem.Allocator, stem: []const u8, h: Helix, out: *std.Ar // foreground for it (peachpuff, base16_terminal) is naming the colour the // reverse will land in the background. const sel = h.firstNotPage(page, &.{ .{ "ui.selection", .bg }, .{ "ui.selection.primary", .bg }, .{ "ui.selection", .fg } }) orelse page; + // ...and the same colour is what pardes paints a SELECTION with, which needs + // an ink over it as well. Most themes name none — helix tints the cell and + // lets the syntax colour ride — so the stand-in is whichever of the theme's + // own two extremes the highlight is farther from, in the Rec.601-ish weights + // the move box's glyph is picked with, left unscaled because these three are + // only ever compared with each other. Not a fixed threshold like that one: + // a quarter of the ring is light, and there "the bright end" is the page. + // + // ponytail: two of the theme's own colours, whichever is farther. A theme + // that styles neither ui.text nor a selection foreground on a LIGHT page + // has no dark colour among the two — its ink stand-in is the default + // palette's index 7, a grey meant for dark terminals — and comes out pale + // on pale. One of the 228 (iceberg_light, which inherits its selection from + // the dark variant it repaints). Upgrade path is the move box's other half: + // fall back to flat black or white when neither extreme separates. + const sel_lum = @as(i32, sel[0]) * 3 + @as(i32, sel[1]) * 6 + sel[2]; + const ink_lum = @as(i32, ink[0]) * 3 + @as(i32, ink[1]) * 6 + ink[2]; + const page_lum = @as(i32, page[0]) * 3 + @as(i32, page[1]) * 6 + page[2]; + const sel_far = if (@abs(sel_lum - ink_lum) >= @abs(sel_lum - page_lum)) ink else page; + // A theme that DID name a selection foreground meant it — 16 of the + // vendored ones do — except when it is the colour taken for the background + // one line up, which is the reverse-video case again: those two would paint + // the highlight in one colour on itself. + const named_ink = h.get("ui.selection", .fg); try out.append(arena, .{ .name = try slug(arena, stem), // `palette` stays null: helix leaves the colors a PROGRAM emits alone, // and so do we. .bg = bg, .fg = fg, + .sel_bg = sel, + .sel_fg = if (named_ink) |c| (if (std.mem.eql(u8, &c, &sel)) sel_far else c) else sel_far, .tag_bg = h.get("ui.statusline", .bg) orelse page, .tag_fg = h.get("ui.statusline", .fg) orelse ink, .box = box, @@ -508,6 +539,16 @@ fn readZed(arena: std.mem.Allocator, gpa: std.mem.Allocator, path: []const u8, t .name = try std.fmt.allocPrint(arena, "{s}_zed", .{try slug(arena, (v.get("name") orelse std.process.fatal("{s}: a variant has no `name`", .{path})).string)}), .bg = z.need("editor.background"), .fg = z.need("editor.foreground"), + // zed's TEXT selection is `players[0].selection`, and it is a 24% + // alpha over the page — the colour on screen is the composite, not + // the value. pardes paints opaque cells and `hex` drops alpha, so + // taking it raw would put a full-strength accent behind the text. + // `element.selected` is the same theme's own opaque "this is + // selected" fill, which is the question actually being asked. The + // ink then stays the editor's own text colour, because that fill is + // always a step off the background and never off the text. + .sel_bg = z.need("element.selected"), + .sel_fg = z.need("editor.foreground"), .tag_bg = z.need("status_bar.background"), .tag_fg = z.need("text.muted"), // zed names its accent, so the move box does not have to be guessed |
