diff --git a/benchmarks/compiled/friends.zig b/benchmarks/compiled/friends.zig
index f9a9ca2..f1c0216 100644
--- a/benchmarks/compiled/friends.zig
+++ b/benchmarks/compiled/friends.zig
@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
- var buf: std.ArrayListUnmanaged(u8) = .{};
+ var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator);
try buf.appendSlice(allocator, "
friend_name
friend_email
friend_about
tag_value ");
diff --git a/benchmarks/compiled/helpers.zig b/benchmarks/compiled/helpers.zig
index a992b8e..5ed874a 100644
--- a/benchmarks/compiled/helpers.zig
+++ b/benchmarks/compiled/helpers.zig
@@ -4,7 +4,7 @@
const std = @import("std");
/// Append HTML-escaped string to buffer
-pub fn appendEscaped(buf: *std.ArrayListUnmanaged(u8), allocator: std.mem.Allocator, str: []const u8) !void {
+pub fn appendEscaped(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, str: []const u8) !void {
for (str) |c| {
switch (c) {
'&' => try buf.appendSlice(allocator, "&"),
diff --git a/benchmarks/compiled/if-expression.zig b/benchmarks/compiled/if-expression.zig
index 4c76bd7..417a271 100644
--- a/benchmarks/compiled/if-expression.zig
+++ b/benchmarks/compiled/if-expression.zig
@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
- var buf: std.ArrayListUnmanaged(u8) = .{};
+ var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator);
try buf.appendSlice(allocator, "Active
Inactive
");
diff --git a/benchmarks/compiled/projects-escaped.zig b/benchmarks/compiled/projects-escaped.zig
index 66003c3..dcc894b 100644
--- a/benchmarks/compiled/projects-escaped.zig
+++ b/benchmarks/compiled/projects-escaped.zig
@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
- var buf: std.ArrayListUnmanaged(u8) = .{};
+ var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator);
try buf.appendSlice(allocator, "project_name: project_description");
diff --git a/benchmarks/compiled/search-results.zig b/benchmarks/compiled/search-results.zig
index 34a3e3a..59db454 100644
--- a/benchmarks/compiled/search-results.zig
+++ b/benchmarks/compiled/search-results.zig
@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
- var buf: std.ArrayListUnmanaged(u8) = .{};
+ var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator);
try buf.appendSlice(allocator, "result_title
$result_price");
diff --git a/benchmarks/compiled/simple-0.zig b/benchmarks/compiled/simple-0.zig
index a0a104d..b352d96 100644
--- a/benchmarks/compiled/simple-0.zig
+++ b/benchmarks/compiled/simple-0.zig
@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
- var buf: std.ArrayListUnmanaged(u8) = .{};
+ var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator);
try buf.appendSlice(allocator, "Hello World
");
diff --git a/benchmarks/compiled/simple-1.zig b/benchmarks/compiled/simple-1.zig
index bfcc524..14a2168 100644
--- a/benchmarks/compiled/simple-1.zig
+++ b/benchmarks/compiled/simple-1.zig
@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
- var buf: std.ArrayListUnmanaged(u8) = .{};
+ var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator);
try buf.appendSlice(allocator, "My SiteWelcome
This is a simple page
");
diff --git a/benchmarks/compiled/simple-2.zig b/benchmarks/compiled/simple-2.zig
index cd3aa53..5006b3a 100644
--- a/benchmarks/compiled/simple-2.zig
+++ b/benchmarks/compiled/simple-2.zig
@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
- var buf: std.ArrayListUnmanaged(u8) = .{};
+ var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator);
try buf.appendSlice(allocator, "Header
Header2
Header3
Header4
Header5
Header6
");
diff --git a/build.zig.zon b/build.zig.zon
index 1e55c44..8354247 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -1,6 +1,6 @@
.{
.name = .pugz,
- .version = "0.3.7",
+ .version = "0.3.8",
.fingerprint = 0x822db0790e17621d, // Changing this has security and trust implications.
.minimum_zig_version = "0.15.2",
.dependencies = .{},
diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md
index e029853..c767502 100644
--- a/docs/CLAUDE.md
+++ b/docs/CLAUDE.md
@@ -12,6 +12,10 @@ Pugz is a Pug-like HTML template engine written in Zig 0.15.2. It compiles Pug t
- When the user specifies a new rule, update this CLAUDE.md file to include it.
- Code comments are required but must be meaningful, not bloated. Focus on explaining "why" not "what". Avoid obvious comments like "// increment counter" - instead explain complex logic, non-obvious decisions, or tricky edge cases.
- **All documentation files (.md) must be saved to the `docs/` directory.** Do not create .md files in the root directory or examples directories - always place them in `docs/`.
+- **Follow Zig standards for the version specified in `build.zig.zon`** (currently 0.15.2). This includes:
+ - Use `std.ArrayList(T)` instead of the deprecated `std.ArrayListUnmanaged(T)` (renamed in Zig 0.15)
+ - Pass allocator to method calls (`append`, `deinit`, etc.) as per the unmanaged pattern
+ - Check Zig release notes for API changes when updating the minimum Zig version
- **Publish command**: Only when user explicitly says "publish", do the following:
1. Bump the fix version (patch version in build.zig.zon)
2. Git commit with appropriate message
diff --git a/src/codegen.zig b/src/codegen.zig
index e718066..a9d11d3 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -85,7 +85,7 @@ pub const CompilerError = error{
pub const Compiler = struct {
allocator: Allocator,
options: CompilerOptions,
- output: std.ArrayListUnmanaged(u8),
+ output: std.ArrayList(u8),
indent_level: usize = 0,
has_doctype: bool = false,
has_tag: bool = false,
diff --git a/src/compile_tpls.zig b/src/compile_tpls.zig
index f6a3839..6552c29 100644
--- a/src/compile_tpls.zig
+++ b/src/compile_tpls.zig
@@ -233,7 +233,7 @@ fn compileSingleFile(
}
fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 {
- var results: std.ArrayListUnmanaged([]const u8) = .{};
+ var results: std.ArrayList([]const u8) = .{};
errdefer {
for (results.items) |item| allocator.free(item);
results.deinit(allocator);
@@ -243,7 +243,7 @@ fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 {
return results.toOwnedSlice(allocator);
}
-fn findPugFilesRecursive(allocator: mem.Allocator, dir_path: []const u8, results: *std.ArrayListUnmanaged([]const u8)) !void {
+fn findPugFilesRecursive(allocator: mem.Allocator, dir_path: []const u8, results: *std.ArrayList([]const u8)) !void {
var dir = try fs.cwd().openDir(dir_path, .{ .iterate = true });
defer dir.close();
@@ -277,7 +277,7 @@ fn makeTemplateName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
else
path;
- var result: std.ArrayListUnmanaged(u8) = .{};
+ var result: std.ArrayList(u8) = .{};
defer result.deinit(allocator);
for (without_ext) |c| {
@@ -298,7 +298,7 @@ fn makeFlatFileName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
else
path;
- var result: std.ArrayListUnmanaged(u8) = .{};
+ var result: std.ArrayList(u8) = .{};
defer result.deinit(allocator);
for (without_ext) |c| {
@@ -315,14 +315,14 @@ fn makeFlatFileName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
}
fn generateRootZig(allocator: mem.Allocator, output_dir: []const u8, template_map: *std.StringHashMap([]const u8)) !void {
- var output: std.ArrayListUnmanaged(u8) = .{};
+ var output: std.ArrayList(u8) = .{};
defer output.deinit(allocator);
try output.appendSlice(allocator, "// Auto-generated by Pugz build step\n");
try output.appendSlice(allocator, "// This file exports all compiled templates\n\n");
// Sort template names
- var names: std.ArrayListUnmanaged([]const u8) = .{};
+ var names: std.ArrayList([]const u8) = .{};
defer names.deinit(allocator);
var iter = template_map.keyIterator();
diff --git a/src/error.zig b/src/error.zig
index 3138c6f..34e55fd 100644
--- a/src/error.zig
+++ b/src/error.zig
@@ -1,7 +1,7 @@
const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
-const ArrayListUnmanaged = std.ArrayListUnmanaged;
+const ArrayList = std.ArrayList;
// ============================================================================
// Pug Error - Error formatting with source context
@@ -47,7 +47,7 @@ pub const PugError = struct {
/// Format as JSON-like structure for serialization
pub fn toJson(self: *const PugError, allocator: Allocator) ![]const u8 {
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
try result.appendSlice(allocator, "{\"code\":\"");
@@ -76,7 +76,7 @@ pub const PugError = struct {
};
/// Append JSON-escaped string to result
-fn appendJsonEscaped(allocator: Allocator, result: *ArrayListUnmanaged(u8), s: []const u8) !void {
+fn appendJsonEscaped(allocator: Allocator, result: *ArrayList(u8), s: []const u8) !void {
for (s) |c| {
switch (c) {
'"' => try result.appendSlice(allocator, "\\\""),
@@ -150,7 +150,7 @@ fn formatErrorMessage(
) ![]const u8 {
_ = code; // Code is embedded in PugError struct
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
// Header: filename:line:column or Pug:line:column
@@ -231,7 +231,7 @@ fn formatErrorMessage(
/// Split source into lines (handles \n, \r\n, \r)
fn splitLines(allocator: Allocator, src: []const u8) ![][]const u8 {
- var lines: ArrayListUnmanaged([]const u8) = .{};
+ var lines: ArrayList([]const u8) = .{};
errdefer lines.deinit(allocator);
var start: usize = 0;
diff --git a/src/lexer.zig b/src/lexer.zig
index 5640c02..eed3b66 100644
--- a/src/lexer.zig
+++ b/src/lexer.zig
@@ -180,13 +180,13 @@ pub const Token = struct {
};
// ============================================================================
-// Character Parser State (simplified) - Zig 0.15 style with ArrayListUnmanaged
+// Character Parser State (simplified) - Zig 0.15 style with ArrayList
// ============================================================================
const BracketType = enum { paren, brace, bracket };
const CharParserState = struct {
- nesting_stack: std.ArrayListUnmanaged(BracketType) = .{},
+ nesting_stack: std.ArrayList(BracketType) = .{},
in_string: bool = false,
string_char: ?u8 = null,
in_template: bool = false,
@@ -320,7 +320,7 @@ const BracketExpressionResult = struct {
};
// ============================================================================
-// Lexer - Zig 0.15 style with ArrayListUnmanaged
+// Lexer - Zig 0.15 style with ArrayList
// ============================================================================
pub const Lexer = struct {
@@ -332,10 +332,10 @@ pub const Lexer = struct {
interpolated: bool,
lineno: usize,
colno: usize,
- indent_stack: std.ArrayListUnmanaged(usize) = .{},
+ indent_stack: std.ArrayList(usize) = .{},
indent_re_type: ?IndentType = null,
interpolation_allowed: bool,
- tokens: std.ArrayListUnmanaged(Token) = .{},
+ tokens: std.ArrayList(Token) = .{},
ended: bool,
last_error: ?LexerError = null,
@@ -359,7 +359,7 @@ pub const Lexer = struct {
}
// Normalize line endings
- var normalized: std.ArrayListUnmanaged(u8) = .{};
+ var normalized: std.ArrayList(u8) = .{};
errdefer normalized.deinit(allocator);
var i: usize = 0;
@@ -378,7 +378,7 @@ pub const Lexer = struct {
}
}
- var indent_stack: std.ArrayListUnmanaged(usize) = .{};
+ var indent_stack: std.ArrayList(usize) = .{};
try indent_stack.append(allocator, 0);
const input_slice = try normalized.toOwnedSlice(allocator);
@@ -1349,7 +1349,7 @@ pub const Lexer = struct {
/// Validates that brackets in an expression are balanced
fn validateExpressionBrackets(self: *Lexer, expr: []const u8) bool {
- var bracket_stack = std.ArrayListUnmanaged(u8){};
+ var bracket_stack = std.ArrayList(u8){};
defer bracket_stack.deinit(self.allocator);
var in_string: u8 = 0;
@@ -2309,8 +2309,8 @@ pub const Lexer = struct {
self.tokens.append(self.allocator, start_token) catch return false;
var string_ptr: usize = 0;
- var tokens_list: std.ArrayListUnmanaged([]const u8) = .{};
- var token_indent_list: std.ArrayListUnmanaged(bool) = .{};
+ var tokens_list: std.ArrayList([]const u8) = .{};
+ var token_indent_list: std.ArrayList(bool) = .{};
defer tokens_list.deinit(self.allocator);
defer token_indent_list.deinit(self.allocator);
@@ -2451,7 +2451,7 @@ pub const Lexer = struct {
var in_string: u8 = 0;
// Track bracket stack - inside #[...] you can have (...) and {...} for attrs/code
- var bracket_stack = std.ArrayListUnmanaged(u8){};
+ var bracket_stack = std.ArrayList(u8){};
defer bracket_stack.deinit(self.allocator);
bracket_stack.append(self.allocator, '[') catch return;
diff --git a/src/linker.zig b/src/linker.zig
index 969d344..b0cdd55 100644
--- a/src/linker.zig
+++ b/src/linker.zig
@@ -102,10 +102,10 @@ pub fn link(allocator: Allocator, ast: *Node) LinkerError!LinkerResult {
// Handle extends
if (extends_node) |ext_node| {
// Get mixins and expected blocks from current template
- var mixins = std.ArrayListUnmanaged(*Node){};
+ var mixins = std.ArrayList(*Node){};
defer mixins.deinit(allocator);
- var expected_blocks = std.ArrayListUnmanaged(*Node){};
+ var expected_blocks = std.ArrayList(*Node){};
defer expected_blocks.deinit(allocator);
try collectMixinsAndBlocks(allocator, result.ast, &mixins, &expected_blocks);
@@ -178,8 +178,8 @@ fn findDeclaredBlocks(allocator: Allocator, ast: *Node) LinkerError!BlockDefinit
fn collectMixinsAndBlocks(
allocator: Allocator,
ast: *Node,
- mixins: *std.ArrayListUnmanaged(*Node),
- expected_blocks: *std.ArrayListUnmanaged(*Node),
+ mixins: *std.ArrayList(*Node),
+ expected_blocks: *std.ArrayList(*Node),
) LinkerError!void {
for (ast.nodes.items) |node| {
switch (node.type) {
diff --git a/src/load.zig b/src/load.zig
index ddd3c9a..d5ea0d8 100644
--- a/src/load.zig
+++ b/src/load.zig
@@ -357,7 +357,7 @@ pub fn pathJoin(allocator: Allocator, base: []const u8, relative: []const u8) ![
const base_dir = dirname(base);
// Handle .. and . components
- var result = std.ArrayListUnmanaged(u8){};
+ var result = std.ArrayList(u8){};
errdefer result.deinit(allocator);
try result.appendSlice(allocator, base_dir);
diff --git a/src/mixin.zig b/src/mixin.zig
index 69d7d46..46c2dfa 100644
--- a/src/mixin.zig
+++ b/src/mixin.zig
@@ -289,7 +289,7 @@ fn substituteArgs(
}
// Perform substitution
- var result = std.ArrayListUnmanaged(u8){};
+ var result = std.ArrayList(u8){};
errdefer result.deinit(allocator);
var i: usize = 0;
@@ -335,7 +335,7 @@ fn evaluateStringConcat(allocator: Allocator, expr: []const u8) ![]const u8 {
// Check if there's a + operator (string concat)
_ = mem.indexOf(u8, expr, " + ") orelse return expr;
- var result = std.ArrayListUnmanaged(u8){};
+ var result = std.ArrayList(u8){};
errdefer result.deinit(allocator);
var remaining = expr;
@@ -386,7 +386,7 @@ fn bindArguments(
bindings: *std.StringHashMapUnmanaged([]const u8),
) MixinError!void {
// Parse parameter names from definition: "text, type" or "text, type='primary'"
- var param_names = std.ArrayListUnmanaged([]const u8){};
+ var param_names = std.ArrayList([]const u8){};
defer param_names.deinit(allocator);
var param_iter = mem.splitSequence(u8, params, ",");
@@ -409,7 +409,7 @@ fn bindArguments(
}
// Parse argument values from call: "'Click', 'primary'" or "text='Click'"
- var arg_values = std.ArrayListUnmanaged([]const u8){};
+ var arg_values = std.ArrayList([]const u8){};
defer arg_values.deinit(allocator);
// Simple argument parsing - split by comma but respect quotes
@@ -589,12 +589,6 @@ test "bindArguments - with default value in param" {
// This is how it appears: params have default, args are the call args
try bindArguments(allocator, "text, type=\"primary\"", "\"Click Me\", \"primary\"", &bindings);
- std.debug.print("\nBindings:\n", .{});
- var iter = bindings.iterator();
- while (iter.next()) |entry| {
- std.debug.print(" {s} = '{s}'\n", .{ entry.key_ptr.*, entry.value_ptr.* });
- }
-
try std.testing.expectEqualStrings("Click Me", bindings.get("text").?);
try std.testing.expectEqualStrings("primary", bindings.get("type").?);
}
diff --git a/src/parser.zig b/src/parser.zig
index 4e54308..d3dce91 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -110,7 +110,7 @@ pub const Node = struct {
filename: ?[]const u8 = null,
// Block fields
- nodes: std.ArrayListUnmanaged(*Node) = .{},
+ nodes: std.ArrayList(*Node) = .{},
// NamedBlock additional fields
name: ?[]const u8 = null, // Also used for Tag, Mixin, Filter
@@ -118,8 +118,8 @@ pub const Node = struct {
// Tag fields
self_closing: bool = false,
- attrs: std.ArrayListUnmanaged(Attribute) = .{},
- attribute_blocks: std.ArrayListUnmanaged(AttributeBlock) = .{},
+ attrs: std.ArrayList(Attribute) = .{},
+ attribute_blocks: std.ArrayList(AttributeBlock) = .{},
is_inline: bool = false,
text_only: bool = false,
self_closing_allowed: bool = false,
@@ -150,7 +150,7 @@ pub const Node = struct {
file: ?FileReference = null,
// Include fields
- filters: std.ArrayListUnmanaged(*Node) = .{},
+ filters: std.ArrayList(*Node) = .{},
// InterpolatedTag fields
expr: ?[]const u8 = null,
@@ -247,7 +247,7 @@ pub const Parser = struct {
allocator: Allocator,
tokens: []const Token,
pos: usize = 0,
- deferred: std.ArrayListUnmanaged(Token) = .{},
+ deferred: std.ArrayList(Token) = .{},
filename: ?[]const u8 = null,
src: ?[]const u8 = null,
in_mixin: usize = 0,
@@ -475,7 +475,7 @@ pub const Parser = struct {
fn parseText(self: *Parser, allow_block: bool) !*Node {
const lineno = self.peek().loc.start.line;
- var tags = std.ArrayListUnmanaged(*Node){};
+ var tags = std.ArrayList(*Node){};
defer tags.deinit(self.allocator);
while (true) {
@@ -548,8 +548,8 @@ pub const Parser = struct {
}
}
- fn parseTextHtml(self: *Parser) !std.ArrayListUnmanaged(*Node) {
- var nodes = std.ArrayListUnmanaged(*Node){};
+ fn parseTextHtml(self: *Parser) !std.ArrayList(*Node) {
+ var nodes = std.ArrayList(*Node){};
var current_node: ?*Node = null;
while (true) {
@@ -922,7 +922,7 @@ pub const Parser = struct {
const line = tok.loc.start.line;
const column = tok.loc.start.column;
- var text = std.ArrayListUnmanaged(u8){};
+ var text = std.ArrayList(u8){};
defer text.deinit(self.allocator);
if (self.peek().type == .start_pipeless_text) {
@@ -1095,7 +1095,7 @@ pub const Parser = struct {
fn parseIncludeFilter(self: *Parser) !*Node {
const tok = try self.expect(.filter);
- var filter_attrs = std.ArrayListUnmanaged(Attribute){};
+ var filter_attrs = std.ArrayList(Attribute){};
if (self.peek().type == .start_attributes) {
filter_attrs = try self.attrs(null);
@@ -1115,7 +1115,7 @@ pub const Parser = struct {
fn parseFilter(self: *Parser) !*Node {
const tok = try self.expect(.filter);
- var filter_attrs = std.ArrayListUnmanaged(Attribute){};
+ var filter_attrs = std.ArrayList(Attribute){};
if (self.peek().type == .start_attributes) {
filter_attrs = try self.attrs(null);
@@ -1483,11 +1483,11 @@ pub const Parser = struct {
fn tag_(self: *Parser, tag: *Node, self_closing_allowed: bool) !void {
var seen_attrs = false;
- var attribute_names = std.ArrayListUnmanaged([]const u8){};
+ var attribute_names = std.ArrayList([]const u8){};
defer attribute_names.deinit(self.allocator);
// Collect class values to merge into single attribute
- var class_values = std.ArrayListUnmanaged([]const u8){};
+ var class_values = std.ArrayList([]const u8){};
defer class_values.deinit(self.allocator);
var class_line: usize = 0;
var class_column: usize = 0;
@@ -1689,10 +1689,10 @@ pub const Parser = struct {
}
}
- fn attrs(self: *Parser, attribute_names: ?*std.ArrayListUnmanaged([]const u8)) !std.ArrayListUnmanaged(Attribute) {
+ fn attrs(self: *Parser, attribute_names: ?*std.ArrayList([]const u8)) !std.ArrayList(Attribute) {
_ = try self.expect(.start_attributes);
- var result = std.ArrayListUnmanaged(Attribute){};
+ var result = std.ArrayList(Attribute){};
var tok = self.advance();
while (tok.type == .attribute) {
diff --git a/src/runtime.zig b/src/runtime.zig
index a2d001d..84a73a7 100644
--- a/src/runtime.zig
+++ b/src/runtime.zig
@@ -1,7 +1,7 @@
const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
-const ArrayListUnmanaged = std.ArrayListUnmanaged;
+const ArrayList = std.ArrayList;
// ============================================================================
// Pug Runtime - HTML generation utilities
@@ -45,7 +45,7 @@ pub fn escape(allocator: Allocator, html: []const u8) ![]const u8 {
return try allocator.dupe(u8, html);
}
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
for (html) |c| {
@@ -84,7 +84,7 @@ pub fn style(allocator: Allocator, val: StyleValue) ![]const u8 {
return try allocator.dupe(u8, s);
},
.object => |props| {
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
for (props) |prop| {
@@ -111,7 +111,7 @@ pub const AttrValue = union(enum) {
/// Returns empty string for false/null values.
/// For true values, returns terse form " key" or full form " key="key"".
pub fn attr(allocator: Allocator, key: []const u8, val: AttrValue, escaped: bool, terse: bool) ![]const u8 {
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
try appendAttr(allocator, &result, key, val, escaped, terse);
if (result.items.len == 0) {
@@ -122,7 +122,7 @@ pub fn attr(allocator: Allocator, key: []const u8, val: AttrValue, escaped: bool
/// Append attribute directly to output buffer - avoids intermediate allocations
/// This is the preferred method for rendering attributes in hot paths
-pub fn appendAttr(allocator: Allocator, output: *ArrayListUnmanaged(u8), key: []const u8, val: AttrValue, escaped: bool, terse: bool) !void {
+pub fn appendAttr(allocator: Allocator, output: *ArrayList(u8), key: []const u8, val: AttrValue, escaped: bool, terse: bool) !void {
switch (val) {
.none => return,
.boolean => |b| {
@@ -186,7 +186,7 @@ pub const ClassCondition = struct {
/// Arrays are flattened, objects include keys with truthy values.
/// Optimized to minimize allocations by writing directly to result buffer.
pub fn classes(allocator: Allocator, val: ClassValue, escaping: ?[]const bool) ![]const u8 {
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
try classesInternal(allocator, val, escaping, &result, 0);
@@ -204,7 +204,7 @@ fn classesInternal(
allocator: Allocator,
val: ClassValue,
escaping: ?[]const bool,
- result: *ArrayListUnmanaged(u8),
+ result: *ArrayList(u8),
depth: usize,
) !void {
switch (val) {
@@ -236,7 +236,7 @@ fn classesInternal(
const had_content = start_len > 0;
// Temporarily collect the class string
- var temp: ArrayListUnmanaged(u8) = .{};
+ var temp: ArrayList(u8) = .{};
defer temp.deinit(allocator);
try classesInternal(allocator, item, null, &temp, depth + 1);
@@ -256,7 +256,7 @@ fn classesInternal(
/// Append escaped HTML directly to result buffer (avoids intermediate allocation)
/// Public for use by codegen and other modules
-pub fn appendEscaped(allocator: Allocator, result: *ArrayListUnmanaged(u8), html: []const u8) !void {
+pub fn appendEscaped(allocator: Allocator, result: *ArrayList(u8), html: []const u8) !void {
for (html) |c| {
if (escapeChar(c)) |escaped| {
try result.appendSlice(allocator, escaped);
@@ -350,7 +350,7 @@ pub fn isHtmlEntity(str: []const u8) bool {
/// Escape for text content - escapes < > & (NOT quotes)
/// Preserves existing HTML entities like ’ or &
/// Shared across codegen.zig and template.zig.
-pub fn appendTextEscaped(allocator: Allocator, output: *ArrayListUnmanaged(u8), str: []const u8) Allocator.Error!void {
+pub fn appendTextEscaped(allocator: Allocator, output: *ArrayList(u8), str: []const u8) Allocator.Error!void {
var i: usize = 0;
while (i < str.len) {
const c = str[i];
@@ -396,7 +396,7 @@ pub const AttrEntry = struct {
/// Render multiple attributes.
/// Class attributes are processed specially and placed first.
pub fn attrs(allocator: Allocator, entries: []const AttrEntry, terse: bool) ![]const u8 {
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
// First pass: find and render class attribute
@@ -459,7 +459,7 @@ pub const MergedValue = struct {
key: []const u8,
value: MergeValue,
allocator: Allocator,
- owned_strings: ArrayListUnmanaged([]const u8),
+ owned_strings: ArrayList([]const u8),
pub fn deinit(self: *MergedValue) void {
for (self.owned_strings.items) |s| {
@@ -474,7 +474,7 @@ fn ensureTrailingSemicolon(allocator: Allocator, s: []const u8) ![]const u8 {
if (s.len == 0) return try allocator.dupe(u8, "");
if (s[s.len - 1] == ';') return try allocator.dupe(u8, s);
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
try result.appendSlice(allocator, s);
try result.append(allocator, ';');
@@ -495,9 +495,9 @@ fn styleToString(allocator: Allocator, val: StyleValue) ![]const u8 {
/// Merged attributes result with O(1) lookups for class/style
pub const MergedAttrs = struct {
allocator: Allocator,
- entries: ArrayListUnmanaged(MergedAttrEntry),
- owned_strings: ArrayListUnmanaged([]const u8),
- owned_class_arrays: ArrayListUnmanaged([][]const u8),
+ entries: ArrayList(MergedAttrEntry),
+ owned_strings: ArrayList([]const u8),
+ owned_class_arrays: ArrayList([][]const u8),
// O(1) index tracking for special keys
class_idx: ?usize = null,
style_idx: ?usize = null,
@@ -751,7 +751,7 @@ fn mergeStyleValue(result: *MergedAttrs, idx: usize, value: MergedAttrValue) !vo
const s2 = try ensureTrailingSemicolon(allocator, s);
defer allocator.free(s2);
- var combined: ArrayListUnmanaged(u8) = .{};
+ var combined: ArrayList(u8) = .{};
errdefer combined.deinit(allocator);
try combined.appendSlice(allocator, s1);
try combined.appendSlice(allocator, s2);
@@ -842,7 +842,7 @@ pub const PugError = struct {
};
fn formatErrorMessage(allocator: Allocator, err_message: []const u8, filename: ?[]const u8, line: usize, src: []const u8) ![]const u8 {
- var result: ArrayListUnmanaged(u8) = .{};
+ var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator);
// Add filename and line
diff --git a/src/strip_comments.zig b/src/strip_comments.zig
index 0d44e0c..2348e1e 100644
--- a/src/strip_comments.zig
+++ b/src/strip_comments.zig
@@ -44,7 +44,7 @@ pub const StripCommentsError = error{
// ============================================================================
pub const StripCommentsResult = struct {
- tokens: std.ArrayListUnmanaged(Token),
+ tokens: std.ArrayList(Token),
err: ?PugError = null,
pub fn deinit(self: *StripCommentsResult, allocator: Allocator) void {
diff --git a/src/template.zig b/src/template.zig
index bfc0a83..ac7ccce 100644
--- a/src/template.zig
+++ b/src/template.zig
@@ -97,7 +97,7 @@ pub fn renderWithData(allocator: Allocator, source: []const u8, data: anytype) !
/// Render a pre-parsed AST with data. Use this for better performance when
/// rendering the same template multiple times - parse once, render many.
pub fn renderAst(allocator: Allocator, ast: *Node, data: anytype) ![]const u8 {
- var output = std.ArrayListUnmanaged(u8){};
+ var output = std.ArrayList(u8){};
errdefer output.deinit(allocator);
// Detect doctype to set terse mode
@@ -122,7 +122,7 @@ pub fn renderAstWithMixins(allocator: Allocator, ast: *Node, data: anytype, regi
/// Render a pre-parsed AST with data, mixin registry, and render options.
pub fn renderAstWithMixinsAndOptions(allocator: Allocator, ast: *Node, data: anytype, registry: *const MixinRegistry, options: RenderOptions) ![]const u8 {
- var output = std.ArrayListUnmanaged(u8){};
+ var output = std.ArrayList(u8){};
errdefer output.deinit(allocator);
// Detect doctype to set terse mode
@@ -213,14 +213,14 @@ fn detectDoctype(node: *Node, ctx: *RenderContext) void {
const whitespace_sensitive_tags = runtime.whitespace_sensitive_tags;
/// Write indentation (two spaces per level)
-fn writeIndent(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), level: u32) Allocator.Error!void {
+fn writeIndent(allocator: Allocator, output: *std.ArrayList(u8), level: u32) Allocator.Error!void {
var i: u32 = 0;
while (i < level) : (i += 1) {
try output.appendSlice(allocator, " ");
}
}
-fn renderNode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
+fn renderNode(allocator: Allocator, output: *std.ArrayList(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
switch (node.type) {
.Block, .NamedBlock => {
for (node.nodes.items) |child| {
@@ -251,7 +251,7 @@ fn renderNode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *
}
}
-fn renderTag(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), tag: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
+fn renderTag(allocator: Allocator, output: *std.ArrayList(u8), tag: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
const name = tag.name orelse "div";
const is_whitespace_sensitive = whitespace_sensitive_tags.has(name);
@@ -393,13 +393,13 @@ fn evaluateAttrValue(allocator: Allocator, val: ?[]const u8, data: anytype) !run
return .{ .string = v };
}
-fn renderText(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), text: *Node, data: anytype) Allocator.Error!void {
+fn renderText(allocator: Allocator, output: *std.ArrayList(u8), text: *Node, data: anytype) Allocator.Error!void {
if (text.val) |val| {
try processInterpolation(allocator, output, val, false, data);
}
}
-fn renderCode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), code: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
+fn renderCode(allocator: Allocator, output: *std.ArrayList(u8), code: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
if (code.buffer) {
if (code.val) |val| {
// Check if it's a string literal (quoted)
@@ -441,7 +441,7 @@ fn renderCode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), code: *
}
/// Render mixin definition or call
-fn renderMixin(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
+fn renderMixin(allocator: Allocator, output: *std.ArrayList(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
// Mixin definitions are skipped (only mixin calls render)
if (!node.call) return;
@@ -494,7 +494,7 @@ fn bindMixinArguments(
bindings: *std.StringHashMapUnmanaged([]const u8),
) !void {
// Parse parameter names from definition: "text, type" or "text, type='primary'"
- var param_names = std.ArrayListUnmanaged([]const u8){};
+ var param_names = std.ArrayList([]const u8){};
defer param_names.deinit(allocator);
var param_iter = std.mem.splitSequence(u8, params, ",");
@@ -517,7 +517,7 @@ fn bindMixinArguments(
}
// Parse argument values from call: "'Click', 'primary'" or "text='Click'"
- var arg_values = std.ArrayListUnmanaged([]const u8){};
+ var arg_values = std.ArrayList([]const u8){};
defer arg_values.deinit(allocator);
// Simple argument parsing - split by comma but respect quotes
@@ -572,7 +572,7 @@ fn stripQuotes(val: []const u8) []const u8 {
return val;
}
-fn renderEach(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), each: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
+fn renderEach(allocator: Allocator, output: *std.ArrayList(u8), each: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
const collection_name = each.obj orelse return;
const item_name = each.val orelse "item";
_ = item_name;
@@ -623,7 +623,7 @@ fn renderEach(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), each: *
}
}
-fn renderNodeWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void {
+fn renderNodeWithItem(allocator: Allocator, output: *std.ArrayList(u8), node: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void {
switch (node.type) {
.Block, .NamedBlock => {
for (node.nodes.items) |child| {
@@ -649,7 +649,7 @@ fn renderNodeWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8),
}
}
-fn renderTagWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), tag: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void {
+fn renderTagWithItem(allocator: Allocator, output: *std.ArrayList(u8), tag: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void {
const name = tag.name orelse "div";
try output.appendSlice(allocator, "<");
@@ -698,14 +698,14 @@ fn renderTagWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8),
}
}
-fn renderTextWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), text: *Node, item: []const u8) Allocator.Error!void {
+fn renderTextWithItem(allocator: Allocator, output: *std.ArrayList(u8), text: *Node, item: []const u8) Allocator.Error!void {
if (text.val) |val| {
try runtime.appendEscaped(allocator, output, val);
_ = item;
}
}
-fn processInterpolationWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), text: []const u8, escape: bool, data: anytype, item: []const u8) Allocator.Error!void {
+fn processInterpolationWithItem(allocator: Allocator, output: *std.ArrayList(u8), text: []const u8, escape: bool, data: anytype, item: []const u8) Allocator.Error!void {
_ = data;
var i: usize = 0;
while (i < text.len) {
@@ -740,7 +740,7 @@ fn processInterpolationWithItem(allocator: Allocator, output: *std.ArrayListUnma
}
}
-fn renderComment(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), comment: *Node) Allocator.Error!void {
+fn renderComment(allocator: Allocator, output: *std.ArrayList(u8), comment: *Node) Allocator.Error!void {
if (!comment.buffer) return;
try output.appendSlice(allocator, "");
}
-fn renderBlockComment(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), comment: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
+fn renderBlockComment(allocator: Allocator, output: *std.ArrayList(u8), comment: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
if (!comment.buffer) return;
try output.appendSlice(allocator, "