aboutsummaryrefslogtreecommitdiff
path: root/src/eval/html/Void.zig
diff options
context:
space:
mode:
authorAnhgelus Morhtuuzh <william@herges.fr>2026-04-27 17:11:08 +0200
committerAnhgelus Morhtuuzh <william@herges.fr>2026-04-27 17:11:08 +0200
commitef5c0341ca15f6862294802103b02992b29609e8 (patch)
tree9b5a274a77d44053b8e53d249b2d59b754c9f673 /src/eval/html/Void.zig
parent9f1a0bf3b0437770a7b62fd28a8748908c38dac4 (diff)
style(html): split elements in multiple files
Diffstat (limited to 'src/eval/html/Void.zig')
-rw-r--r--src/eval/html/Void.zig104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/eval/html/Void.zig b/src/eval/html/Void.zig
new file mode 100644
index 0000000..58550f4
--- /dev/null
+++ b/src/eval/html/Void.zig
@@ -0,0 +1,104 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const List = std.ArrayList;
+const html = @import("html.zig");
+const Element = @import("Element.zig");
+const Error = Element.Error;
+
+alloc: Allocator,
+tag: []const u8,
+attributes: std.StringArrayHashMap([]const u8),
+class_list: std.BufSet,
+
+pub const Self = @This();
+
+pub fn init(alloc: Allocator, tag: []const u8) Error!*Self {
+ const v = try alloc.create(Self);
+ v.* = .{
+ .alloc = alloc,
+ .tag = tag,
+ .attributes = .init(alloc),
+ .class_list = .init(alloc),
+ };
+ return v;
+}
+
+pub fn element(self: *Self) Element {
+ return .{ .vtable = .{ .render = Self.render }, .ptr = self };
+}
+
+pub fn setAttribute(self: *Self, k: []const u8, v: []const u8) Error!void {
+ try self.attributes.put(try self.alloc.dupe(u8, k), try self.alloc.dupe(u8, v));
+}
+
+pub fn removeAttribute(self: *Self, k: []const u8) void {
+ _ = self.attributes.orderedRemove(k);
+}
+
+pub fn hasAttribute(self: *Self, k: []const u8) bool {
+ return self.attributes.contains(k);
+}
+
+pub fn appendClass(self: *Self, v: []const u8) Error!void {
+ try self.class_list.insert(v);
+}
+
+pub fn hasClass(self: *Self, v: []const u8) bool {
+ return self.class_list.contains(v);
+}
+
+pub fn removeClass(self: *Self, v: []const u8) void {
+ self.class_list.remove(v);
+}
+
+fn render(context: *anyopaque, alloc: Allocator) Error![]const u8 {
+ const self: *Self = @ptrCast(@alignCast(context));
+ const attr = try renderAttribute(alloc, &self.attributes, &self.class_list);
+ defer if (attr) |it| alloc.free(it);
+ var acc = try List(u8).initCapacity(alloc, self.tag.len + 2);
+ errdefer acc.deinit(alloc);
+ try acc.append(alloc, '<');
+ try acc.appendSlice(alloc, self.tag);
+ if (attr) |it| try acc.appendSlice(alloc, it);
+ try acc.append(alloc, '>');
+ return acc.toOwnedSlice(alloc);
+}
+
+fn renderAttribute(alloc: Allocator, attributes: *std.StringArrayHashMap([]const u8), class_list: *std.BufSet) Error!?[]const u8 {
+ const class = try renderClass(alloc, class_list);
+ defer if (class) |it| {
+ _ = attributes.orderedRemove("class");
+ alloc.free(it);
+ };
+ if (class) |it| try attributes.put("class", it);
+ var iter = attributes.iterator();
+ if (iter.len == 0) return null;
+ var acc = try List(u8).initCapacity(alloc, iter.len);
+ errdefer acc.deinit(alloc);
+ try acc.append(alloc, ' ');
+ var i: usize = 0;
+ while (iter.next()) |it| : (i += 1) {
+ try acc.appendSlice(alloc, it.key_ptr.*);
+ try acc.appendSlice(alloc, "=\"");
+ const escape = try html.escape(alloc, it.value_ptr.*);
+ defer alloc.free(escape);
+ try acc.appendSlice(alloc, escape);
+ try acc.append(alloc, '"');
+ if (i < iter.len - 1) try acc.append(alloc, ' ');
+ }
+ return try acc.toOwnedSlice(alloc);
+}
+
+fn renderClass(alloc: Allocator, class_list: *std.BufSet) Error!?[]const u8 {
+ const n = class_list.count();
+ if (n == 0) return null;
+ var acc = try List(u8).initCapacity(alloc, n);
+ errdefer acc.deinit(alloc);
+ var iter = class_list.iterator();
+ var i: usize = 0;
+ while (iter.next()) |it| : (i += 1) {
+ try acc.appendSlice(alloc, it.*);
+ if (i < n - 1) try acc.append(alloc, ' ');
+ }
+ return try acc.toOwnedSlice(alloc);
+}