]> git.frustrated-labs.net Git - frustrated-functor.dev.git/commitdiff
implement template replacement
authorAlexander Goussas <[email protected]>
Sat, 18 Apr 2026 16:06:03 +0000 (11:06 -0500)
committerAlexander Goussas <[email protected]>
Sat, 18 Apr 2026 16:06:03 +0000 (11:06 -0500)
bin/blog-processor/src/html_formatter.zig
bin/blog-processor/src/root.zig
bin/blog-processor/src/string_utils.zig [new file with mode: 0644]

index 71b03843b89e1c106e59f72544fe2b96e5c964c7..99644ba8255c5718ab3bcac2fe6f30ba7515c30f 100644 (file)
@@ -1,5 +1,6 @@
 const std = @import("std");
 const md = @import("./markdown_parser.zig");
+const strings = @import("./string_utils.zig");
 
 const stdC = @cImport({
     @cInclude("stdio.h");
@@ -42,6 +43,9 @@ const HtmlFormatter = struct {
         }
 
         if (self.opts.template) |t| {
+            const replaced = try strings.replace(alloc, t, "{body}", self.buffer.items);
+            self.buffer.deinit(alloc);
+            self.buffer = std.ArrayList(u8).fromOwnedSlice(replaced);
         }
 
         return self.buffer.items;
@@ -154,7 +158,7 @@ test "can format document with more than one element" {
 test "can format empty document with template" {
     const alloc = std.testing.allocator;
     const template = 
-        \\<body>%s</body>
+        \\<body>{body}</body>
         ;
     var formatter = HtmlFormatter.init(.{ .template = template });
     defer formatter.deinit(alloc);
@@ -169,7 +173,7 @@ test "can format empty document with template" {
 test "can format empty non-document with template" {
     const alloc = std.testing.allocator;
     const template = 
-        \\<body>%s</body>
+        \\<body>{body}</body>
         ;
     var formatter = HtmlFormatter.init(.{ .template = template });
     defer formatter.deinit(alloc);
index 72e7c52539c8d964bc0c30398c5f91cb6882ba1b..49eabb0a2b7ba1b3686048960e2d073ee6858069 100644 (file)
@@ -6,4 +6,5 @@
 test "all tests" {
     _ = @import("./markdown_parser.zig");
     _ = @import("./html_formatter.zig");
+    _ = @import("./string_utils.zig");
 }
diff --git a/bin/blog-processor/src/string_utils.zig b/bin/blog-processor/src/string_utils.zig
new file mode 100644 (file)
index 0000000..70a2c15
--- /dev/null
@@ -0,0 +1,64 @@
+const std = @import("std");
+
+/// Replace target in s by replacement.
+/// Return an owned buffer.
+pub fn replace(alloc: std.mem.Allocator, s: []const u8, target: []const u8, replacement: []const u8) ![]u8 {
+    var buffer = try std.ArrayList(u8).initCapacity(alloc, s.len);
+
+    var i: usize = 0;
+    while (i < s.len) {
+        var j: usize = i;
+        const matched = while (j < s.len and j - i < target.len) {
+            if (s[j] != target[j - i]) break false;
+            j += 1;
+        } else true;
+        if (matched) {
+            try buffer.appendSlice(alloc, replacement);
+            i = j;
+        } else {
+            try buffer.append(alloc, s[i]);
+            i += 1;
+        }
+    }
+
+    return try buffer.toOwnedSlice(alloc);
+}
+
+test "replace can replace single instance of target in string" {
+    var alloc = std.testing.allocator;
+
+    const s = "This is a {target}";
+    const target = "{target}";
+    const replacement = "test";
+
+    const result = try replace(alloc, s, target, replacement);
+    defer alloc.free(result);
+
+    try std.testing.expectEqualStrings("This is a test", result);
+}
+
+test "replace can replace multiple instances of target in string" {
+    var alloc = std.testing.allocator;
+
+    const s = "This is a {target} to {target} {target}s";
+    const target = "{target}";
+    const replacement = "test";
+
+    const result = try replace(alloc, s, target, replacement);
+    defer alloc.free(result);
+
+    try std.testing.expectEqualStrings("This is a test to test tests", result);
+}
+
+test "replace when replacing target with target is a no-op" {
+    var alloc = std.testing.allocator;
+
+    const s = "This is a {target} to {target} {target}s";
+    const target = "{target}";
+    const replacement = "{target}";
+
+    const result = try replace(alloc, s, target, replacement);
+    defer alloc.free(result);
+
+    try std.testing.expectEqualStrings(s, result);
+}