about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/main.zig70
1 files changed, 37 insertions, 33 deletions
diff --git a/src/main.zig b/src/main.zig
index 3e2fa7e..1a4a86c 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -16,8 +16,6 @@ const LICENSE_NAME = "BY-NC-SA 4.0";
 const LICENSE_URL = "https://git.sr.ht/~robertgzr/site/blob/rabbits/LICENSE.content";
 const SOURCE_URL = "https://git.sr.ht/~robertgzr/site/tree/rabbits";
 
-const BuildErrors = (std.fs.File.OpenError || std.fs.File.WriteError || std.mem.Allocator.Error);
-
 // tune std.log options
 pub const std_options = .{
     .log_level = .info,
@@ -56,7 +54,7 @@ fn joinIn(allocator: std.mem.Allocator, paths: []const []const u8, filename_part
     return try std.fs.path.join(allocator, paths2);
 }
 
-fn portal(allocator: std.mem.Allocator, f: std.fs.File, refname: []const u8, insert_heading: bool) BuildErrors!void {
+fn portal(allocator: std.mem.Allocator, w: std.io.AnyWriter, refname: []const u8, insert_heading: bool) anyerror!void {
     const basename = try std.mem.replaceOwned(u8, allocator, refname, " ", "_");
     defer allocator.free(basename);
     const refpathPage = try joinIn(allocator, &.{PAGE_PATH}, &.{ basename, ".htm" });
@@ -65,7 +63,7 @@ fn portal(allocator: std.mem.Allocator, f: std.fs.File, refname: []const u8, ins
     defer allocator.free(refpathSite);
 
     if (insert_heading)
-        try f.writer().print(
+        try w.print(
             \\<h2 id="{[ID]s}"><a href="/{[PATH]s}">{[NAME]s}</a></2>
             \\
         , .{
@@ -74,21 +72,18 @@ fn portal(allocator: std.mem.Allocator, f: std.fs.File, refname: []const u8, ins
             .PATH = refpathSite,
         });
 
-    try inject(allocator, f, refpathPage);
+    try inject(allocator, w, refpathPage);
 
     // XXX: track ref count?
 }
 
-fn template(allocator: std.mem.Allocator, f: std.fs.File, refname: []const u8) BuildErrors!void {
-    if (std.mem.startsWith(u8, refname, "/"))
-        return try portal(allocator, f, refname[1..], false);
-
+fn ref(allocator: std.mem.Allocator, w: std.io.AnyWriter, refname: []const u8) anyerror!void {
     const basename = try std.mem.replaceOwned(u8, allocator, refname, " ", "_");
     defer allocator.free(basename);
     const refpathSite = try joinIn(allocator, &.{SITE_PATH}, &.{ basename, ".html" });
     defer allocator.free(refpathSite);
 
-    try f.writer().print(
+    try w.print(
         \\<a href="/{[PATH]s}">{[NAME]s}</a>
         \\
     , .{
@@ -99,7 +94,16 @@ fn template(allocator: std.mem.Allocator, f: std.fs.File, refname: []const u8) B
     // XXX: track ref count?
 }
 
-fn inject(allocator: std.mem.Allocator, f: std.fs.File, srcpath: []const u8) BuildErrors!void {
+fn template(allocator: std.mem.Allocator, w: std.io.AnyWriter, refname: []const u8) anyerror!void {
+    if (std.mem.startsWith(u8, refname, "/")) {
+        return try portal(allocator, w, refname[1..], false);
+    } else {
+        return try ref(allocator, w, refname);
+    }
+}
+
+// Parses srcpath, resolves refs and portals and writes everything to w
+fn inject(allocator: std.mem.Allocator, w: std.io.AnyWriter, srcpath: []const u8) !void {
     const inc = std.fs.cwd().openFile(srcpath, .{ .mode = .read_only }) catch |err| {
         if (err == error.FileNotFound)
             std.log.warn("Missing {s} include.", .{srcpath});
@@ -108,7 +112,7 @@ fn inject(allocator: std.mem.Allocator, f: std.fs.File, srcpath: []const u8) Bui
     };
     defer inc.close();
 
-    var buf_writer = std.io.bufferedWriter(f.writer());
+    var buf_writer = std.io.bufferedWriter(w);
     var out_stream = buf_writer.writer();
 
     var buf_reader = std.io.bufferedReader(inc.reader());
@@ -116,37 +120,36 @@ fn inject(allocator: std.mem.Allocator, f: std.fs.File, srcpath: []const u8) Bui
 
     var arena = std.heap.ArenaAllocator.init(allocator);
     defer arena.deinit();
+
     while (in_stream.readUntilDelimiterOrEofAlloc(
         arena.allocator(),
         '\n',
         buf_reader.buf.len,
-    ) catch @panic("Failed to read from stream")) |chunk| {
-        if (std.mem.indexOfPosLinear(u8, chunk, 0, "{")) |start| {
-            try out_stream.writeAll(chunk[0..start]);
-            try buf_writer.flush();
+    ) catch {
+        @panic("Failed to read from stream");
+    }) |chunk| {
+        defer _ = arena.reset(.free_all);
 
+        if (std.mem.indexOfPosLinear(u8, chunk, 0, "{")) |start| {
             if (std.mem.indexOfPosLinear(u8, chunk, start + 1, "}")) |end| {
-                try template(allocator, f, chunk[start + 1 .. end]);
-                try buf_writer.flush();
-
+                try out_stream.writeAll(chunk[0..start]);
+                template(allocator, out_stream.any(), chunk[start + 1 .. end]) catch
+                    @panic("Failed to resolve template");
                 try out_stream.writeAll(chunk[end + 1 ..]);
-                try buf_writer.flush();
-            } else {
-                // NOTE: we need to print the opening brace. we did not find a
-                // closing brace on the same line, so this isn't a ref
-                try out_stream.writeAll("{");
+                try out_stream.writeByte('\n');
+                continue;
             }
-        } else {
-            try out_stream.writeAll(chunk);
-            try out_stream.writeByte('\n');
         }
-        _ = arena.reset(.free_all);
+
+        try out_stream.writeAll(chunk);
+        try out_stream.writeByte('\n');
+        try buf_writer.flush();
     }
 
     try buf_writer.flush();
 }
 
-fn build(allocator: std.mem.Allocator, f: std.fs.File, page_name: []const u8, srcpath: []const u8) BuildErrors!void {
+fn build(allocator: std.mem.Allocator, f: std.fs.File, page_name: []const u8, srcpath: []const u8) !void {
     const mtime = blk: {
         const attr = try allocator.create(std.os.linux.Stat);
         defer allocator.destroy(attr);
@@ -193,7 +196,7 @@ fn build(allocator: std.mem.Allocator, f: std.fs.File, page_name: []const u8, sr
         \\<nav>
         \\
     );
-    portal(allocator, f, "meta.nav", false) catch {}; // ignore error
+    portal(allocator, f.writer().any(), "meta.nav", false) catch {}; // ignore error
     try f.writer().writeAll(
         \\</nav>
         \\
@@ -210,7 +213,7 @@ fn build(allocator: std.mem.Allocator, f: std.fs.File, page_name: []const u8, sr
     , .{
         .PAGE_NAME = page_name,
     });
-    try inject(allocator, f, srcpath);
+    try inject(allocator, f.writer().any(), srcpath);
     try f.writer().writeAll(
         \\
         \\</main>
@@ -432,14 +435,15 @@ pub fn main() !void {
 
     std.log.info("Indexed {d} pages.", .{pages.len});
 
-    std.log.info("Generated index.", .{});
-
     var ctx = Context{
         .allocator = allocator,
         .pages = pages,
     };
 
     try genIndexHtml(&ctx);
+
+    std.log.info("Generated index.", .{});
+
     try genSite(&ctx);
 
     std.log.info("Generated {d} files.", .{ctx.generated});