From 9b47dd2028deb45324ca19d909d0cee69f51f1b9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 27 Aug 2025 22:47:42 -0700 Subject: [PATCH] update langref and docs to avoid GenericWriter --- lib/docs/wasm/Decl.zig | 9 ++--- lib/docs/wasm/html_render.zig | 18 +++++----- lib/docs/wasm/main.zig | 54 ++++++++++++++++------------- lib/docs/wasm/markdown/renderer.zig | 31 ++++++++--------- tools/docgen.zig | 42 +++++++++++----------- tools/doctest.zig | 36 +++++++++---------- 6 files changed, 97 insertions(+), 93 deletions(-) diff --git a/lib/docs/wasm/Decl.zig b/lib/docs/wasm/Decl.zig index ba1a7b455a..79a55294d2 100644 --- a/lib/docs/wasm/Decl.zig +++ b/lib/docs/wasm/Decl.zig @@ -6,6 +6,7 @@ const gpa = std.heap.wasm_allocator; const assert = std.debug.assert; const log = std.log; const Oom = error{OutOfMemory}; +const ArrayList = std.ArrayList; ast_node: Ast.Node.Index, file: Walk.File.Index, @@ -189,7 +190,7 @@ pub fn lookup(decl: *const Decl, name: []const u8) ?Decl.Index { } /// Appends the fully qualified name to `out`. -pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void { +pub fn fqn(decl: *const Decl, out: *ArrayList(u8)) Oom!void { try decl.append_path(out); if (decl.parent != .none) { try append_parent_ns(out, decl.parent); @@ -199,12 +200,12 @@ pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void { } } -pub fn reset_with_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void { +pub fn reset_with_path(decl: *const Decl, list: *ArrayList(u8)) Oom!void { list.clearRetainingCapacity(); try append_path(decl, list); } -pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void { +pub fn append_path(decl: *const Decl, list: *ArrayList(u8)) Oom!void { const start = list.items.len; // Prefer the module name alias. for (Walk.modules.keys(), Walk.modules.values()) |pkg_name, pkg_file| { @@ -230,7 +231,7 @@ pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!voi } } -pub fn append_parent_ns(list: *std.ArrayListUnmanaged(u8), parent: Decl.Index) Oom!void { +pub fn append_parent_ns(list: *ArrayList(u8), parent: Decl.Index) Oom!void { assert(parent != .none); const decl = parent.get(); if (decl.parent != .none) { diff --git a/lib/docs/wasm/html_render.zig b/lib/docs/wasm/html_render.zig index 68b10a01e4..13d2ec05c5 100644 --- a/lib/docs/wasm/html_render.zig +++ b/lib/docs/wasm/html_render.zig @@ -1,6 +1,8 @@ const std = @import("std"); const Ast = std.zig.Ast; const assert = std.debug.assert; +const ArrayList = std.ArrayList; +const Writer = std.Io.Writer; const Walk = @import("Walk"); const Decl = Walk.Decl; @@ -30,7 +32,7 @@ pub const Annotation = struct { pub fn fileSourceHtml( file_index: Walk.File.Index, - out: *std.ArrayListUnmanaged(u8), + out: *ArrayList(u8), root_node: Ast.Node.Index, options: RenderSourceOptions, ) !void { @@ -38,7 +40,7 @@ pub fn fileSourceHtml( const file = file_index.get(); const g = struct { - var field_access_buffer: std.ArrayListUnmanaged(u8) = .empty; + var field_access_buffer: ArrayList(u8) = .empty; }; const start_token = ast.firstToken(root_node); @@ -88,7 +90,7 @@ pub fn fileSourceHtml( if (next_annotate_index >= options.source_location_annotations.len) break; const next_annotation = options.source_location_annotations[next_annotate_index]; if (cursor <= next_annotation.file_byte_offset) break; - try out.writer(gpa).print("", .{ + try out.print(gpa, "", .{ options.annotation_prefix, next_annotation.dom_id, }); next_annotate_index += 1; @@ -318,7 +320,7 @@ pub fn fileSourceHtml( } } -fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usize) !void { +fn appendUnindented(out: *ArrayList(u8), s: []const u8, indent: usize) !void { var it = std.mem.splitScalar(u8, s, '\n'); var is_first_line = true; while (it.next()) |line| { @@ -332,7 +334,7 @@ fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usi } } -pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void { +pub fn appendEscaped(out: *ArrayList(u8), s: []const u8) !void { for (s) |c| { try out.ensureUnusedCapacity(gpa, 6); switch (c) { @@ -347,7 +349,7 @@ pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void { fn walkFieldAccesses( file_index: Walk.File.Index, - out: *std.ArrayListUnmanaged(u8), + out: *ArrayList(u8), node: Ast.Node.Index, ) Oom!void { const ast = file_index.get_ast(); @@ -371,7 +373,7 @@ fn walkFieldAccesses( fn resolveIdentLink( file_index: Walk.File.Index, - out: *std.ArrayListUnmanaged(u8), + out: *ArrayList(u8), ident_token: Ast.TokenIndex, ) Oom!void { const decl_index = file_index.get().lookup_token(ident_token); @@ -391,7 +393,7 @@ fn unindent(s: []const u8, indent: usize) []const u8 { return s[indent_idx..]; } -pub fn resolveDeclLink(decl_index: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void { +pub fn resolveDeclLink(decl_index: Decl.Index, out: *ArrayList(u8)) Oom!void { const decl = decl_index.get(); switch (decl.categorize()) { .alias => |alias_decl| try alias_decl.get().fqn(out), diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index d3043cd917..adf3f6b884 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -5,6 +5,8 @@ const Ast = std.zig.Ast; const Walk = @import("Walk"); const markdown = @import("markdown.zig"); const Decl = Walk.Decl; +const ArrayList = std.ArrayList; +const Writer = std.Io.Writer; const fileSourceHtml = @import("html_render.zig").fileSourceHtml; const appendEscaped = @import("html_render.zig").appendEscaped; @@ -66,8 +68,8 @@ export fn unpack(tar_ptr: [*]u8, tar_len: usize) void { }; } -var query_string: std.ArrayListUnmanaged(u8) = .empty; -var query_results: std.ArrayListUnmanaged(Decl.Index) = .empty; +var query_string: ArrayList(u8) = .empty; +var query_results: ArrayList(Decl.Index) = .empty; /// Resizes the query string to be the correct length; returns the pointer to /// the query string. @@ -99,11 +101,11 @@ fn query_exec_fallible(query: []const u8, ignore_case: bool) !void { segments: u16, }; const g = struct { - var full_path_search_text: std.ArrayListUnmanaged(u8) = .empty; - var full_path_search_text_lower: std.ArrayListUnmanaged(u8) = .empty; - var doc_search_text: std.ArrayListUnmanaged(u8) = .empty; + var full_path_search_text: ArrayList(u8) = .empty; + var full_path_search_text_lower: ArrayList(u8) = .empty; + var doc_search_text: ArrayList(u8) = .empty; /// Each element matches a corresponding query_results element. - var scores: std.ArrayListUnmanaged(Score) = .empty; + var scores: ArrayList(Score) = .empty; }; // First element stores the size of the list. @@ -234,7 +236,7 @@ const ErrorIdentifier = packed struct(u64) { return ast.tokenTag(token_index - 1) == .doc_comment; } - fn html(ei: ErrorIdentifier, base_decl: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void { + fn html(ei: ErrorIdentifier, base_decl: Decl.Index, out: *ArrayList(u8)) Oom!void { const decl_index = ei.decl_index; const ast = decl_index.get().file.get_ast(); const name = ast.tokenSlice(ei.token_index); @@ -260,7 +262,7 @@ const ErrorIdentifier = packed struct(u64) { } }; -var string_result: std.ArrayListUnmanaged(u8) = .empty; +var string_result: ArrayList(u8) = .empty; var error_set_result: std.StringArrayHashMapUnmanaged(ErrorIdentifier) = .empty; export fn decl_error_set(decl_index: Decl.Index) Slice(ErrorIdentifier) { @@ -411,7 +413,7 @@ fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index { fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.Index { const g = struct { - var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty; + var result: ArrayList(Ast.Node.Index) = .empty; }; g.result.clearRetainingCapacity(); var buf: [2]Ast.Node.Index = undefined; @@ -429,7 +431,7 @@ fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.In fn decl_params_fallible(decl_index: Decl.Index) ![]Ast.Node.Index { const g = struct { - var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty; + var result: ArrayList(Ast.Node.Index) = .empty; }; g.result.clearRetainingCapacity(); const decl = decl_index.get(); @@ -460,7 +462,7 @@ export fn decl_param_html(decl_index: Decl.Index, param_node: Ast.Node.Index) St } fn decl_field_html_fallible( - out: *std.ArrayListUnmanaged(u8), + out: *ArrayList(u8), decl_index: Decl.Index, field_node: Ast.Node.Index, ) !void { @@ -480,7 +482,7 @@ fn decl_field_html_fallible( } fn decl_param_html_fallible( - out: *std.ArrayListUnmanaged(u8), + out: *ArrayList(u8), decl_index: Decl.Index, param_node: Ast.Node.Index, ) !void { @@ -649,7 +651,7 @@ export fn decl_docs_html(decl_index: Decl.Index, short: bool) String { } fn collect_docs( - list: *std.ArrayListUnmanaged(u8), + list: *ArrayList(u8), ast: *const Ast, first_doc_comment: Ast.TokenIndex, ) Oom!void { @@ -667,7 +669,7 @@ fn collect_docs( } fn render_docs( - out: *std.ArrayListUnmanaged(u8), + out: *ArrayList(u8), decl_index: Decl.Index, first_doc_comment: Ast.TokenIndex, short: bool, @@ -691,11 +693,10 @@ fn render_docs( defer parsed_doc.deinit(gpa); const g = struct { - var link_buffer: std.ArrayListUnmanaged(u8) = .empty; + var link_buffer: ArrayList(u8) = .empty; }; - const Writer = std.ArrayListUnmanaged(u8).Writer; - const Renderer = markdown.Renderer(Writer, Decl.Index); + const Renderer = markdown.Renderer(Decl.Index); const renderer: Renderer = .{ .context = decl_index, .renderFn = struct { @@ -703,8 +704,8 @@ fn render_docs( r: Renderer, doc: markdown.Document, node: markdown.Document.Node.Index, - writer: Writer, - ) !void { + writer: *Writer, + ) Writer.Error!void { const data = doc.nodes.items(.data)[@intFromEnum(node)]; switch (doc.nodes.items(.tag)[@intFromEnum(node)]) { .code_span => { @@ -712,7 +713,7 @@ fn render_docs( const content = doc.string(data.text.content); if (resolve_decl_path(r.context, content)) |resolved_decl_index| { g.link_buffer.clearRetainingCapacity(); - try resolveDeclLink(resolved_decl_index, &g.link_buffer); + resolveDeclLink(resolved_decl_index, &g.link_buffer) catch return error.WriteFailed; try writer.writeAll(" return error.OutOfMemory, + }; } fn resolve_decl_path(decl_index: Decl.Index, path: []const u8) ?Decl.Index { @@ -827,7 +833,7 @@ export fn find_module_root(pkg: Walk.ModuleIndex) Decl.Index { } /// Set by `set_input_string`. -var input_string: std.ArrayListUnmanaged(u8) = .empty; +var input_string: ArrayList(u8) = .empty; export fn set_input_string(len: usize) [*]u8 { input_string.resize(gpa, len) catch @panic("OOM"); @@ -849,7 +855,7 @@ export fn find_decl() Decl.Index { if (result != .none) return result; const g = struct { - var match_fqn: std.ArrayListUnmanaged(u8) = .empty; + var match_fqn: ArrayList(u8) = .empty; }; for (Walk.decls.items, 0..) |*decl, decl_index| { g.match_fqn.clearRetainingCapacity(); @@ -905,7 +911,7 @@ export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl. export fn namespace_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) { const g = struct { - var members: std.ArrayListUnmanaged(Decl.Index) = .empty; + var members: ArrayList(Decl.Index) = .empty; }; g.members.clearRetainingCapacity(); diff --git a/lib/docs/wasm/markdown/renderer.zig b/lib/docs/wasm/markdown/renderer.zig index cba857d204..13e3795b9a 100644 --- a/lib/docs/wasm/markdown/renderer.zig +++ b/lib/docs/wasm/markdown/renderer.zig @@ -2,25 +2,26 @@ const std = @import("std"); const Document = @import("Document.zig"); const Node = Document.Node; const assert = std.debug.assert; +const Writer = std.Io.Writer; /// A Markdown document renderer. /// /// Each concrete `Renderer` type has a `renderDefault` function, with the /// intention that custom `renderFn` implementations can call `renderDefault` /// for node types for which they require no special rendering. -pub fn Renderer(comptime Writer: type, comptime Context: type) type { +pub fn Renderer(comptime Context: type) type { return struct { renderFn: *const fn ( r: Self, doc: Document, node: Node.Index, - writer: Writer, + writer: *Writer, ) Writer.Error!void = renderDefault, context: Context, const Self = @This(); - pub fn render(r: Self, doc: Document, writer: Writer) Writer.Error!void { + pub fn render(r: Self, doc: Document, writer: *Writer) Writer.Error!void { try r.renderFn(r, doc, .root, writer); } @@ -28,7 +29,7 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type { r: Self, doc: Document, node: Node.Index, - writer: Writer, + writer: *Writer, ) Writer.Error!void { const data = doc.nodes.items(.data)[@intFromEnum(node)]; switch (doc.nodes.items(.tag)[@intFromEnum(node)]) { @@ -188,8 +189,8 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type { pub fn renderInlineNodeText( doc: Document, node: Node.Index, - writer: anytype, -) @TypeOf(writer).Error!void { + writer: *Writer, +) Writer.Error!void { const data = doc.nodes.items(.data)[@intFromEnum(node)]; switch (doc.nodes.items(.tag)[@intFromEnum(node)]) { .root, @@ -234,14 +235,12 @@ pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter([]const u8, formatHtml) { return .{ .data = bytes }; } -fn formatHtml(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void { - for (bytes) |b| { - switch (b) { - '<' => try writer.writeAll("<"), - '>' => try writer.writeAll(">"), - '&' => try writer.writeAll("&"), - '"' => try writer.writeAll("""), - else => try writer.writeByte(b), - } - } +fn formatHtml(bytes: []const u8, w: *Writer) Writer.Error!void { + for (bytes) |b| switch (b) { + '<' => try w.writeAll("<"), + '>' => try w.writeAll(">"), + '&' => try w.writeAll("&"), + '"' => try w.writeAll("""), + else => try w.writeByte(b), + }; } diff --git a/tools/docgen.zig b/tools/docgen.zig index 04066eff78..fbab24576c 100644 --- a/tools/docgen.zig +++ b/tools/docgen.zig @@ -1,6 +1,5 @@ const std = @import("std"); const builtin = @import("builtin"); -const io = std.io; const fs = std.fs; const process = std.process; const Progress = std.Progress; @@ -8,8 +7,10 @@ const print = std.debug.print; const mem = std.mem; const testing = std.testing; const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; const getExternalExecutor = std.zig.system.getExternalExecutor; const fatal = std.process.fatal; +const Writer = std.Io.Writer; const max_doc_file_size = 10 * 1024 * 1024; @@ -344,10 +345,10 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc { var last_action: Action = .open; var last_columns: ?u8 = null; - var toc_buf = std.array_list.Managed(u8).init(allocator); + var toc_buf: Writer.Allocating = .init(allocator); defer toc_buf.deinit(); - var toc = toc_buf.writer(); + const toc = &toc_buf.writer; var nodes = std.array_list.Managed(Node).init(allocator); defer nodes.deinit(); @@ -422,7 +423,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc { } if (last_action == .open) { try toc.writeByte('\n'); - try toc.writeByteNTimes(' ', header_stack_size * 4); + try toc.splatByteAll(' ', header_stack_size * 4); if (last_columns) |n| { try toc.print("\n"); } else { try toc.writeAll("\n"); @@ -591,30 +592,29 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc { } } - return Toc{ + return .{ .nodes = try nodes.toOwnedSlice(), .toc = try toc_buf.toOwnedSlice(), .urls = urls, }; } -fn urlize(allocator: Allocator, input: []const u8) ![]u8 { - var buf = std.array_list.Managed(u8).init(allocator); - defer buf.deinit(); +fn urlize(gpa: Allocator, input: []const u8) ![]u8 { + var buf: ArrayList(u8) = .empty; + defer buf.deinit(gpa); - const out = buf.writer(); for (input) |c| { switch (c) { 'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => { - try out.writeByte(c); + try buf.append(gpa, c); }, ' ' => { - try out.writeByte('-'); + try buf.append(gpa, '-'); }, else => {}, } } - return try buf.toOwnedSlice(); + return try buf.toOwnedSlice(gpa); } fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 { @@ -626,7 +626,7 @@ fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 { return try buf.toOwnedSlice(); } -fn writeEscaped(out: anytype, input: []const u8) !void { +fn writeEscaped(out: *Writer, input: []const u8) !void { for (input) |c| { try switch (c) { '&' => out.writeAll("&"), @@ -662,14 +662,14 @@ fn isType(name: []const u8) bool { return false; } -fn writeEscapedLines(out: anytype, text: []const u8) !void { +fn writeEscapedLines(out: *Writer, text: []const u8) !void { return writeEscaped(out, text); } fn tokenizeAndPrintRaw( allocator: Allocator, docgen_tokenizer: *Tokenizer, - out: anytype, + out: *Writer, source_token: Token, raw_src: []const u8, ) !void { @@ -907,14 +907,14 @@ fn tokenizeAndPrintRaw( fn tokenizeAndPrint( allocator: Allocator, docgen_tokenizer: *Tokenizer, - out: anytype, + out: *Writer, source_token: Token, ) !void { const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end]; return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src); } -fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: anytype, syntax_block: SyntaxBlock) !void { +fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock) !void { const source_type = @tagName(syntax_block.source_type); try out.print("
{s}
", .{ source_type, syntax_block.name });
@@ -932,7 +932,7 @@ fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: any
     try out.writeAll("
"); } -fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void { +fn printShell(out: *Writer, shell_content: []const u8, escape: bool) !void { const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n"); try out.writeAll("
Shell
");
     var cmd_cont: bool = false;
@@ -984,7 +984,7 @@ fn genHtml(
     tokenizer: *Tokenizer,
     toc: *Toc,
     code_dir: std.fs.Dir,
-    out: anytype,
+    out: *Writer,
 ) !void {
     for (toc.nodes) |node| {
         switch (node) {
diff --git a/tools/doctest.zig b/tools/doctest.zig
index 2c8f14e913..9aa7262d7f 100644
--- a/tools/doctest.zig
+++ b/tools/doctest.zig
@@ -127,9 +127,9 @@ fn printOutput(
     const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);
     const print = std.debug.print;
 
-    var shell_buffer = std.array_list.Managed(u8).init(arena);
+    var shell_buffer: std.Io.Writer.Allocating = .init(arena);
     defer shell_buffer.deinit();
-    var shell_out = shell_buffer.writer();
+    const shell_out = &shell_buffer.writer;
 
     const code_name = std.fs.path.stem(input_path);
 
@@ -600,7 +600,7 @@ fn printOutput(
     }
 
     if (!code.just_check_syntax) {
-        try printShell(out, shell_buffer.items, false);
+        try printShell(out, shell_buffer.written(), false);
     }
 }
 
@@ -975,25 +975,21 @@ fn skipPrefix(line: []const u8) []const u8 {
     return line[3..];
 }
 
-fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {
-    var buf = std.array_list.Managed(u8).init(allocator);
-    defer buf.deinit();
-
-    const out = buf.writer();
-    try writeEscaped(out, input);
-    return try buf.toOwnedSlice();
+fn escapeHtml(gpa: Allocator, input: []const u8) ![]u8 {
+    var allocating: Writer.Allocating = .init(gpa);
+    defer allocating.deinit();
+    try writeEscaped(&allocating.writer, input);
+    return allocating.toOwnedSlice();
 }
 
-fn writeEscaped(out: *Writer, input: []const u8) !void {
-    for (input) |c| {
-        try switch (c) {
-            '&' => out.writeAll("&"),
-            '<' => out.writeAll("<"),
-            '>' => out.writeAll(">"),
-            '"' => out.writeAll("""),
-            else => out.writeByte(c),
-        };
-    }
+fn writeEscaped(w: *Writer, input: []const u8) !void {
+    for (input) |c| try switch (c) {
+        '&' => w.writeAll("&"),
+        '<' => w.writeAll("<"),
+        '>' => w.writeAll(">"),
+        '"' => w.writeAll("""),
+        else => w.writeByte(c),
+    };
 }
 
 fn termColor(allocator: Allocator, input: []const u8) ![]u8 {