diff options
| author | Robert Günzler <r@gnzler.io> | 2025-09-10 14:37:49 +0200 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2025-09-24 01:47:16 +0200 |
| commit | 0bf92658eb1972d4312383a3a70d7c032e9bfdbb (patch) | |
| tree | 26f04a152732a6facbbfb163096d454a69dc0646 | |
| parent | f37ab57d68b12262a366bfe11be892738ebf7f55 (diff) | |
| download | site-0bf92658eb1972d4312383a3a70d7c032e9bfdbb.tar.gz | |
better handle refs by looking up pages on use
this fixes an issue where nonexistent refs would corrupt the output Signed-off-by: Robert Günzler <r@gnzler.io>
| -rw-r--r-- | src/gen.zig | 91 |
1 files changed, 62 insertions, 29 deletions
diff --git a/src/gen.zig b/src/gen.zig index 6c7abcf..79a3ea8 100644 --- a/src/gen.zig +++ b/src/gen.zig @@ -286,8 +286,15 @@ fn inject(allocator: std.mem.Allocator, w: std.io.AnyWriter, srcpath: []const u8 if (std.mem.indexOfPosLinear(u8, chunk, 0, "{")) |start| { if (std.mem.indexOfPosLinear(u8, chunk, start + 1, "}")) |end| { try out_stream.writeAll(chunk[0..start]); - template(allocator, out_stream.any(), chunk[start + 1 .. end]) catch - @panic("Failed to resolve template"); + template(allocator, out_stream.any(), chunk[start + 1 .. end]) catch |err| switch (err) { + error.FileNotFound => { + // log.warn("ref {s} not found", .{chunk[start + 1 .. end]}); + // trim already written chunk and exit templating + chunk = chunk[start..]; + break :templating; + }, + else => @panic("Failed to resolve template"), + }; chunk = chunk[end + 1 ..]; } else break :templating; } else break :templating; @@ -311,57 +318,83 @@ fn template(allocator: std.mem.Allocator, w: std.io.AnyWriter, refname: []const } } +const Page = struct { + arena: std.heap.ArenaAllocator, + ref: []const u8, + name: []const u8, + html: []const u8, + htm: []const u8, + anchor: []const u8, + + fn from_ref(allocator: std.mem.Allocator, refname: []const u8) !Page { + var arena = std.heap.ArenaAllocator.init(allocator); + + const endofref = std.mem.lastIndexOf(u8, refname, "#") orelse refname.len; + const basename = try std.mem.replaceOwned(u8, arena.allocator(), refname[0..endofref], " ", "_"); + const html = try fs.join_path_and_filename(arena.allocator(), &.{Context.params.SITE_PATH}, &.{ basename, ".html" }); + const htm = try fs.join_path_and_filename(arena.allocator(), &.{Context.params.PAGE_PATH}, &.{ basename, ".htm" }); + + try std.fs.cwd().access(htm, .{ .mode = .read_only }); + + return .{ + .arena = arena, + .ref = refname[0..endofref], + .name = basename, + .html = html, + .htm = htm, + .anchor = if (endofref < refname.len) refname[endofref..] else "", + }; + } + + fn deinit(self: Page) void { + self.arena.deinit(); + } +}; + 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 fs.join_path_and_filename(allocator, &.{Context.params.PAGE_PATH}, &.{ basename, ".htm" }); - defer allocator.free(refpathPage); - const refpathSite = try fs.join_path_and_filename(allocator, &.{Context.params.SITE_PATH}, &.{ basename, ".html" }); - defer allocator.free(refpathSite); + const page = try Page.from_ref(allocator, refname); + defer page.deinit(); if (insert_heading) try w.print( \\<h2 id="{[ID]s}"><a href="/{[PATH]s}">{[NAME]s}</a></2> \\ , .{ - .ID = basename, - .NAME = refname, - .PATH = refpathSite, + .ID = page.ref, + .NAME = page.name, + .PATH = page.html, }); - try inject(allocator, w, refpathPage); + try inject(allocator, w, page.htm); // XXX: track ref count? } fn ref(allocator: std.mem.Allocator, w: std.io.AnyWriter, refname: []const u8) anyerror!void { - const endofref = std.mem.lastIndexOf(u8, refname, "#") orelse refname.len; - - const basename = try std.mem.replaceOwned(u8, allocator, refname[0..endofref], " ", "_"); - defer allocator.free(basename); - const refpathSite = try fs.join_path_and_filename(allocator, &.{Context.params.SITE_PATH}, &.{ basename, ".html" }); - defer allocator.free(refpathSite); + const page = try Page.from_ref(allocator, refname); + defer page.deinit(); try w.print( - \\<a href="/{[PATH]s}{[anchor]s}">{[NAME]s}</a> + \\<a href="/{[PATH]s}{[ANCHOR]s}">{[NAME]s}</a> , .{ - .NAME = refname[0..endofref], - .PATH = refpathSite, - .anchor = if (endofref < refname.len) refname[endofref..] else "", + .NAME = page.name, + .PATH = page.html, + .ANCHOR = page.anchor, }); // XXX: track ref count? } fn ref_link(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 fs.join_path_and_filename(allocator, &.{Context.params.SITE_PATH}, &.{ basename, ".html" }); - defer allocator.free(refpathSite); + const page = try Page.from_ref(allocator, refname); + defer page.deinit(); - try w.print("/{s}", .{refpathSite}); + try w.print("/{s}", .{page.html}); } -fn ref_name(_: std.mem.Allocator, w: std.io.AnyWriter, refname: []const u8) anyerror!void { - try w.print("{s}", .{refname}); +fn ref_name(allocator: std.mem.Allocator, w: std.io.AnyWriter, refname: []const u8) anyerror!void { + const page = try Page.from_ref(allocator, refname); + defer page.deinit(); + + try w.print("{s}", .{page.ref}); } |