summaryrefslogtreecommitdiff
path: root/build.zig
diff options
context:
space:
mode:
Diffstat (limited to 'build.zig')
-rw-r--r--build.zig59
1 files changed, 58 insertions, 1 deletions
diff --git a/build.zig b/build.zig
index c11ccccd..04516cc8 100644
--- a/build.zig
+++ b/build.zig
@@ -93,7 +93,8 @@ pub fn build(b: *std.Build) void {
else
null;
- // build-time IO, only used to slurp the grammars' highlights.scm queries
+ // build-time IO: slurps the grammars' highlights.scm queries, and reads
+ // vendor/themes to find the theme sources
var threaded: std.Io.Threaded = .init(b.allocator, .{});
defer threaded.deinit();
const io = threaded.io();
@@ -115,6 +116,40 @@ pub fn build(b: *std.Build) void {
.link_libc = true,
});
+ // THEMES. tools/gen_themes.zig turns each vendored helix .toml / zed .json
+ // into one .zig file per theme plus a list.zig that imports them all;
+ // src/pardes.zig folds that list into the ring beside the three it ships.
+ //
+ // Straight into the build cache and handed over as a module, rather than
+ // written back into src/: the output then has no freshness problem to own
+ // (zig re-runs the generator only when a vendored file changes, and a
+ // cached run leaves the compile's inputs byte-identical, so `zig build`
+ // with nothing touched still does nothing), there is nothing to gitignore
+ // and no stale .zig can survive a deleted source.
+ //
+ // The INPUT list is read from the directory here rather than written out,
+ // so adding a theme is dropping a file in — and each file goes in as a
+ // content-hashed argument, which is what makes that new file re-run the
+ // step and nothing else.
+ const theme_gen = b.addExecutable(.{
+ .name = "pardes-gen-themes",
+ .root_module = b.createModule(.{
+ .target = b.graph.host,
+ .optimize = .ReleaseSafe,
+ .root_source_file = b.path("tools/gen_themes.zig"),
+ }),
+ });
+ const run_theme_gen = b.addRunArtifact(theme_gen);
+ const themes_out = run_theme_gen.addOutputDirectoryArg("themes");
+ for (vendoredThemes(b, io)) |name| run_theme_gen.addFileArg(b.path(b.fmt("vendor/themes/{s}", .{name})));
+ const themes_mod = b.createModule(.{
+ .target = target,
+ .optimize = optimize,
+ .root_source_file = themes_out.path(b, "list.zig"),
+ });
+ root_mod.addImport("generated_themes", themes_mod);
+ hx_core_mod.addImport("generated_themes", themes_mod);
+
// static archives the emcc link needs beyond the zig object (grammars, SDL)
var wasm_libs: std.ArrayList(std.Build.LazyPath) = .empty;
@@ -713,6 +748,28 @@ fn compileGlsl(b: *std.Build, src: []const u8, stage: []const u8, out: []const u
return cmd.addOutputFileArg(out);
}
+/// The theme sources, sorted. SORTED because the run step is cached by its
+/// argv: readdir order is whatever the filesystem feels like, and an argv that
+/// shuffles is a cache miss and a rebuild every time. Anything that is not a
+/// .toml or a .json is skipped, which is what lets the upstream LICENSE files
+/// sit beside the themes they cover.
+fn vendoredThemes(b: *std.Build, io: std.Io) []const []const u8 {
+ var dir = b.build_root.handle.openDir(io, "vendor/themes", .{ .iterate = true }) catch @panic("open vendor/themes");
+ defer dir.close(io);
+ var names: std.ArrayList([]const u8) = .empty;
+ var it = dir.iterate();
+ while (it.next(io) catch @panic("read vendor/themes")) |e| {
+ if (!std.mem.endsWith(u8, e.name, ".toml") and !std.mem.endsWith(u8, e.name, ".json")) continue;
+ names.append(b.allocator, b.dupe(e.name)) catch @panic("OOM");
+ }
+ std.mem.sort([]const u8, names.items, {}, struct {
+ fn lt(_: void, a: []const u8, c: []const u8) bool {
+ return std.mem.order(u8, a, c) == .lt;
+ }
+ }.lt);
+ return names.items;
+}
+
fn detectEmscriptenSysroot(b: *std.Build) ?[]const u8 {
if (b.option([]const u8, "emscripten-sysroot", "path to the Emscripten sysroot")) |path| return path;
if (b.sysroot) |path| return path;