about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2026-09-24 16:46:29 +0200
committerRobert Günzler <r@gnzler.io>2026-10-02 10:39:48 +0200
commit1821d750aa0be2f8662001fc90e888a4c2bb9a3f (patch)
treec109343919a23e7fe08818f88d02ef397987589b /src
parent8b578bb5e442359167efda57798693cac7793f61 (diff)
downloadsite-1821d750aa0be2f8662001fc90e888a4c2bb9a3f.tar.gz
support generating index
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to '')
-rw-r--r--src/main.zig76
1 files changed, 63 insertions, 13 deletions
diff --git a/src/main.zig b/src/main.zig
index 6804735..a8603c7 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -270,6 +270,11 @@ const Cli = struct {
         }
 
         {
+            var pn = if (!DEBUG) progress.start("Generating index", 0);
+            defer if (!DEBUG) pn.end();
+            try genIndex(io, gpa, root_dir, target_dir, index);
+        }
+        {
             var pn = if (!DEBUG) progress.start("Generating backrefs", index.items.len);
             defer if (!DEBUG) pn.end();
             try genBackrefs(io, gpa, target_dir, target_path, index, outgoingRefs);
@@ -359,6 +364,28 @@ const Cli = struct {
         }
     }
 
+    fn genIndex(
+        io: Io,
+        gpa: Allocator,
+        root_dir: Io.Dir,
+        target_dir: Io.Dir,
+        index: std.ArrayList([]const u8),
+    ) !void {
+        log.info("Generating index", .{});
+
+        var source = File.init(io, root_dir, "index.htm", null) catch |err|
+            switch (err) {
+                error.FileNotFound => return,
+                else => return err,
+            };
+        defer source.close(io);
+
+        const b = try Builder.init(gpa, root_dir, source, target_dir);
+        b.index = index;
+        defer b.deinit(gpa);
+        try b.build(io, gpa);
+    }
+
     fn serve(io: Io, _: Allocator, _: FlagSet, args: [][]const u8) !void {
         if (args.len != 1) return Cli.usage();
 
@@ -429,10 +456,13 @@ const Builder = struct {
     dgsts: std.ArrayList(Digest) = .empty,
     // track references
     refs: std.ArrayList([]const u8) = .empty,
+    // used for post processing
+    index: ?std.ArrayList([]const u8) = null,
 
     pub const Options = struct {
-        // TODO: this is a bit of a hack no?
-        offset_from_siteroot: ?[]const u8,
+        // TODO: this is a bit of a hack no? we should just track the target
+        // path and use that
+        offset_from_siteroot: ?[]const u8 = "/site",
     };
 
     const DELIM_START: []const u8 = "{[";
@@ -444,9 +474,7 @@ const Builder = struct {
             .root_dir = root_dir,
             .source = source,
             .target_dir = target_dir,
-            .options = .{
-                .offset_from_siteroot = "/site",
-            },
+            .options = .{},
         };
         return b;
     }
@@ -588,6 +616,32 @@ const Builder = struct {
             try w.writeAll("{[builtin.backrefs]}"); // done in post processing
             return;
         }
+        if (std.mem.eql(u8, ref_name, "builtin.index")) {
+            if (self.index == null) {
+                try w.writeAll("{[builtin.backrefs]}"); // done in post processing
+                return;
+            }
+
+            std.debug.assert(self.index != null);
+            try w.writeAll(
+                \\<nav>
+                \\<ul>
+                \\
+            );
+            for (self.index.?.items) |e| try w.print(
+                \\<li><a href="{s}">{s}</a></li>
+                \\
+            , .{
+                try formatLink(gpa, std.fs.path.stem(e), self.options.offset_from_siteroot),
+                try formatName(gpa, std.fs.path.stem(e)),
+            });
+            try w.writeAll(
+                \\</ul>
+                \\</nav>
+                \\
+            );
+            return;
+        }
 
         switch (ref_name[0]) {
             '/' => try self.templatePortal(io, gpa, ref_name[1..], w),
@@ -772,14 +826,10 @@ fn formatName(gpa: Allocator, name: []const u8) ![]u8 {
     return try std.mem.replaceOwned(u8, gpa, name, "_", " ");
 }
 
-fn formatLink(gpa: Allocator, name: []const u8, offset: ?[]const u8) ![]u8 {
-    var link = try std.fmt.allocPrint(gpa, "{s}.html", .{name});
-    if (offset) |_| {
-        const link2 = try std.fs.path.join(gpa, &.{ offset.?, link });
-        gpa.free(link);
-        link = link2;
-    }
-    return link;
+fn formatLink(gpa: Allocator, name: []const u8, pathPrefix: ?[]const u8) ![]u8 {
+    const link_name = try std.fmt.allocPrint(gpa, "{s}.html", .{name});
+    defer gpa.free(link_name);
+    return try std.fs.path.join(gpa, &.{ pathPrefix orelse "/", link_name });
 }
 
 fn targetExists(io: Io, gpa: Allocator, target_dir: Io.Dir, sub_path: []const u8, root_dir: Io.Dir) !bool {