about summary refs log tree commit diff
path: root/src/gen.zig
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2026-04-08 13:29:17 +0900
committerRobert Günzler <r@gnzler.io>2026-04-08 13:50:39 +0900
commit2200e168cfc35134aec2ccc656ad5419663a973c (patch)
tree3b85ec1e701ffad2a519fd5d9c54321be5c3eedf /src/gen.zig
parent8bca0ebd8645bf2714035ed61ac140956a83fc21 (diff)
downloadsite-2200e168cfc35134aec2ccc656ad5419663a973c.tar.gz
start refactoring to support multiple page roots
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to 'src/gen.zig')
-rw-r--r--src/gen.zig127
1 files changed, 57 insertions, 70 deletions
diff --git a/src/gen.zig b/src/gen.zig
index 449342e..fd1dff7 100644
--- a/src/gen.zig
+++ b/src/gen.zig
@@ -9,21 +9,21 @@ const log = std.log.scoped(.gen);
 pub fn generate(ctx: *Context) !void {
     ctx.generated.clearRetainingCapacity();
 
-    ctx.progress_start("generate");
+    ctx.progress_start("generate", true);
     defer ctx.progress_end();
 
-    try genIndex(ctx);
+    try index(ctx);
 
     log.info("Generated index.", .{});
 
-    try genSites(ctx);
+    try pages(ctx);
 
     log.info("Generated {d} files.", .{ctx.generated.items.len});
     log.info("Generated {d} tildes.", .{ctx.tilde});
 }
 
-fn genIndex(ctx: *Context) !void {
-    ctx.progress_start("index.htm");
+fn index(ctx: *Context) !void {
+    ctx.progress_start("index.htm", false);
     defer ctx.progress_end();
 
     const srcpathIndex = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.PAGE_PATH}, &.{"index.htm"});
@@ -40,32 +40,21 @@ fn genIndex(ctx: *Context) !void {
         \\
     );
 
-    // alphanum ascii sort
-    std.mem.sort(
-        []const u8,
-        ctx.pages.items,
-        {},
-        struct {
-            fn lessthan(_: void, a: []const u8, b: []const u8) bool {
-                return std.ascii.lessThanIgnoreCase(a, b);
+    for (ctx.sites.items) |s| {
+        for (s.pages.items) |p| {
+            if (p.kind == .Htm) {
+                const dstpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.SITE_PATH}, &.{ p.name, ".html" });
+                defer ctx.allocator().free(dstpath);
+
+                try w.interface.print(
+                    \\<li><a href="/{[LINK]s}">{[NAME]s}</a></li>
+                    \\
+                , .{
+                    .LINK = dstpath,
+                    .NAME = p.name,
+                });
             }
-        }.lessthan,
-    );
-
-    for (ctx.pages.items) |p| {
-        if (std.mem.startsWith(u8, p, "meta.")) continue;
-
-        const dstname = try fs.stripExtension(p);
-        const dstpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.SITE_PATH}, &.{ dstname, ".html" });
-        defer ctx.allocator().free(dstpath);
-
-        try w.interface.print(
-            \\<li><a href="/{[LINK]s}">{[NAME]s}</a></li>
-            \\
-        , .{
-            .LINK = dstpath,
-            .NAME = dstname,
-        });
+        }
     }
 
     try w.interface.writeAll(
@@ -76,27 +65,25 @@ fn genIndex(ctx: *Context) !void {
     try w.interface.flush();
 }
 
-fn genSites(ctx: *Context) !void {
-    for (ctx.pages.items) |p| {
-        if (std.mem.startsWith(u8, std.fs.path.basename(p), "meta.")) {
-            // meta pages
-            try meta(ctx, p);
-            continue;
+fn pages(ctx: *Context) !void {
+    for (ctx.sites.items) |s| {
+        for (s.pages.items) |p| {
+            if (p.kind == .Meta) {
+                try meta(ctx, p);
+            } else if (p.kind == .Htm) {
+                try page(ctx, p);
+            }
         }
-
-        // regular pages
-        try genSite(ctx, p);
     }
 }
 
-fn genSite(ctx: *Context, p: []const u8) !void {
-    ctx.progress_start(std.fs.path.basename(p));
+fn page(ctx: *Context, p: Context.Site.Page) !void {
+    ctx.progress_start(p.name, false);
     defer ctx.progress_end();
 
-    const dstname = try fs.stripExtension(p);
-    const srcpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.PAGE_PATH}, &.{ dstname, ".htm" });
+    const srcpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.PAGE_PATH}, &.{ p.name, ".htm" });
     defer ctx.allocator().free(srcpath);
-    const dstpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.SITE_PATH}, &.{ dstname, ".html" });
+    const dstpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.SITE_PATH}, &.{ p.name, ".html" });
     defer ctx.allocator().free(dstpath);
     const rel_dstpath = try std.fs.path.relative(ctx.allocator(), Context.params.SITE_PATH, dstpath);
     defer ctx.allocator().free(rel_dstpath);
