authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-27 22:47:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 18:30:57-07:00
log9b47dd2028deb45324ca19d909d0cee69f51f1b9
tree1b9cd7bbe8b1f09c77bc8b38458a0c5f745c2934
parent8023f3dcebff06cbf3563bdd09b07462ed43509f

update langref and docs to avoid GenericWriter


6 files changed, 97 insertions(+), 93 deletions(-)

lib/docs/wasm/Decl.zig+5-4
...@@ -6,6 +6,7 @@ const gpa = std.heap.wasm_allocator;...@@ -6,6 +6,7 @@ const gpa = std.heap.wasm_allocator;
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const log = std.log;7const log = std.log;
8const Oom = error{OutOfMemory};8const Oom = error{OutOfMemory};
9const ArrayList = std.ArrayList;
910
10ast_node: Ast.Node.Index,11ast_node: Ast.Node.Index,
11file: Walk.File.Index,12file: Walk.File.Index,
...@@ -189,7 +190,7 @@ pub fn lookup(decl: *const Decl, name: []const u8) ?Decl.Index {...@@ -189,7 +190,7 @@ pub fn lookup(decl: *const Decl, name: []const u8) ?Decl.Index {
189}190}
190191
191/// Appends the fully qualified name to `out`.192/// Appends the fully qualified name to `out`.
192pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void {193pub fn fqn(decl: *const Decl, out: *ArrayList(u8)) Oom!void {
193 try decl.append_path(out);194 try decl.append_path(out);
194 if (decl.parent != .none) {195 if (decl.parent != .none) {
195 try append_parent_ns(out, decl.parent);196 try append_parent_ns(out, decl.parent);
...@@ -199,12 +200,12 @@ pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void {...@@ -199,12 +200,12 @@ pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void {
199 }200 }
200}201}
201202
202pub fn reset_with_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void {203pub fn reset_with_path(decl: *const Decl, list: *ArrayList(u8)) Oom!void {
203 list.clearRetainingCapacity();204 list.clearRetainingCapacity();
204 try append_path(decl, list);205 try append_path(decl, list);
205}206}
206207
207pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void {208pub fn append_path(decl: *const Decl, list: *ArrayList(u8)) Oom!void {
208 const start = list.items.len;209 const start = list.items.len;
209 // Prefer the module name alias.210 // Prefer the module name alias.
210 for (Walk.modules.keys(), Walk.modules.values()) |pkg_name, pkg_file| {211 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...@@ -230,7 +231,7 @@ pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!voi
230 }231 }
231}232}
232233
233pub fn append_parent_ns(list: *std.ArrayListUnmanaged(u8), parent: Decl.Index) Oom!void {234pub fn append_parent_ns(list: *ArrayList(u8), parent: Decl.Index) Oom!void {
234 assert(parent != .none);235 assert(parent != .none);
235 const decl = parent.get();236 const decl = parent.get();
236 if (decl.parent != .none) {237 if (decl.parent != .none) {
lib/docs/wasm/html_render.zig+10-8
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const std = @import("std");1const std = @import("std");
2const Ast = std.zig.Ast;2const Ast = std.zig.Ast;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const ArrayList = std.ArrayList;
5const Writer = std.Io.Writer;
46
5const Walk = @import("Walk");7const Walk = @import("Walk");
6const Decl = Walk.Decl;8const Decl = Walk.Decl;
...@@ -30,7 +32,7 @@ pub const Annotation = struct {...@@ -30,7 +32,7 @@ pub const Annotation = struct {
3032
31pub fn fileSourceHtml(33pub fn fileSourceHtml(
32 file_index: Walk.File.Index,34 file_index: Walk.File.Index,
33 out: *std.ArrayListUnmanaged(u8),35 out: *ArrayList(u8),
34 root_node: Ast.Node.Index,36 root_node: Ast.Node.Index,
35 options: RenderSourceOptions,37 options: RenderSourceOptions,
36) !void {38) !void {
...@@ -38,7 +40,7 @@ pub fn fileSourceHtml(...@@ -38,7 +40,7 @@ pub fn fileSourceHtml(
38 const file = file_index.get();40 const file = file_index.get();
3941
40 const g = struct {42 const g = struct {
41 var field_access_buffer: std.ArrayListUnmanaged(u8) = .empty;43 var field_access_buffer: ArrayList(u8) = .empty;
42 };44 };
4345
44 const start_token = ast.firstToken(root_node);46 const start_token = ast.firstToken(root_node);
...@@ -88,7 +90,7 @@ pub fn fileSourceHtml(...@@ -88,7 +90,7 @@ pub fn fileSourceHtml(
88 if (next_annotate_index >= options.source_location_annotations.len) break;90 if (next_annotate_index >= options.source_location_annotations.len) break;
89 const next_annotation = options.source_location_annotations[next_annotate_index];91 const next_annotation = options.source_location_annotations[next_annotate_index];
90 if (cursor <= next_annotation.file_byte_offset) break;92 if (cursor <= next_annotation.file_byte_offset) break;
91 try out.writer(gpa).print("<span id=\"{s}{d}\"></span>", .{93 try out.print(gpa, "<span id=\"{s}{d}\"></span>", .{
92 options.annotation_prefix, next_annotation.dom_id,94 options.annotation_prefix, next_annotation.dom_id,
93 });95 });
94 next_annotate_index += 1;96 next_annotate_index += 1;
...@@ -318,7 +320,7 @@ pub fn fileSourceHtml(...@@ -318,7 +320,7 @@ pub fn fileSourceHtml(
318 }320 }
319}321}
320322
321fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usize) !void {323fn appendUnindented(out: *ArrayList(u8), s: []const u8, indent: usize) !void {
322 var it = std.mem.splitScalar(u8, s, '\n');324 var it = std.mem.splitScalar(u8, s, '\n');
323 var is_first_line = true;325 var is_first_line = true;
324 while (it.next()) |line| {326 while (it.next()) |line| {
...@@ -332,7 +334,7 @@ fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usi...@@ -332,7 +334,7 @@ fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usi
332 }334 }
333}335}
334336
335pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void {337pub fn appendEscaped(out: *ArrayList(u8), s: []const u8) !void {
336 for (s) |c| {338 for (s) |c| {
337 try out.ensureUnusedCapacity(gpa, 6);339 try out.ensureUnusedCapacity(gpa, 6);
338 switch (c) {340 switch (c) {
...@@ -347,7 +349,7 @@ pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void {...@@ -347,7 +349,7 @@ pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void {
347349
348fn walkFieldAccesses(350fn walkFieldAccesses(
349 file_index: Walk.File.Index,351 file_index: Walk.File.Index,
350 out: *std.ArrayListUnmanaged(u8),352 out: *ArrayList(u8),
351 node: Ast.Node.Index,353 node: Ast.Node.Index,
352) Oom!void {354) Oom!void {
353 const ast = file_index.get_ast();355 const ast = file_index.get_ast();
...@@ -371,7 +373,7 @@ fn walkFieldAccesses(...@@ -371,7 +373,7 @@ fn walkFieldAccesses(
371373
372fn resolveIdentLink(374fn resolveIdentLink(
373 file_index: Walk.File.Index,375 file_index: Walk.File.Index,
374 out: *std.ArrayListUnmanaged(u8),376 out: *ArrayList(u8),
375 ident_token: Ast.TokenIndex,377 ident_token: Ast.TokenIndex,
376) Oom!void {378) Oom!void {
377 const decl_index = file_index.get().lookup_token(ident_token);379 const decl_index = file_index.get().lookup_token(ident_token);
...@@ -391,7 +393,7 @@ fn unindent(s: []const u8, indent: usize) []const u8 {...@@ -391,7 +393,7 @@ fn unindent(s: []const u8, indent: usize) []const u8 {
391 return s[indent_idx..];393 return s[indent_idx..];
392}394}
393395
394pub fn resolveDeclLink(decl_index: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void {396pub fn resolveDeclLink(decl_index: Decl.Index, out: *ArrayList(u8)) Oom!void {
395 const decl = decl_index.get();397 const decl = decl_index.get();
396 switch (decl.categorize()) {398 switch (decl.categorize()) {
397 .alias => |alias_decl| try alias_decl.get().fqn(out),399 .alias => |alias_decl| try alias_decl.get().fqn(out),
lib/docs/wasm/main.zig+30-24
...@@ -5,6 +5,8 @@ const Ast = std.zig.Ast;...@@ -5,6 +5,8 @@ const Ast = std.zig.Ast;
5const Walk = @import("Walk");5const Walk = @import("Walk");
6const markdown = @import("markdown.zig");6const markdown = @import("markdown.zig");
7const Decl = Walk.Decl;7const Decl = Walk.Decl;
8const ArrayList = std.ArrayList;
9const Writer = std.Io.Writer;
810
9const fileSourceHtml = @import("html_render.zig").fileSourceHtml;11const fileSourceHtml = @import("html_render.zig").fileSourceHtml;
10const appendEscaped = @import("html_render.zig").appendEscaped;12const appendEscaped = @import("html_render.zig").appendEscaped;
...@@ -66,8 +68,8 @@ export fn unpack(tar_ptr: [*]u8, tar_len: usize) void {...@@ -66,8 +68,8 @@ export fn unpack(tar_ptr: [*]u8, tar_len: usize) void {
66 };68 };
67}69}
6870
69var query_string: std.ArrayListUnmanaged(u8) = .empty;71var query_string: ArrayList(u8) = .empty;
70var query_results: std.ArrayListUnmanaged(Decl.Index) = .empty;72var query_results: ArrayList(Decl.Index) = .empty;
7173
72/// Resizes the query string to be the correct length; returns the pointer to74/// Resizes the query string to be the correct length; returns the pointer to
73/// the query string.75/// the query string.
...@@ -99,11 +101,11 @@ fn query_exec_fallible(query: []const u8, ignore_case: bool) !void {...@@ -99,11 +101,11 @@ fn query_exec_fallible(query: []const u8, ignore_case: bool) !void {
99 segments: u16,101 segments: u16,
100 };102 };
101 const g = struct {103 const g = struct {
102 var full_path_search_text: std.ArrayListUnmanaged(u8) = .empty;104 var full_path_search_text: ArrayList(u8) = .empty;
103 var full_path_search_text_lower: std.ArrayListUnmanaged(u8) = .empty;105 var full_path_search_text_lower: ArrayList(u8) = .empty;
104 var doc_search_text: std.ArrayListUnmanaged(u8) = .empty;106 var doc_search_text: ArrayList(u8) = .empty;
105 /// Each element matches a corresponding query_results element.107 /// Each element matches a corresponding query_results element.
106 var scores: std.ArrayListUnmanaged(Score) = .empty;108 var scores: ArrayList(Score) = .empty;
107 };109 };
108110
109 // First element stores the size of the list.111 // First element stores the size of the list.
...@@ -234,7 +236,7 @@ const ErrorIdentifier = packed struct(u64) {...@@ -234,7 +236,7 @@ const ErrorIdentifier = packed struct(u64) {
234 return ast.tokenTag(token_index - 1) == .doc_comment;236 return ast.tokenTag(token_index - 1) == .doc_comment;
235 }237 }
236238
237 fn html(ei: ErrorIdentifier, base_decl: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void {239 fn html(ei: ErrorIdentifier, base_decl: Decl.Index, out: *ArrayList(u8)) Oom!void {
238 const decl_index = ei.decl_index;240 const decl_index = ei.decl_index;
239 const ast = decl_index.get().file.get_ast();241 const ast = decl_index.get().file.get_ast();
240 const name = ast.tokenSlice(ei.token_index);242 const name = ast.tokenSlice(ei.token_index);
...@@ -260,7 +262,7 @@ const ErrorIdentifier = packed struct(u64) {...@@ -260,7 +262,7 @@ const ErrorIdentifier = packed struct(u64) {
260 }262 }
261};263};
262264
263var string_result: std.ArrayListUnmanaged(u8) = .empty;265var string_result: ArrayList(u8) = .empty;
264var error_set_result: std.StringArrayHashMapUnmanaged(ErrorIdentifier) = .empty;266var error_set_result: std.StringArrayHashMapUnmanaged(ErrorIdentifier) = .empty;
265267
266export fn decl_error_set(decl_index: Decl.Index) Slice(ErrorIdentifier) {268export 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 {...@@ -411,7 +413,7 @@ fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
411413
412fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.Index {414fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.Index {
413 const g = struct {415 const g = struct {
414 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;416 var result: ArrayList(Ast.Node.Index) = .empty;
415 };417 };
416 g.result.clearRetainingCapacity();418 g.result.clearRetainingCapacity();
417 var buf: [2]Ast.Node.Index = undefined;419 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...@@ -429,7 +431,7 @@ fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.In
429431
430fn decl_params_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {432fn decl_params_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
431 const g = struct {433 const g = struct {
432 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;434 var result: ArrayList(Ast.Node.Index) = .empty;
433 };435 };
434 g.result.clearRetainingCapacity();436 g.result.clearRetainingCapacity();
435 const decl = decl_index.get();437 const decl = decl_index.get();
...@@ -460,7 +462,7 @@ export fn decl_param_html(decl_index: Decl.Index, param_node: Ast.Node.Index) St...@@ -460,7 +462,7 @@ export fn decl_param_html(decl_index: Decl.Index, param_node: Ast.Node.Index) St
460}462}
461463
462fn decl_field_html_fallible(464fn decl_field_html_fallible(
463 out: *std.ArrayListUnmanaged(u8),465 out: *ArrayList(u8),
464 decl_index: Decl.Index,466 decl_index: Decl.Index,
465 field_node: Ast.Node.Index,467 field_node: Ast.Node.Index,
466) !void {468) !void {
...@@ -480,7 +482,7 @@ fn decl_field_html_fallible(...@@ -480,7 +482,7 @@ fn decl_field_html_fallible(
480}482}
481483
482fn decl_param_html_fallible(484fn decl_param_html_fallible(
483 out: *std.ArrayListUnmanaged(u8),485 out: *ArrayList(u8),
484 decl_index: Decl.Index,486 decl_index: Decl.Index,
485 param_node: Ast.Node.Index,487 param_node: Ast.Node.Index,
486) !void {488) !void {
...@@ -649,7 +651,7 @@ export fn decl_docs_html(decl_index: Decl.Index, short: bool) String {...@@ -649,7 +651,7 @@ export fn decl_docs_html(decl_index: Decl.Index, short: bool) String {
649}651}
650652
651fn collect_docs(653fn collect_docs(
652 list: *std.ArrayListUnmanaged(u8),654 list: *ArrayList(u8),
653 ast: *const Ast,655 ast: *const Ast,
654 first_doc_comment: Ast.TokenIndex,656 first_doc_comment: Ast.TokenIndex,
655) Oom!void {657) Oom!void {
...@@ -667,7 +669,7 @@ fn collect_docs(...@@ -667,7 +669,7 @@ fn collect_docs(
667}669}
668670
669fn render_docs(671fn render_docs(
670 out: *std.ArrayListUnmanaged(u8),672 out: *ArrayList(u8),
671 decl_index: Decl.Index,673 decl_index: Decl.Index,
672 first_doc_comment: Ast.TokenIndex,674 first_doc_comment: Ast.TokenIndex,
673 short: bool,675 short: bool,
...@@ -691,11 +693,10 @@ fn render_docs(...@@ -691,11 +693,10 @@ fn render_docs(
691 defer parsed_doc.deinit(gpa);693 defer parsed_doc.deinit(gpa);
692694
693 const g = struct {695 const g = struct {
694 var link_buffer: std.ArrayListUnmanaged(u8) = .empty;696 var link_buffer: ArrayList(u8) = .empty;
695 };697 };
696698
697 const Writer = std.ArrayListUnmanaged(u8).Writer;699 const Renderer = markdown.Renderer(Decl.Index);
698 const Renderer = markdown.Renderer(Writer, Decl.Index);
699 const renderer: Renderer = .{700 const renderer: Renderer = .{
700 .context = decl_index,701 .context = decl_index,
701 .renderFn = struct {702 .renderFn = struct {
...@@ -703,8 +704,8 @@ fn render_docs(...@@ -703,8 +704,8 @@ fn render_docs(
703 r: Renderer,704 r: Renderer,
704 doc: markdown.Document,705 doc: markdown.Document,
705 node: markdown.Document.Node.Index,706 node: markdown.Document.Node.Index,
706 writer: Writer,707 writer: *Writer,
707 ) !void {708 ) Writer.Error!void {
708 const data = doc.nodes.items(.data)[@intFromEnum(node)];709 const data = doc.nodes.items(.data)[@intFromEnum(node)];
709 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {710 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
710 .code_span => {711 .code_span => {
...@@ -712,7 +713,7 @@ fn render_docs(...@@ -712,7 +713,7 @@ fn render_docs(
712 const content = doc.string(data.text.content);713 const content = doc.string(data.text.content);
713 if (resolve_decl_path(r.context, content)) |resolved_decl_index| {714 if (resolve_decl_path(r.context, content)) |resolved_decl_index| {
714 g.link_buffer.clearRetainingCapacity();715 g.link_buffer.clearRetainingCapacity();
715 try resolveDeclLink(resolved_decl_index, &g.link_buffer);716 resolveDeclLink(resolved_decl_index, &g.link_buffer) catch return error.WriteFailed;
716717
717 try writer.writeAll("<a href=\"#");718 try writer.writeAll("<a href=\"#");
718 _ = missing_feature_url_escape;719 _ = missing_feature_url_escape;
...@@ -730,7 +731,12 @@ fn render_docs(...@@ -730,7 +731,12 @@ fn render_docs(
730 }731 }
731 }.render,732 }.render,
732 };733 };
733 try renderer.render(parsed_doc, out.writer(gpa));734
735 var allocating = Writer.Allocating.fromArrayList(gpa, out);
736 defer out.* = allocating.toArrayList();
737 renderer.render(parsed_doc, &allocating.writer) catch |err| switch (err) {
738 error.WriteFailed => return error.OutOfMemory,
739 };
734}740}
735741
736fn resolve_decl_path(decl_index: Decl.Index, path: []const u8) ?Decl.Index {742fn 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 {...@@ -827,7 +833,7 @@ export fn find_module_root(pkg: Walk.ModuleIndex) Decl.Index {
827}833}
828834
829/// Set by `set_input_string`.835/// Set by `set_input_string`.
830var input_string: std.ArrayListUnmanaged(u8) = .empty;836var input_string: ArrayList(u8) = .empty;
831837
832export fn set_input_string(len: usize) [*]u8 {838export fn set_input_string(len: usize) [*]u8 {
833 input_string.resize(gpa, len) catch @panic("OOM");839 input_string.resize(gpa, len) catch @panic("OOM");
...@@ -849,7 +855,7 @@ export fn find_decl() Decl.Index {...@@ -849,7 +855,7 @@ export fn find_decl() Decl.Index {
849 if (result != .none) return result;855 if (result != .none) return result;
850856
851 const g = struct {857 const g = struct {
852 var match_fqn: std.ArrayListUnmanaged(u8) = .empty;858 var match_fqn: ArrayList(u8) = .empty;
853 };859 };
854 for (Walk.decls.items, 0..) |*decl, decl_index| {860 for (Walk.decls.items, 0..) |*decl, decl_index| {
855 g.match_fqn.clearRetainingCapacity();861 g.match_fqn.clearRetainingCapacity();
...@@ -905,7 +911,7 @@ export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl....@@ -905,7 +911,7 @@ export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl.
905911
906export fn namespace_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {912export fn namespace_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {
907 const g = struct {913 const g = struct {
908 var members: std.ArrayListUnmanaged(Decl.Index) = .empty;914 var members: ArrayList(Decl.Index) = .empty;
909 };915 };
910916
911 g.members.clearRetainingCapacity();917 g.members.clearRetainingCapacity();
lib/docs/wasm/markdown/renderer.zig+15-16
...@@ -2,25 +2,26 @@ const std = @import("std");...@@ -2,25 +2,26 @@ const std = @import("std");
2const Document = @import("Document.zig");2const Document = @import("Document.zig");
3const Node = Document.Node;3const Node = Document.Node;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Writer = std.Io.Writer;
56
6/// A Markdown document renderer.7/// A Markdown document renderer.
7///8///
8/// Each concrete `Renderer` type has a `renderDefault` function, with the9/// Each concrete `Renderer` type has a `renderDefault` function, with the
9/// intention that custom `renderFn` implementations can call `renderDefault`10/// intention that custom `renderFn` implementations can call `renderDefault`
10/// for node types for which they require no special rendering.11/// for node types for which they require no special rendering.
11pub fn Renderer(comptime Writer: type, comptime Context: type) type {12pub fn Renderer(comptime Context: type) type {
12 return struct {13 return struct {
13 renderFn: *const fn (14 renderFn: *const fn (
14 r: Self,15 r: Self,
15 doc: Document,16 doc: Document,
16 node: Node.Index,17 node: Node.Index,
17 writer: Writer,18 writer: *Writer,
18 ) Writer.Error!void = renderDefault,19 ) Writer.Error!void = renderDefault,
19 context: Context,20 context: Context,
2021
21 const Self = @This();22 const Self = @This();
2223
23 pub fn render(r: Self, doc: Document, writer: Writer) Writer.Error!void {24 pub fn render(r: Self, doc: Document, writer: *Writer) Writer.Error!void {
24 try r.renderFn(r, doc, .root, writer);25 try r.renderFn(r, doc, .root, writer);
25 }26 }
2627
...@@ -28,7 +29,7 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {...@@ -28,7 +29,7 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
28 r: Self,29 r: Self,
29 doc: Document,30 doc: Document,
30 node: Node.Index,31 node: Node.Index,
31 writer: Writer,32 writer: *Writer,
32 ) Writer.Error!void {33 ) Writer.Error!void {
33 const data = doc.nodes.items(.data)[@intFromEnum(node)];34 const data = doc.nodes.items(.data)[@intFromEnum(node)];
34 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {35 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
...@@ -188,8 +189,8 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {...@@ -188,8 +189,8 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
188pub fn renderInlineNodeText(189pub fn renderInlineNodeText(
189 doc: Document,190 doc: Document,
190 node: Node.Index,191 node: Node.Index,
191 writer: anytype,192 writer: *Writer,
192) @TypeOf(writer).Error!void {193) Writer.Error!void {
193 const data = doc.nodes.items(.data)[@intFromEnum(node)];194 const data = doc.nodes.items(.data)[@intFromEnum(node)];
194 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {195 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
195 .root,196 .root,
...@@ -234,14 +235,12 @@ pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter([]const u8, formatHtml) {...@@ -234,14 +235,12 @@ pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter([]const u8, formatHtml) {
234 return .{ .data = bytes };235 return .{ .data = bytes };
235}236}
236237
237fn formatHtml(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void {238fn formatHtml(bytes: []const u8, w: *Writer) Writer.Error!void {
238 for (bytes) |b| {239 for (bytes) |b| switch (b) {
239 switch (b) {240 '<' => try w.writeAll("&lt;"),
240 '<' => try writer.writeAll("&lt;"),241 '>' => try w.writeAll("&gt;"),
241 '>' => try writer.writeAll("&gt;"),242 '&' => try w.writeAll("&amp;"),
242 '&' => try writer.writeAll("&amp;"),243 '"' => try w.writeAll("&quot;"),
243 '"' => try writer.writeAll("&quot;"),244 else => try w.writeByte(b),
244 else => try writer.writeByte(b),245 };
245 }
246 }
247}246}
tools/docgen.zig+21-21
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const io = std.io;
4const fs = std.fs;3const fs = std.fs;
5const process = std.process;4const process = std.process;
6const Progress = std.Progress;5const Progress = std.Progress;
...@@ -8,8 +7,10 @@ const print = std.debug.print;...@@ -8,8 +7,10 @@ const print = std.debug.print;
8const mem = std.mem;7const mem = std.mem;
9const testing = std.testing;8const testing = std.testing;
10const Allocator = std.mem.Allocator;9const Allocator = std.mem.Allocator;
10const ArrayList = std.ArrayList;
11const getExternalExecutor = std.zig.system.getExternalExecutor;11const getExternalExecutor = std.zig.system.getExternalExecutor;
12const fatal = std.process.fatal;12const fatal = std.process.fatal;
13const Writer = std.Io.Writer;
1314
14const max_doc_file_size = 10 * 1024 * 1024;15const max_doc_file_size = 10 * 1024 * 1024;
1516
...@@ -344,10 +345,10 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -344,10 +345,10 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
344 var last_action: Action = .open;345 var last_action: Action = .open;
345 var last_columns: ?u8 = null;346 var last_columns: ?u8 = null;
346347
347 var toc_buf = std.array_list.Managed(u8).init(allocator);348 var toc_buf: Writer.Allocating = .init(allocator);
348 defer toc_buf.deinit();349 defer toc_buf.deinit();
349350
350 var toc = toc_buf.writer();351 const toc = &toc_buf.writer;
351352
352 var nodes = std.array_list.Managed(Node).init(allocator);353 var nodes = std.array_list.Managed(Node).init(allocator);
353 defer nodes.deinit();354 defer nodes.deinit();
...@@ -422,7 +423,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -422,7 +423,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
422 }423 }
423 if (last_action == .open) {424 if (last_action == .open) {
424 try toc.writeByte('\n');425 try toc.writeByte('\n');
425 try toc.writeByteNTimes(' ', header_stack_size * 4);426 try toc.splatByteAll(' ', header_stack_size * 4);
426 if (last_columns) |n| {427 if (last_columns) |n| {
427 try toc.print("<ul style=\"columns: {d}\">\n", .{n});428 try toc.print("<ul style=\"columns: {d}\">\n", .{n});
428 } else {429 } else {
...@@ -432,7 +433,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -432,7 +433,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
432 last_action = .open;433 last_action = .open;
433 }434 }
434 last_columns = columns;435 last_columns = columns;
435 try toc.writeByteNTimes(' ', 4 + header_stack_size * 4);436 try toc.splatByteAll(' ', 4 + header_stack_size * 4);
436 try toc.print("<li><a id=\"toc-{s}\" href=\"#{s}\">{s}</a>", .{ urlized, urlized, content });437 try toc.print("<li><a id=\"toc-{s}\" href=\"#{s}\">{s}</a>", .{ urlized, urlized, content });
437 } else if (mem.eql(u8, tag_name, "header_close")) {438 } else if (mem.eql(u8, tag_name, "header_close")) {
438 if (header_stack_size == 0) {439 if (header_stack_size == 0) {
...@@ -442,7 +443,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -442,7 +443,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
442 _ = try eatToken(tokenizer, .bracket_close);443 _ = try eatToken(tokenizer, .bracket_close);
443444
444 if (last_action == .close) {445 if (last_action == .close) {
445 try toc.writeByteNTimes(' ', 8 + header_stack_size * 4);446 try toc.splatByteAll(' ', 8 + header_stack_size * 4);
446 try toc.writeAll("</ul></li>\n");447 try toc.writeAll("</ul></li>\n");
447 } else {448 } else {
448 try toc.writeAll("</li>\n");449 try toc.writeAll("</li>\n");
...@@ -591,30 +592,29 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -591,30 +592,29 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
591 }592 }
592 }593 }
593594
594 return Toc{595 return .{
595 .nodes = try nodes.toOwnedSlice(),596 .nodes = try nodes.toOwnedSlice(),
596 .toc = try toc_buf.toOwnedSlice(),597 .toc = try toc_buf.toOwnedSlice(),
597 .urls = urls,598 .urls = urls,
598 };599 };
599}600}
600601
601fn urlize(allocator: Allocator, input: []const u8) ![]u8 {602fn urlize(gpa: Allocator, input: []const u8) ![]u8 {
602 var buf = std.array_list.Managed(u8).init(allocator);603 var buf: ArrayList(u8) = .empty;
603 defer buf.deinit();604 defer buf.deinit(gpa);
604605
605 const out = buf.writer();
606 for (input) |c| {606 for (input) |c| {
607 switch (c) {607 switch (c) {
608 'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => {608 'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => {
609 try out.writeByte(c);609 try buf.append(gpa, c);
610 },610 },
611 ' ' => {611 ' ' => {
612 try out.writeByte('-');612 try buf.append(gpa, '-');
613 },613 },
614 else => {},614 else => {},
615 }615 }
616 }616 }
617 return try buf.toOwnedSlice();617 return try buf.toOwnedSlice(gpa);
618}618}
619619
620fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {620fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {
...@@ -626,7 +626,7 @@ fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {...@@ -626,7 +626,7 @@ fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {
626 return try buf.toOwnedSlice();626 return try buf.toOwnedSlice();
627}627}
628628
629fn writeEscaped(out: anytype, input: []const u8) !void {629fn writeEscaped(out: *Writer, input: []const u8) !void {
630 for (input) |c| {630 for (input) |c| {
631 try switch (c) {631 try switch (c) {
632 '&' => out.writeAll("&amp;"),632 '&' => out.writeAll("&amp;"),
...@@ -662,14 +662,14 @@ fn isType(name: []const u8) bool {...@@ -662,14 +662,14 @@ fn isType(name: []const u8) bool {
662 return false;662 return false;
663}663}
664664
665fn writeEscapedLines(out: anytype, text: []const u8) !void {665fn writeEscapedLines(out: *Writer, text: []const u8) !void {
666 return writeEscaped(out, text);666 return writeEscaped(out, text);
667}667}
668668
669fn tokenizeAndPrintRaw(669fn tokenizeAndPrintRaw(
670 allocator: Allocator,670 allocator: Allocator,
671 docgen_tokenizer: *Tokenizer,671 docgen_tokenizer: *Tokenizer,
672 out: anytype,672 out: *Writer,
673 source_token: Token,673 source_token: Token,
674 raw_src: []const u8,674 raw_src: []const u8,
675) !void {675) !void {
...@@ -907,14 +907,14 @@ fn tokenizeAndPrintRaw(...@@ -907,14 +907,14 @@ fn tokenizeAndPrintRaw(
907fn tokenizeAndPrint(907fn tokenizeAndPrint(
908 allocator: Allocator,908 allocator: Allocator,
909 docgen_tokenizer: *Tokenizer,909 docgen_tokenizer: *Tokenizer,
910 out: anytype,910 out: *Writer,
911 source_token: Token,911 source_token: Token,
912) !void {912) !void {
913 const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end];913 const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end];
914 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);914 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);
915}915}
916916
917fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: anytype, syntax_block: SyntaxBlock) !void {917fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock) !void {
918 const source_type = @tagName(syntax_block.source_type);918 const source_type = @tagName(syntax_block.source_type);
919919
920 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name });920 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name });
...@@ -932,7 +932,7 @@ fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: any...@@ -932,7 +932,7 @@ fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: any
932 try out.writeAll("</pre></figure>");932 try out.writeAll("</pre></figure>");
933}933}
934934
935fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void {935fn printShell(out: *Writer, shell_content: []const u8, escape: bool) !void {
936 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n");936 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n");
937 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>");937 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>");
938 var cmd_cont: bool = false;938 var cmd_cont: bool = false;
...@@ -984,7 +984,7 @@ fn genHtml(...@@ -984,7 +984,7 @@ fn genHtml(
984 tokenizer: *Tokenizer,984 tokenizer: *Tokenizer,
985 toc: *Toc,985 toc: *Toc,
986 code_dir: std.fs.Dir,986 code_dir: std.fs.Dir,
987 out: anytype,987 out: *Writer,
988) !void {988) !void {
989 for (toc.nodes) |node| {989 for (toc.nodes) |node| {
990 switch (node) {990 switch (node) {
tools/doctest.zig+16-20
...@@ -127,9 +127,9 @@ fn printOutput(...@@ -127,9 +127,9 @@ fn printOutput(
127 const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);127 const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);
128 const print = std.debug.print;128 const print = std.debug.print;
129129
130 var shell_buffer = std.array_list.Managed(u8).init(arena);130 var shell_buffer: std.Io.Writer.Allocating = .init(arena);
131 defer shell_buffer.deinit();131 defer shell_buffer.deinit();
132 var shell_out = shell_buffer.writer();132 const shell_out = &shell_buffer.writer;
133133
134 const code_name = std.fs.path.stem(input_path);134 const code_name = std.fs.path.stem(input_path);
135135
...@@ -600,7 +600,7 @@ fn printOutput(...@@ -600,7 +600,7 @@ fn printOutput(
600 }600 }
601601
602 if (!code.just_check_syntax) {602 if (!code.just_check_syntax) {
603 try printShell(out, shell_buffer.items, false);603 try printShell(out, shell_buffer.written(), false);
604 }604 }
605}605}
606606
...@@ -975,25 +975,21 @@ fn skipPrefix(line: []const u8) []const u8 {...@@ -975,25 +975,21 @@ fn skipPrefix(line: []const u8) []const u8 {
975 return line[3..];975 return line[3..];
976}976}
977977
978fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {978fn escapeHtml(gpa: Allocator, input: []const u8) ![]u8 {
979 var buf = std.array_list.Managed(u8).init(allocator);979 var allocating: Writer.Allocating = .init(gpa);
980 defer buf.deinit();980 defer allocating.deinit();
981981 try writeEscaped(&allocating.writer, input);
982 const out = buf.writer();982 return allocating.toOwnedSlice();
983 try writeEscaped(out, input);
984 return try buf.toOwnedSlice();
985}983}
986984
987fn writeEscaped(out: *Writer, input: []const u8) !void {985fn writeEscaped(w: *Writer, input: []const u8) !void {
988 for (input) |c| {986 for (input) |c| try switch (c) {
989 try switch (c) {987 '&' => w.writeAll("&amp;"),
990 '&' => out.writeAll("&amp;"),988 '<' => w.writeAll("&lt;"),
991 '<' => out.writeAll("&lt;"),989 '>' => w.writeAll("&gt;"),
992 '>' => out.writeAll("&gt;"),990 '"' => w.writeAll("&quot;"),
993 '"' => out.writeAll("&quot;"),991 else => w.writeByte(c),
994 else => out.writeByte(c),992 };
995 };
996 }
997}993}
998994
999fn termColor(allocator: Allocator, input: []const u8) ![]u8 {995fn termColor(allocator: Allocator, input: []const u8) ![]u8 {