zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 53e971226dcc2fd0cb53e3442399b8724700b3e5 (tree)
parent 51a4861a081eea5d9bfd590c63f4a4506305f941
Author: Loris Cro <kappaloris@gmail.com>
Date:   Thu, 18 Aug 2022 18:02:19 +0200

autodoc: minor pr cleanup

Diffstat:
Mlib/docs/main.js | 4++--
Msrc/Autodoc.zig | 33++++++++++++++++++---------------
Dsrc/Docgen.zig | 425-------------------------------------------------------------------------------
Asrc/autodoc/render_source.zig | 424+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 444 insertions(+), 442 deletions(-)

diff --git a/lib/docs/main.js b/lib/docs/main.js @@ -51,7 +51,7 @@ var zigAnalysis; const domHdrName = document.getElementById("hdrName"); const domHelpModal = document.getElementById("helpModal"); const domSearchPlaceholder = document.getElementById("searchPlaceholder"); - const sourceFileUrlTemplate = "src-viewer/{{file}}#L{{line}}" + const sourceFileUrlTemplate = "src/{{file}}#L{{line}}" const domLangRefLink = document.getElementById("langRefLink"); let lineCounter = 1; @@ -989,7 +989,7 @@ var zigAnalysis; "switch(" + cond + ") {" + - '<a href="/src-viewer/' + + '<a href="/src/' + file_name + "#L" + line + diff --git a/src/Autodoc.zig b/src/Autodoc.zig @@ -9,7 +9,7 @@ const Package = @import("Package.zig"); const Zir = @import("Zir.zig"); const Ref = Zir.Inst.Ref; const log = std.log.scoped(.autodoc); -const Docgen = @import("Docgen.zig"); +const Docgen = @import("autodoc/render_source.zig"); module: *Module, doc_location: Compilation.EmitLoc, @@ -243,6 +243,7 @@ pub fn generateZirData(self: *Autodoc) !void { try d.handle.openDir(self.doc_location.basename, .{}) else try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{}); + { const data_js_f = try output_dir.createFile("data.js", .{}); defer data_js_f.close(); @@ -267,25 +268,27 @@ pub fn generateZirData(self: *Autodoc) !void { try buffer.flush(); } - output_dir.makeDir("src-viewer") catch |e| switch (e) { - error.PathAlreadyExists => {}, - else => |err| return err, - }; - const html_dir = try output_dir.openDir("src-viewer", .{}); + { + output_dir.makeDir("src") catch |e| switch (e) { + error.PathAlreadyExists => {}, + else => |err| return err, + }; + const html_dir = try output_dir.openDir("src", .{}); - var files_iterator = self.files.iterator(); + var files_iterator = self.files.iterator(); - while (files_iterator.next()) |entry| { - const new_html_path = entry.key_ptr.*.sub_file_path; + while (files_iterator.next()) |entry| { + const new_html_path = entry.key_ptr.*.sub_file_path; - const html_file = try createFromPath(html_dir, new_html_path); - defer html_file.close(); - var buffer = std.io.bufferedWriter(html_file.writer()); + const html_file = try createFromPath(html_dir, new_html_path); + defer html_file.close(); + var buffer = std.io.bufferedWriter(html_file.writer()); - const out = buffer.writer(); + const out = buffer.writer(); - try Docgen.genHtml(self.module.gpa, entry.key_ptr.*, out); - try buffer.flush(); + try Docgen.genHtml(self.module.gpa, entry.key_ptr.*, out); + try buffer.flush(); + } } // copy main.js, index.html diff --git a/src/Docgen.zig b/src/Docgen.zig @@ -1,425 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const io = std.io; -const fs = std.fs; -const process = std.process; -const ChildProcess = std.ChildProcess; -const Progress = std.Progress; -const print = std.debug.print; -const mem = std.mem; -const testing = std.testing; -const Allocator = std.mem.Allocator; -const Module = @import("Module.zig"); - -pub fn genHtml( - allocator: Allocator, - src: *Module.File, - out: anytype, -) !void { - try out.writeAll( - \\<!doctype html> - \\<html lang="en"> - \\<head> - \\ <meta charset="utf-8"> - \\ <meta name="viewport" content="width=device-width, initial-scale=1.0"> - ); - try out.print(" <title>{s} - source view</title>\n", .{src.sub_file_path}); - try out.writeAll( - \\ <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg=="/> - \\ <style> - \\ body{ - \\ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; - \\ margin: 0; - \\ line-height: 1.5; - \\ } - \\ - \\ @media screen and (min-width: 1025px) { - \\ pre > code { - \\ display: block; - \\ overflow: auto; - \\ line-height: normal; - \\ margin: 0em; - \\ } - \\ .tok-kw { - \\ color: #333; - \\ font-weight: bold; - \\ } - \\ .tok-str { - \\ color: #d14; - \\ } - \\ .tok-builtin { - \\ color: #005C7A; - \\ } - \\ .tok-comment { - \\ color: #545454; - \\ font-style: italic; - \\ } - \\ .tok-fn { - \\ color: #900; - \\ font-weight: bold; - \\ } - \\ .tok-null { - \\ color: #005C5C; - \\ } - \\ .tok-number { - \\ color: #005C5C; - \\ } - \\ .tok-type { - \\ color: #458; - \\ font-weight: bold; - \\ } - \\ pre { - \\ counter-reset: line; - \\ } - \\ pre .line:before { - \\ counter-increment: line; - \\ content: counter(line); - \\ display: inline-block; - \\ padding-right: 1em; - \\ width: 2em; - \\ text-align: right; - \\ color: #999; - \\ } - \\ - \\ @media (prefers-color-scheme: dark) { - \\ body{ - \\ background:#222; - \\ color: #ccc; - \\ } - \\ pre > code { - \\ color: #ccc; - \\ background: #222; - \\ border: unset; - \\ } - \\ .tok-kw { - \\ color: #eee; - \\ } - \\ .tok-str { - \\ color: #2e5; - \\ } - \\ .tok-builtin { - \\ color: #ff894c; - \\ } - \\ .tok-comment { - \\ color: #aa7; - \\ } - \\ .tok-fn { - \\ color: #B1A0F8; - \\ } - \\ .tok-null { - \\ color: #ff8080; - \\ } - \\ .tok-number { - \\ color: #ff8080; - \\ } - \\ .tok-type { - \\ color: #68f; - \\ } - \\ } - \\ </style> - \\</head> - \\<body> - \\ - ); - - const source = try src.getSource(allocator); - try tokenizeAndPrintRaw(allocator, out, source.bytes); - try out.writeAll( - \\</body> - \\</html> - ); -} - -const start_line = "<span class=\"line\" id=\"L{d}\">"; -const end_line = "</span>\n"; - -var line_counter: usize = 1; - -pub fn tokenizeAndPrintRaw( - allocator: Allocator, - out: anytype, - raw_src: [:0]const u8, -) !void { - const src = try allocator.dupeZ(u8, raw_src); - defer allocator.free(src); - - line_counter = 1; - - try out.print("<pre><code>" ++ start_line, .{line_counter}); - var tokenizer = std.zig.Tokenizer.init(src); - var index: usize = 0; - var next_tok_is_fn = false; - while (true) { - const prev_tok_was_fn = next_tok_is_fn; - next_tok_is_fn = false; - - const token = tokenizer.next(); - if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| { - // render one comment - const comment_start = index + comment_start_off; - const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n"); - const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start; - - try writeEscapedLines(out, src[index..comment_start]); - try out.writeAll("<span class=\"tok-comment\">"); - try writeEscaped(out, src[comment_start..comment_end]); - try out.writeAll("</span>\n"); - index = comment_end; - tokenizer.index = index; - continue; - } - - try writeEscapedLines(out, src[index..token.loc.start]); - switch (token.tag) { - .eof => break, - - .keyword_addrspace, - .keyword_align, - .keyword_and, - .keyword_asm, - .keyword_async, - .keyword_await, - .keyword_break, - .keyword_catch, - .keyword_comptime, - .keyword_const, - .keyword_continue, - .keyword_defer, - .keyword_else, - .keyword_enum, - .keyword_errdefer, - .keyword_error, - .keyword_export, - .keyword_extern, - .keyword_for, - .keyword_if, - .keyword_inline, - .keyword_noalias, - .keyword_noinline, - .keyword_nosuspend, - .keyword_opaque, - .keyword_or, - .keyword_orelse, - .keyword_packed, - .keyword_anyframe, - .keyword_pub, - .keyword_resume, - .keyword_return, - .keyword_linksection, - .keyword_callconv, - .keyword_struct, - .keyword_suspend, - .keyword_switch, - .keyword_test, - .keyword_threadlocal, - .keyword_try, - .keyword_union, - .keyword_unreachable, - .keyword_usingnamespace, - .keyword_var, - .keyword_volatile, - .keyword_allowzero, - .keyword_while, - .keyword_anytype, - => { - try out.writeAll("<span class=\"tok-kw\">"); - try writeEscaped(out, src[token.loc.start..token.loc.end]); - try out.writeAll("</span>"); - }, - - .keyword_fn => { - try out.writeAll("<span class=\"tok-kw\">"); - try writeEscaped(out, src[token.loc.start..token.loc.end]); - try out.writeAll("</span>"); - next_tok_is_fn = true; - }, - - .string_literal, - .char_literal, - => { - try out.writeAll("<span class=\"tok-str\">"); - try writeEscaped(out, src[token.loc.start..token.loc.end]); - try out.writeAll("</span>"); - }, - - .multiline_string_literal_line => { - if (src[token.loc.end - 1] == '\n') { - try out.writeAll("<span class=\"tok-str\">"); - try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]); - line_counter += 1; - try out.print("</span>" ++ end_line ++ "\n" ++ start_line, .{line_counter}); - } else { - try out.writeAll("<span class=\"tok-str\">"); - try writeEscaped(out, src[token.loc.start..token.loc.end]); - try out.writeAll("</span>"); - } - }, - - .builtin => { - try out.writeAll("<span class=\"tok-builtin\">"); - try writeEscaped(out, src[token.loc.start..token.loc.end]); - try out.writeAll("</span>"); - }, - - .doc_comment, - .container_doc_comment, - => { - try out.writeAll("<span class=\"tok-comment\">"); - try writeEscaped(out, src[token.loc.start..token.loc.end]); - try out.writeAll("</span>"); - }, - - .identifier => { - const tok_bytes = src[token.loc.start..token.loc.end]; - if (mem.eql(u8, tok_bytes, "undefined") or - mem.eql(u8, tok_bytes, "null") or - mem.eql(u8, tok_bytes, "true") or - mem.eql(u8, tok_bytes, "false")) - { - try out.writeAll("<span class=\"tok-null\">"); - try writeEscaped(out, tok_bytes); - try out.writeAll("</span>"); - } else if (prev_tok_was_fn) { - try out.writeAll("<span class=\"tok-fn\">"); - try writeEscaped(out, tok_bytes); - try out.writeAll("</span>"); - } else { - const is_int = blk: { - if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u') - break :blk false; - var i = token.loc.start + 1; - if (i == token.loc.end) - break :blk false; - while (i != token.loc.end) : (i += 1) { - if (src[i] < '0' or src[i] > '9') - break :blk false; - } - break :blk true; - }; - if (is_int or isType(tok_bytes)) { - try out.writeAll("<span class=\"tok-type\">"); - try writeEscaped(out, tok_bytes); - try out.writeAll("</span>"); - } else { - try writeEscaped(out, tok_bytes); - } - } - }, - - .integer_literal, - .float_literal, - => { - try out.writeAll("<span class=\"tok-number\">"); - try writeEscaped(out, src[token.loc.start..token.loc.end]); - try out.writeAll("</span>"); - }, - - .bang, - .pipe, - .pipe_pipe, - .pipe_equal, - .equal, - .equal_equal, - .equal_angle_bracket_right, - .bang_equal, - .l_paren, - .r_paren, - .semicolon, - .percent, - .percent_equal, - .l_brace, - .r_brace, - .l_bracket, - .r_bracket, - .period, - .period_asterisk, - .ellipsis2, - .ellipsis3, - .caret, - .caret_equal, - .plus, - .plus_plus, - .plus_equal, - .plus_percent, - .plus_percent_equal, - .plus_pipe, - .plus_pipe_equal, - .minus, - .minus_equal, - .minus_percent, - .minus_percent_equal, - .minus_pipe, - .minus_pipe_equal, - .asterisk, - .asterisk_equal, - .asterisk_asterisk, - .asterisk_percent, - .asterisk_percent_equal, - .asterisk_pipe, - .asterisk_pipe_equal, - .arrow, - .colon, - .slash, - .slash_equal, - .comma, - .ampersand, - .ampersand_equal, - .question_mark, - .angle_bracket_left, - .angle_bracket_left_equal, - .angle_bracket_angle_bracket_left, - .angle_bracket_angle_bracket_left_equal, - .angle_bracket_angle_bracket_left_pipe, - .angle_bracket_angle_bracket_left_pipe_equal, - .angle_bracket_right, - .angle_bracket_right_equal, - .angle_bracket_angle_bracket_right, - .angle_bracket_angle_bracket_right_equal, - .tilde, - => try writeEscaped(out, src[token.loc.start..token.loc.end]), - - .invalid, .invalid_periodasterisks => return error.ParseError, - } - index = token.loc.end; - } - try out.writeAll(end_line ++ "</code></pre>"); -} - -fn writeEscapedLines(out: anytype, text: []const u8) !void { - for (text) |char| { - if (char == '\n') { - try out.writeAll(end_line); - line_counter += 1; - try out.print(start_line, .{line_counter}); - } else { - try writeEscaped(out, &[_]u8{char}); - } - } -} - -fn writeEscaped(out: anytype, input: []const u8) !void { - for (input) |c| { - try switch (c) { - '&' => out.writeAll("&amp;"), - '<' => out.writeAll("&lt;"), - '>' => out.writeAll("&gt;"), - '"' => out.writeAll("&quot;"), - else => out.writeByte(c), - }; - } -} - -const builtin_types = [_][]const u8{ - "f16", "f32", "f64", "f128", "c_longdouble", "c_short", - "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong", - "c_ulonglong", "c_char", "anyopaque", "void", "bool", "isize", - "usize", "noreturn", "type", "anyerror", "comptime_int", "comptime_float", -}; - -fn isType(name: []const u8) bool { - for (builtin_types) |t| { - if (mem.eql(u8, t, name)) - return true; - } - return false; -} diff --git a/src/autodoc/render_source.zig b/src/autodoc/render_source.zig @@ -0,0 +1,424 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const io = std.io; +const fs = std.fs; +const process = std.process; +const ChildProcess = std.ChildProcess; +const Progress = std.Progress; +const print = std.debug.print; +const mem = std.mem; +const testing = std.testing; +const Allocator = std.mem.Allocator; +const Module = @import("../Module.zig"); + +pub fn genHtml( + allocator: Allocator, + src: *Module.File, + out: anytype, +) !void { + try out.writeAll( + \\<!doctype html> + \\<html lang="en"> + \\<head> + \\ <meta charset="utf-8"> + \\ <meta name="viewport" content="width=device-width, initial-scale=1.0"> + ); + try out.print(" <title>{s} - source view</title>\n", .{src.sub_file_path}); + try out.writeAll( + \\ <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg=="/> + \\ <style> + \\ body{ + \\ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; + \\ margin: 0; + \\ line-height: 1.5; + \\ } + \\ + \\ pre > code { + \\ display: block; + \\ overflow: auto; + \\ line-height: normal; + \\ margin: 0em; + \\ } + \\ .tok-kw { + \\ color: #333; + \\ font-weight: bold; + \\ } + \\ .tok-str { + \\ color: #d14; + \\ } + \\ .tok-builtin { + \\ color: #005C7A; + \\ } + \\ .tok-comment { + \\ color: #545454; + \\ font-style: italic; + \\ } + \\ .tok-fn { + \\ color: #900; + \\ font-weight: bold; + \\ } + \\ .tok-null { + \\ color: #005C5C; + \\ } + \\ .tok-number { + \\ color: #005C5C; + \\ } + \\ .tok-type { + \\ color: #458; + \\ font-weight: bold; + \\ } + \\ pre { + \\ counter-reset: line; + \\ } + \\ pre .line:before { + \\ counter-increment: line; + \\ content: counter(line); + \\ display: inline-block; + \\ padding-right: 1em; + \\ width: 2em; + \\ text-align: right; + \\ color: #999; + \\ } + \\ + \\ @media (prefers-color-scheme: dark) { + \\ body{ + \\ background:#222; + \\ color: #ccc; + \\ } + \\ pre > code { + \\ color: #ccc; + \\ background: #222; + \\ border: unset; + \\ } + \\ .tok-kw { + \\ color: #eee; + \\ } + \\ .tok-str { + \\ color: #2e5; + \\ } + \\ .tok-builtin { + \\ color: #ff894c; + \\ } + \\ .tok-comment { + \\ color: #aa7; + \\ } + \\ .tok-fn { + \\ color: #B1A0F8; + \\ } + \\ .tok-null { + \\ color: #ff8080; + \\ } + \\ .tok-number { + \\ color: #ff8080; + \\ } + \\ .tok-type { + \\ color: #68f; + \\ } + \\ } + \\ </style> + \\</head> + \\<body> + \\ + ); + + const source = try src.getSource(allocator); + try tokenizeAndPrintRaw(allocator, out, source.bytes); + try out.writeAll( + \\</body> + \\</html> + ); +} + +const start_line = "<span class=\"line\" id=\"L{d}\">"; +const end_line = "</span>\n"; + +var line_counter: usize = 1; + +pub fn tokenizeAndPrintRaw( + allocator: Allocator, + out: anytype, + raw_src: [:0]const u8, +) !void { + const src = try allocator.dupeZ(u8, raw_src); + defer allocator.free(src); + + line_counter = 1; + + try out.print("<pre><code>" ++ start_line, .{line_counter}); + var tokenizer = std.zig.Tokenizer.init(src); + var index: usize = 0; + var next_tok_is_fn = false; + while (true) { + const prev_tok_was_fn = next_tok_is_fn; + next_tok_is_fn = false; + + const token = tokenizer.next(); + if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| { + // render one comment + const comment_start = index + comment_start_off; + const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n"); + const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start; + + try writeEscapedLines(out, src[index..comment_start]); + try out.writeAll("<span class=\"tok-comment\">"); + try writeEscaped(out, src[comment_start..comment_end]); + try out.writeAll("</span>\n"); + index = comment_end; + tokenizer.index = index; + continue; + } + + try writeEscapedLines(out, src[index..token.loc.start]); + switch (token.tag) { + .eof => break, + + .keyword_addrspace, + .keyword_align, + .keyword_and, + .keyword_asm, + .keyword_async, + .keyword_await, + .keyword_break, + .keyword_catch, + .keyword_comptime, + .keyword_const, + .keyword_continue, + .keyword_defer, + .keyword_else, + .keyword_enum, + .keyword_errdefer, + .keyword_error, + .keyword_export, + .keyword_extern, + .keyword_for, + .keyword_if, + .keyword_inline, + .keyword_noalias, + .keyword_noinline, + .keyword_nosuspend, + .keyword_opaque, + .keyword_or, + .keyword_orelse, + .keyword_packed, + .keyword_anyframe, + .keyword_pub, + .keyword_resume, + .keyword_return, + .keyword_linksection, + .keyword_callconv, + .keyword_struct, + .keyword_suspend, + .keyword_switch, + .keyword_test, + .keyword_threadlocal, + .keyword_try, + .keyword_union, + .keyword_unreachable, + .keyword_usingnamespace, + .keyword_var, + .keyword_volatile, + .keyword_allowzero, + .keyword_while, + .keyword_anytype, + => { + try out.writeAll("<span class=\"tok-kw\">"); + try writeEscaped(out, src[token.loc.start..token.loc.end]); + try out.writeAll("</span>"); + }, + + .keyword_fn => { + try out.writeAll("<span class=\"tok-kw\">"); + try writeEscaped(out, src[token.loc.start..token.loc.end]); + try out.writeAll("</span>"); + next_tok_is_fn = true; + }, + + .string_literal, + .char_literal, + => { + try out.writeAll("<span class=\"tok-str\">"); + try writeEscaped(out, src[token.loc.start..token.loc.end]); + try out.writeAll("</span>"); + }, + + .multiline_string_literal_line => { + if (src[token.loc.end - 1] == '\n') { + try out.writeAll("<span class=\"tok-str\">"); + try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]); + line_counter += 1; + try out.print("</span>" ++ end_line ++ "\n" ++ start_line, .{line_counter}); + } else { + try out.writeAll("<span class=\"tok-str\">"); + try writeEscaped(out, src[token.loc.start..token.loc.end]); + try out.writeAll("</span>"); + } + }, + + .builtin => { + try out.writeAll("<span class=\"tok-builtin\">"); + try writeEscaped(out, src[token.loc.start..token.loc.end]); + try out.writeAll("</span>"); + }, + + .doc_comment, + .container_doc_comment, + => { + try out.writeAll("<span class=\"tok-comment\">"); + try writeEscaped(out, src[token.loc.start..token.loc.end]); + try out.writeAll("</span>"); + }, + + .identifier => { + const tok_bytes = src[token.loc.start..token.loc.end]; + if (mem.eql(u8, tok_bytes, "undefined") or + mem.eql(u8, tok_bytes, "null") or + mem.eql(u8, tok_bytes, "true") or + mem.eql(u8, tok_bytes, "false")) + { + try out.writeAll("<span class=\"tok-null\">"); + try writeEscaped(out, tok_bytes); + try out.writeAll("</span>"); + } else if (prev_tok_was_fn) { + try out.writeAll("<span class=\"tok-fn\">"); + try writeEscaped(out, tok_bytes); + try out.writeAll("</span>"); + } else { + const is_int = blk: { + if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u') + break :blk false; + var i = token.loc.start + 1; + if (i == token.loc.end) + break :blk false; + while (i != token.loc.end) : (i += 1) { + if (src[i] < '0' or src[i] > '9') + break :blk false; + } + break :blk true; + }; + if (is_int or isType(tok_bytes)) { + try out.writeAll("<span class=\"tok-type\">"); + try writeEscaped(out, tok_bytes); + try out.writeAll("</span>"); + } else { + try writeEscaped(out, tok_bytes); + } + } + }, + + .integer_literal, + .float_literal, + => { + try out.writeAll("<span class=\"tok-number\">"); + try writeEscaped(out, src[token.loc.start..token.loc.end]); + try out.writeAll("</span>"); + }, + + .bang, + .pipe, + .pipe_pipe, + .pipe_equal, + .equal, + .equal_equal, + .equal_angle_bracket_right, + .bang_equal, + .l_paren, + .r_paren, + .semicolon, + .percent, + .percent_equal, + .l_brace, + .r_brace, + .l_bracket, + .r_bracket, + .period, + .period_asterisk, + .ellipsis2, + .ellipsis3, + .caret, + .caret_equal, + .plus, + .plus_plus, + .plus_equal, + .plus_percent, + .plus_percent_equal, + .plus_pipe, + .plus_pipe_equal, + .minus, + .minus_equal, + .minus_percent, + .minus_percent_equal, + .minus_pipe, + .minus_pipe_equal, + .asterisk, + .asterisk_equal, + .asterisk_asterisk, + .asterisk_percent, + .asterisk_percent_equal, + .asterisk_pipe, + .asterisk_pipe_equal, + .arrow, + .colon, + .slash, + .slash_equal, + .comma, + .ampersand, + .ampersand_equal, + .question_mark, + .angle_bracket_left, + .angle_bracket_left_equal, + .angle_bracket_angle_bracket_left, + .angle_bracket_angle_bracket_left_equal, + .angle_bracket_angle_bracket_left_pipe, + .angle_bracket_angle_bracket_left_pipe_equal, + .angle_bracket_right, + .angle_bracket_right_equal, + .angle_bracket_angle_bracket_right, + .angle_bracket_angle_bracket_right_equal, + .tilde, + => try writeEscaped(out, src[token.loc.start..token.loc.end]), + + .invalid, .invalid_periodasterisks => return error.ParseError, + } + index = token.loc.end; + } + try out.writeAll(end_line ++ "</code></pre>"); +} + +fn writeEscapedLines(out: anytype, text: []const u8) !void { + for (text) |char| { + if (char == '\n') { + try out.writeAll(end_line); + line_counter += 1; + try out.print(start_line, .{line_counter}); + } else { + try writeEscaped(out, &[_]u8{char}); + } + } +} + +fn writeEscaped(out: anytype, input: []const u8) !void { + for (input) |c| { + try switch (c) { + '&' => out.writeAll("&amp;"), + '<' => out.writeAll("&lt;"), + '>' => out.writeAll("&gt;"), + '"' => out.writeAll("&quot;"), + else => out.writeByte(c), + }; + } +} + +const builtin_types = [_][]const u8{ + "f16", "f32", "f64", "f128", "c_longdouble", "c_short", + "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong", + "c_ulonglong", "c_char", "anyopaque", "void", "bool", "isize", + "usize", "noreturn", "type", "anyerror", "comptime_int", "comptime_float", +}; + +fn isType(name: []const u8) bool { + for (builtin_types) |t| { + if (mem.eql(u8, t, name)) + return true; + } + return false; +}