@@ -112,14 +99,14 @@ fn genSite(ctx: *Context, p: []const u8) !void {
     const dstmtime = try fs.getLastEdit(dstpath);
     if (!ctx.force and srcmtime.sec < dstmtime.sec) return;
 
-    log.debug("generating {s} at {s}", .{ p, rel_dstpath });
+    log.debug("generating {s} at {s}", .{ p.path, rel_dstpath });
 
     const f = try fs.FileSwapper.createAt(ctx.allocator(), dstpath);
 
     var buffer: [1024]u8 = undefined;
     var w = f.writer(&buffer);
 
-    const page_name = try std.mem.replaceOwned(u8, ctx.allocator(), dstname, "_", " ");
+    const page_name = try std.mem.replaceOwned(u8, ctx.allocator(), p.name, "_", " ");
     defer ctx.allocator().free(page_name);
 
     try build(ctx.allocator(), &w.interface, page_name, srcpath);
@@ -230,19 +217,18 @@ fn build(allocator: std.mem.Allocator, w: *std.Io.Writer, page_name: []const u8,
 // build a virtual html file, currently either:
 // - meta.nav: used for populating the global navigation menu
 // - meta.tilde: used to create ~foobar files
-fn meta(ctx: *Context, p: []const u8) !void {
-    ctx.progress_start(std.fs.path.basename(p));
+fn meta(ctx: *Context, p: Context.Site.Page) !void {
+    ctx.progress_start(p.name, false);
     defer ctx.progress_end();
 
     ctx.meta += 1;
 
-    if (std.mem.startsWith(u8, p, "meta.nav.")) return;
+    if (std.mem.startsWith(u8, p.name, "meta.nav")) return;
 
-    if (std.mem.startsWith(u8, p, "meta.tilde.")) {
-        const dot = std.mem.indexOfPosLinear(u8, p, 11, ".");
-        const dstname = p[11..dot.?];
-        const srcpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.PAGE_PATH}, &.{p});
+    if (std.mem.startsWith(u8, p.name, "meta.tilde")) {
+        const srcpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.PAGE_PATH}, &.{p.path});
         defer ctx.allocator().free(srcpath);
+        const dstname = p.name[11..]; // trim "meta.tilde." from the name
         const dstpath = try fs.joinPathAndFilename(ctx.allocator(), &.{Context.params.LINK_PATH}, &.{ "~", dstname });
         defer ctx.allocator().free(dstpath);
 
@@ -289,6 +275,7 @@ fn meta(ctx: *Context, p: []const u8) !void {
         return;
     }
 
+    log.err("unknown meta page type: {s}", .{p.name});
     return error.unknownMeta;
 }
 
@@ -390,49 +377,49 @@ const Page = struct {
 };
 
 fn portal(allocator: std.mem.Allocator, w: *std.Io.Writer, refname: []const u8, insert_heading: bool) anyerror!void {
-    const page = try Page.from_ref(allocator, refname);
-    defer page.deinit();
+    const p = try Page.from_ref(allocator, refname);
+    defer p.deinit();
 
     if (insert_heading)
         try w.print(
             \\<h2 id="{[ID]s}"><a href="/{[PATH]s}">{[NAME]s}</a></2>
             \\
         , .{
-            .ID = page.ref,
-            .NAME = page.name,
-            .PATH = page.html,
+            .ID = p.ref,
+            .NAME = p.name,
+            .PATH = p.html,
         });
 
-    try inject(allocator, w, page.htm);
+    try inject(allocator, w, p.htm);
 
     // XXX: track ref count?
 }
 
 fn ref(allocator: std.mem.Allocator, w: *std.Io.Writer, refname: []const u8) anyerror!void {
-    const page = try Page.from_ref(allocator, refname);
-    defer page.deinit();
+    const p = try Page.from_ref(allocator, refname);
+    defer p.deinit();
 
     try w.print(
         \\<a href="/{[PATH]s}{[ANCHOR]s}">{[NAME]s}</a>
     , .{
-        .NAME = page.name,
-        .PATH = page.html,
-        .ANCHOR = page.anchor,
+        .NAME = p.name,
+        .PATH = p.html,
+        .ANCHOR = p.anchor,
     });
 
     // XXX: track ref count?
 }
 
 fn ref_link(allocator: std.mem.Allocator, w: *std.Io.Writer, refname: []const u8) anyerror!void {
-    const page = try Page.from_ref(allocator, refname);
-    defer page.deinit();
+    const p = try Page.from_ref(allocator, refname);
+    defer p.deinit();
 
-    try w.print("/{s}{s}", .{ page.html, page.anchor });
+    try w.print("/{s}{s}", .{ p.html, p.anchor });
 }
 
 fn ref_name(allocator: std.mem.Allocator, w: *std.Io.Writer, refname: []const u8) anyerror!void {
-    const page = try Page.from_ref(allocator, refname);
-    defer page.deinit();
+    const p = try Page.from_ref(allocator, refname);
+    defer p.deinit();
 
-    try w.print("{s}", .{page.ref});
+    try w.print("{s}", .{p.ref});
 }