Something went wrong. Try again.
Markup language that is simple to read, to write and to parse.
zig parser html language markup typst
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115const std = @import("std");const Allocator = std.mem.Allocator;const List = std.ArrayList;const html = @import("html.zig");const Element = @import("Element.zig");const Node = Element.Node;const Error = Element.Error;
alloc: Allocator,tag: []const u8,attributes: std.array_hash_map.String([]const u8),class_list: std.BufSet,node: Node = .{ .ptr = undefined, .vtable = .{ .element = fromNode },},
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 = .empty, .class_list = .init(alloc), }; v.node.ptr = v; return v;}
pub fn element(self: *Self) Element { return Element.Wrapper(Self, render).init(self);}
pub fn setAttribute(self: *Self, k: []const u8, v: []const u8) Error!void { try self.attributes.put(self.alloc, try self.alloc.dupe(u8, k), try html.escape(self.alloc, 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(try html.escape(self.alloc, 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 fromNode(context: *anyopaque) Element { const self: *Self = @ptrCast(@alignCast(context)); return self.element();}
fn render(self: *Self, alloc: Allocator) Error![]const u8 { 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.array_hash_map.String([]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(alloc, "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);}