authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-08-18 18:02:19+02:00
committergravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-08-18 18:02:19+02:00
log53e971226dcc2fd0cb53e3442399b8724700b3e5
tree2d23cad4a85858f3a45234ea431be2eb3b746f2c
parent51a4861a081eea5d9bfd590c63f4a4506305f941

autodoc: minor pr cleanup


4 files changed, 444 insertions(+), 442 deletions(-)

lib/docs/main.js+2-2
...@@ -51,7 +51,7 @@ var zigAnalysis;...@@ -51,7 +51,7 @@ var zigAnalysis;
51 const domHdrName = document.getElementById("hdrName");51 const domHdrName = document.getElementById("hdrName");
52 const domHelpModal = document.getElementById("helpModal");52 const domHelpModal = document.getElementById("helpModal");
53 const domSearchPlaceholder = document.getElementById("searchPlaceholder");53 const domSearchPlaceholder = document.getElementById("searchPlaceholder");
54 const sourceFileUrlTemplate = "src-viewer/{{file}}#L{{line}}"54 const sourceFileUrlTemplate = "src/{{file}}#L{{line}}"
55 const domLangRefLink = document.getElementById("langRefLink");55 const domLangRefLink = document.getElementById("langRefLink");
5656
57 let lineCounter = 1;57 let lineCounter = 1;
...@@ -989,7 +989,7 @@ var zigAnalysis;...@@ -989,7 +989,7 @@ var zigAnalysis;
989 "switch(" +989 "switch(" +
990 cond +990 cond +
991 ") {" +991 ") {" +
992 '<a href="/src-viewer/' +992 '<a href="/src/' +
993 file_name +993 file_name +
994 "#L" +994 "#L" +
995 line +995 line +
src/Autodoc.zig+18-15
...@@ -9,7 +9,7 @@ const Package = @import("Package.zig");...@@ -9,7 +9,7 @@ const Package = @import("Package.zig");
9const Zir = @import("Zir.zig");9const Zir = @import("Zir.zig");
10const Ref = Zir.Inst.Ref;10const Ref = Zir.Inst.Ref;
11const log = std.log.scoped(.autodoc);11const log = std.log.scoped(.autodoc);
12const Docgen = @import("Docgen.zig");12const Docgen = @import("autodoc/render_source.zig");
1313
14module: *Module,14module: *Module,
15doc_location: Compilation.EmitLoc,15doc_location: Compilation.EmitLoc,
...@@ -243,6 +243,7 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -243,6 +243,7 @@ pub fn generateZirData(self: *Autodoc) !void {
243 try d.handle.openDir(self.doc_location.basename, .{})243 try d.handle.openDir(self.doc_location.basename, .{})
244 else244 else
245 try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{});245 try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{});
246
246 {247 {
247 const data_js_f = try output_dir.createFile("data.js", .{});248 const data_js_f = try output_dir.createFile("data.js", .{});
248 defer data_js_f.close();249 defer data_js_f.close();
...@@ -267,25 +268,27 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -267,25 +268,27 @@ pub fn generateZirData(self: *Autodoc) !void {
267 try buffer.flush();268 try buffer.flush();
268 }269 }
269270
270 output_dir.makeDir("src-viewer") catch |e| switch (e) {271 {
271 error.PathAlreadyExists => {},272 output_dir.makeDir("src") catch |e| switch (e) {
272 else => |err| return err,273 error.PathAlreadyExists => {},
273 };274 else => |err| return err,
274 const html_dir = try output_dir.openDir("src-viewer", .{});275 };
276 const html_dir = try output_dir.openDir("src", .{});
275277
276 var files_iterator = self.files.iterator();278 var files_iterator = self.files.iterator();
277279
278 while (files_iterator.next()) |entry| {280 while (files_iterator.next()) |entry| {
279 const new_html_path = entry.key_ptr.*.sub_file_path;281 const new_html_path = entry.key_ptr.*.sub_file_path;
280282
281 const html_file = try createFromPath(html_dir, new_html_path);283 const html_file = try createFromPath(html_dir, new_html_path);
282 defer html_file.close();284 defer html_file.close();
283 var buffer = std.io.bufferedWriter(html_file.writer());285 var buffer = std.io.bufferedWriter(html_file.writer());
284286
285 const out = buffer.writer();287 const out = buffer.writer();
286288
287 try Docgen.genHtml(self.module.gpa, entry.key_ptr.*, out);289 try Docgen.genHtml(self.module.gpa, entry.key_ptr.*, out);
288 try buffer.flush();290 try buffer.flush();
291 }
289 }292 }
290293
291 // copy main.js, index.html294 // copy main.js, index.html
src/Docgen.zig deleted-425
...@@ -1,425 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const io = std.io;
4const fs = std.fs;
5const process = std.process;
6const ChildProcess = std.ChildProcess;
7const Progress = std.Progress;
8const print = std.debug.print;
9const mem = std.mem;
10const testing = std.testing;
11const Allocator = std.mem.Allocator;
12const Module = @import("Module.zig");
13
14pub fn genHtml(
15 allocator: Allocator,
16 src: *Module.File,
17 out: anytype,
18) !void {
19 try out.writeAll(
20 \\<!doctype html>
21 \\<html lang="en">
22 \\<head>
23 \\ <meta charset="utf-8">
24 \\ <meta name="viewport" content="width=device-width, initial-scale=1.0">
25 );
26 try out.print(" <title>{s} - source view</title>\n", .{src.sub_file_path});
27 try out.writeAll(
28 \\ <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg=="/>
29 \\ <style>
30 \\ body{
31 \\ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
32 \\ margin: 0;
33 \\ line-height: 1.5;
34 \\ }
35 \\
36 \\ @media screen and (min-width: 1025px) {
37 \\ pre > code {
38 \\ display: block;
39 \\ overflow: auto;
40 \\ line-height: normal;
41 \\ margin: 0em;
42 \\ }
43 \\ .tok-kw {
44 \\ color: #333;
45 \\ font-weight: bold;
46 \\ }
47 \\ .tok-str {
48 \\ color: #d14;
49 \\ }
50 \\ .tok-builtin {
51 \\ color: #005C7A;
52 \\ }
53 \\ .tok-comment {
54 \\ color: #545454;
55 \\ font-style: italic;
56 \\ }
57 \\ .tok-fn {
58 \\ color: #900;
59 \\ font-weight: bold;
60 \\ }
61 \\ .tok-null {
62 \\ color: #005C5C;
63 \\ }
64 \\ .tok-number {
65 \\ color: #005C5C;
66 \\ }
67 \\ .tok-type {
68 \\ color: #458;
69 \\ font-weight: bold;
70 \\ }
71 \\ pre {
72 \\ counter-reset: line;
73 \\ }
74 \\ pre .line:before {
75 \\ counter-increment: line;
76 \\ content: counter(line);
77 \\ display: inline-block;
78 \\ padding-right: 1em;
79 \\ width: 2em;
80 \\ text-align: right;
81 \\ color: #999;
82 \\ }
83 \\
84 \\ @media (prefers-color-scheme: dark) {
85 \\ body{
86 \\ background:#222;
87 \\ color: #ccc;
88 \\ }
89 \\ pre > code {
90 \\ color: #ccc;
91 \\ background: #222;
92 \\ border: unset;
93 \\ }
94 \\ .tok-kw {
95 \\ color: #eee;
96 \\ }
97 \\ .tok-str {
98 \\ color: #2e5;
99 \\ }
100 \\ .tok-builtin {
101 \\ color: #ff894c;
102 \\ }
103 \\ .tok-comment {
104 \\ color: #aa7;
105 \\ }
106 \\ .tok-fn {
107 \\ color: #B1A0F8;
108 \\ }
109 \\ .tok-null {
110 \\ color: #ff8080;
111 \\ }
112 \\ .tok-number {
113 \\ color: #ff8080;
114 \\ }
115 \\ .tok-type {
116 \\ color: #68f;
117 \\ }
118 \\ }
119 \\ </style>
120 \\</head>
121 \\<body>
122 \\
123 );
124
125 const source = try src.getSource(allocator);
126 try tokenizeAndPrintRaw(allocator, out, source.bytes);
127 try out.writeAll(
128 \\</body>
129 \\</html>
130 );
131}
132
133const start_line = "<span class=\"line\" id=\"L{d}\">";
134const end_line = "</span>\n";
135
136var line_counter: usize = 1;
137
138pub fn tokenizeAndPrintRaw(
139 allocator: Allocator,
140 out: anytype,
141 raw_src: [:0]const u8,
142) !void {
143 const src = try allocator.dupeZ(u8, raw_src);
144 defer allocator.free(src);
145
146 line_counter = 1;
147
148 try out.print("<pre><code>" ++ start_line, .{line_counter});
149 var tokenizer = std.zig.Tokenizer.init(src);
150 var index: usize = 0;
151 var next_tok_is_fn = false;
152 while (true) {
153 const prev_tok_was_fn = next_tok_is_fn;
154 next_tok_is_fn = false;
155
156 const token = tokenizer.next();
157 if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| {
158 // render one comment
159 const comment_start = index + comment_start_off;
160 const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n");
161 const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start;
162
163 try writeEscapedLines(out, src[index..comment_start]);
164 try out.writeAll("<span class=\"tok-comment\">");
165 try writeEscaped(out, src[comment_start..comment_end]);
166 try out.writeAll("</span>\n");
167 index = comment_end;
168 tokenizer.index = index;
169 continue;
170 }
171
172 try writeEscapedLines(out, src[index..token.loc.start]);
173 switch (token.tag) {
174 .eof => break,
175
176 .keyword_addrspace,
177 .keyword_align,
178 .keyword_and,
179 .keyword_asm,
180 .keyword_async,
181 .keyword_await,
182 .keyword_break,
183 .keyword_catch,
184 .keyword_comptime,
185 .keyword_const,
186 .keyword_continue,
187 .keyword_defer,
188 .keyword_else,
189 .keyword_enum,
190 .keyword_errdefer,
191 .keyword_error,
192 .keyword_export,
193 .keyword_extern,
194 .keyword_for,
195 .keyword_if,
196 .keyword_inline,
197 .keyword_noalias,
198 .keyword_noinline,
199 .keyword_nosuspend,
200 .keyword_opaque,
201 .keyword_or,
202 .keyword_orelse,
203 .keyword_packed,
204 .keyword_anyframe,
205 .keyword_pub,
206 .keyword_resume,
207 .keyword_return,
208 .keyword_linksection,
209 .keyword_callconv,
210 .keyword_struct,
211 .keyword_suspend,
212 .keyword_switch,
213 .keyword_test,
214 .keyword_threadlocal,
215 .keyword_try,
216 .keyword_union,
217 .keyword_unreachable,
218 .keyword_usingnamespace,
219 .keyword_var,
220 .keyword_volatile,
221 .keyword_allowzero,
222 .keyword_while,
223 .keyword_anytype,
224 => {
225 try out.writeAll("<span class=\"tok-kw\">");
226 try writeEscaped(out, src[token.loc.start..token.loc.end]);
227 try out.writeAll("</span>");
228 },
229
230 .keyword_fn => {
231 try out.writeAll("<span class=\"tok-kw\">");
232 try writeEscaped(out, src[token.loc.start..token.loc.end]);
233 try out.writeAll("</span>");
234 next_tok_is_fn = true;
235 },
236
237 .string_literal,
238 .char_literal,
239 => {
240 try out.writeAll("<span class=\"tok-str\">");
241 try writeEscaped(out, src[token.loc.start..token.loc.end]);
242 try out.writeAll("</span>");
243 },
244
245 .multiline_string_literal_line => {
246 if (src[token.loc.end - 1] == '\n') {
247 try out.writeAll("<span class=\"tok-str\">");
248 try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]);
249 line_counter += 1;
250 try out.print("</span>" ++ end_line ++ "\n" ++ start_line, .{line_counter});
251 } else {
252 try out.writeAll("<span class=\"tok-str\">");
253 try writeEscaped(out, src[token.loc.start..token.loc.end]);
254 try out.writeAll("</span>");
255 }
256 },
257
258 .builtin => {
259 try out.writeAll("<span class=\"tok-builtin\">");
260 try writeEscaped(out, src[token.loc.start..token.loc.end]);
261 try out.writeAll("</span>");
262 },
263
264 .doc_comment,
265 .container_doc_comment,
266 => {
267 try out.writeAll("<span class=\"tok-comment\">");
268 try writeEscaped(out, src[token.loc.start..token.loc.end]);
269 try out.writeAll("</span>");
270 },
271
272 .identifier => {
273 const tok_bytes = src[token.loc.start..token.loc.end];
274 if (mem.eql(u8, tok_bytes, "undefined") or
275 mem.eql(u8, tok_bytes, "null") or
276 mem.eql(u8, tok_bytes, "true") or
277 mem.eql(u8, tok_bytes, "false"))
278 {
279 try out.writeAll("<span class=\"tok-null\">");
280 try writeEscaped(out, tok_bytes);
281 try out.writeAll("</span>");
282 } else if (prev_tok_was_fn) {
283 try out.writeAll("<span class=\"tok-fn\">");
284 try writeEscaped(out, tok_bytes);
285 try out.writeAll("</span>");
286 } else {
287 const is_int = blk: {
288 if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u')
289 break :blk false;
290 var i = token.loc.start + 1;
291 if (i == token.loc.end)
292 break :blk false;
293 while (i != token.loc.end) : (i += 1) {
294 if (src[i] < '0' or src[i] > '9')
295 break :blk false;
296 }
297 break :blk true;
298 };
299 if (is_int or isType(tok_bytes)) {
300 try out.writeAll("<span class=\"tok-type\">");
301 try writeEscaped(out, tok_bytes);
302 try out.writeAll("</span>");
303 } else {
304 try writeEscaped(out, tok_bytes);
305 }
306 }
307 },
308
309 .integer_literal,
310 .float_literal,
311 => {
312 try out.writeAll("<span class=\"tok-number\">");
313 try writeEscaped(out, src[token.loc.start..token.loc.end]);
314 try out.writeAll("</span>");
315 },
316
317 .bang,
318 .pipe,
319 .pipe_pipe,
320 .pipe_equal,
321 .equal,
322 .equal_equal,
323 .equal_angle_bracket_right,
324 .bang_equal,
325 .l_paren,
326 .r_paren,
327 .semicolon,
328 .percent,
329 .percent_equal,
330 .l_brace,
331 .r_brace,
332 .l_bracket,
333 .r_bracket,
334 .period,
335 .period_asterisk,
336 .ellipsis2,
337 .ellipsis3,
338 .caret,
339 .caret_equal,
340 .plus,
341 .plus_plus,
342 .plus_equal,
343 .plus_percent,
344 .plus_percent_equal,
345 .plus_pipe,
346 .plus_pipe_equal,
347 .minus,
348 .minus_equal,
349 .minus_percent,
350 .minus_percent_equal,
351 .minus_pipe,
352 .minus_pipe_equal,
353 .asterisk,
354 .asterisk_equal,
355 .asterisk_asterisk,
356 .asterisk_percent,
357 .asterisk_percent_equal,
358 .asterisk_pipe,
359 .asterisk_pipe_equal,
360 .arrow,
361 .colon,
362 .slash,
363 .slash_equal,
364 .comma,
365 .ampersand,
366 .ampersand_equal,
367 .question_mark,
368 .angle_bracket_left,
369 .angle_bracket_left_equal,
370 .angle_bracket_angle_bracket_left,
371 .angle_bracket_angle_bracket_left_equal,
372 .angle_bracket_angle_bracket_left_pipe,
373 .angle_bracket_angle_bracket_left_pipe_equal,
374 .angle_bracket_right,
375 .angle_bracket_right_equal,
376 .angle_bracket_angle_bracket_right,
377 .angle_bracket_angle_bracket_right_equal,
378 .tilde,
379 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
380
381 .invalid, .invalid_periodasterisks => return error.ParseError,
382 }
383 index = token.loc.end;
384 }
385 try out.writeAll(end_line ++ "</code></pre>");
386}
387
388fn writeEscapedLines(out: anytype, text: []const u8) !void {
389 for (text) |char| {
390 if (char == '\n') {
391 try out.writeAll(end_line);
392 line_counter += 1;
393 try out.print(start_line, .{line_counter});
394 } else {
395 try writeEscaped(out, &[_]u8{char});
396 }
397 }
398}
399
400fn writeEscaped(out: anytype, input: []const u8) !void {
401 for (input) |c| {
402 try switch (c) {
403 '&' => out.writeAll("&amp;"),
404 '<' => out.writeAll("&lt;"),
405 '>' => out.writeAll("&gt;"),
406 '"' => out.writeAll("&quot;"),
407 else => out.writeByte(c),
408 };
409 }
410}
411
412const builtin_types = [_][]const u8{
413 "f16", "f32", "f64", "f128", "c_longdouble", "c_short",
414 "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong",
415 "c_ulonglong", "c_char", "anyopaque", "void", "bool", "isize",
416 "usize", "noreturn", "type", "anyerror", "comptime_int", "comptime_float",
417};
418
419fn isType(name: []const u8) bool {
420 for (builtin_types) |t| {
421 if (mem.eql(u8, t, name))
422 return true;
423 }
424 return false;
425}
src/autodoc/render_source.zig created+424
...@@ -0,0 +1,424 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const io = std.io;
4const fs = std.fs;
5const process = std.process;
6const ChildProcess = std.ChildProcess;
7const Progress = std.Progress;
8const print = std.debug.print;
9const mem = std.mem;
10const testing = std.testing;
11const Allocator = std.mem.Allocator;
12const Module = @import("../Module.zig");
13
14pub fn genHtml(
15 allocator: Allocator,
16 src: *Module.File,
17 out: anytype,
18) !void {
19 try out.writeAll(
20 \\<!doctype html>
21 \\<html lang="en">
22 \\<head>
23 \\ <meta charset="utf-8">
24 \\ <meta name="viewport" content="width=device-width, initial-scale=1.0">
25 );
26 try out.print(" <title>{s} - source view</title>\n", .{src.sub_file_path});
27 try out.writeAll(
28 \\ <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg=="/>
29 \\ <style>
30 \\ body{
31 \\ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
32 \\ margin: 0;
33 \\ line-height: 1.5;
34 \\ }
35 \\
36 \\ pre > code {
37 \\ display: block;
38 \\ overflow: auto;
39 \\ line-height: normal;
40 \\ margin: 0em;
41 \\ }
42 \\ .tok-kw {
43 \\ color: #333;
44 \\ font-weight: bold;
45 \\ }
46 \\ .tok-str {
47 \\ color: #d14;
48 \\ }
49 \\ .tok-builtin {
50 \\ color: #005C7A;
51 \\ }
52 \\ .tok-comment {
53 \\ color: #545454;
54 \\ font-style: italic;
55 \\ }
56 \\ .tok-fn {
57 \\ color: #900;
58 \\ font-weight: bold;
59 \\ }
60 \\ .tok-null {
61 \\ color: #005C5C;
62 \\ }
63 \\ .tok-number {
64 \\ color: #005C5C;
65 \\ }
66 \\ .tok-type {
67 \\ color: #458;
68 \\ font-weight: bold;
69 \\ }
70 \\ pre {
71 \\ counter-reset: line;
72 \\ }
73 \\ pre .line:before {
74 \\ counter-increment: line;
75 \\ content: counter(line);
76 \\ display: inline-block;
77 \\ padding-right: 1em;
78 \\ width: 2em;
79 \\ text-align: right;
80 \\ color: #999;
81 \\ }
82 \\
83 \\ @media (prefers-color-scheme: dark) {
84 \\ body{
85 \\ background:#222;
86 \\ color: #ccc;
87 \\ }
88 \\ pre > code {
89 \\ color: #ccc;
90 \\ background: #222;
91 \\ border: unset;
92 \\ }
93 \\ .tok-kw {
94 \\ color: #eee;
95 \\ }
96 \\ .tok-str {
97 \\ color: #2e5;
98 \\ }
99 \\ .tok-builtin {
100 \\ color: #ff894c;
101 \\ }
102 \\ .tok-comment {
103 \\ color: #aa7;
104 \\ }
105 \\ .tok-fn {
106 \\ color: #B1A0F8;
107 \\ }
108 \\ .tok-null {
109 \\ color: #ff8080;
110 \\ }
111 \\ .tok-number {
112 \\ color: #ff8080;
113 \\ }
114 \\ .tok-type {
115 \\ color: #68f;
116 \\ }
117 \\ }
118 \\ </style>
119 \\</head>
120 \\<body>
121 \\
122 );
123
124 const source = try src.getSource(allocator);
125 try tokenizeAndPrintRaw(allocator, out, source.bytes);
126 try out.writeAll(
127 \\</body>
128 \\</html>
129 );
130}
131
132const start_line = "<span class=\"line\" id=\"L{d}\">";
133const end_line = "</span>\n";
134
135var line_counter: usize = 1;
136
137pub fn tokenizeAndPrintRaw(
138 allocator: Allocator,
139 out: anytype,
140 raw_src: [:0]const u8,
141) !void {
142 const src = try allocator.dupeZ(u8, raw_src);
143 defer allocator.free(src);
144
145 line_counter = 1;
146
147 try out.print("<pre><code>" ++ start_line, .{line_counter});
148 var tokenizer = std.zig.Tokenizer.init(src);
149 var index: usize = 0;
150 var next_tok_is_fn = false;
151 while (true) {
152 const prev_tok_was_fn = next_tok_is_fn;
153 next_tok_is_fn = false;
154
155 const token = tokenizer.next();
156 if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| {
157 // render one comment
158 const comment_start = index + comment_start_off;
159 const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n");
160 const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start;
161
162 try writeEscapedLines(out, src[index..comment_start]);
163 try out.writeAll("<span class=\"tok-comment\">");
164 try writeEscaped(out, src[comment_start..comment_end]);
165 try out.writeAll("</span>\n");
166 index = comment_end;
167 tokenizer.index = index;
168 continue;
169 }
170
171 try writeEscapedLines(out, src[index..token.loc.start]);
172 switch (token.tag) {
173 .eof => break,
174
175 .keyword_addrspace,
176 .keyword_align,
177 .keyword_and,
178 .keyword_asm,
179 .keyword_async,
180 .keyword_await,
181 .keyword_break,
182 .keyword_catch,
183 .keyword_comptime,
184 .keyword_const,
185 .keyword_continue,
186 .keyword_defer,
187 .keyword_else,
188 .keyword_enum,
189 .keyword_errdefer,
190 .keyword_error,
191 .keyword_export,
192 .keyword_extern,
193 .keyword_for,
194 .keyword_if,
195 .keyword_inline,
196 .keyword_noalias,
197 .keyword_noinline,
198 .keyword_nosuspend,
199 .keyword_opaque,
200 .keyword_or,
201 .keyword_orelse,
202 .keyword_packed,
203 .keyword_anyframe,
204 .keyword_pub,
205 .keyword_resume,
206 .keyword_return,
207 .keyword_linksection,
208 .keyword_callconv,
209 .keyword_struct,
210 .keyword_suspend,
211 .keyword_switch,
212 .keyword_test,
213 .keyword_threadlocal,
214 .keyword_try,
215 .keyword_union,
216 .keyword_unreachable,
217 .keyword_usingnamespace,
218 .keyword_var,
219 .keyword_volatile,
220 .keyword_allowzero,
221 .keyword_while,
222 .keyword_anytype,
223 => {
224 try out.writeAll("<span class=\"tok-kw\">");
225 try writeEscaped(out, src[token.loc.start..token.loc.end]);
226 try out.writeAll("</span>");
227 },
228
229 .keyword_fn => {
230 try out.writeAll("<span class=\"tok-kw\">");
231 try writeEscaped(out, src[token.loc.start..token.loc.end]);
232 try out.writeAll("</span>");
233 next_tok_is_fn = true;
234 },
235
236 .string_literal,
237 .char_literal,
238 => {
239 try out.writeAll("<span class=\"tok-str\">");
240 try writeEscaped(out, src[token.loc.start..token.loc.end]);
241 try out.writeAll("</span>");
242 },
243
244 .multiline_string_literal_line => {
245 if (src[token.loc.end - 1] == '\n') {
246 try out.writeAll("<span class=\"tok-str\">");
247 try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]);
248 line_counter += 1;
249 try out.print("</span>" ++ end_line ++ "\n" ++ start_line, .{line_counter});
250 } else {
251 try out.writeAll("<span class=\"tok-str\">");
252 try writeEscaped(out, src[token.loc.start..token.loc.end]);
253 try out.writeAll("</span>");
254 }
255 },
256
257 .builtin => {
258 try out.writeAll("<span class=\"tok-builtin\">");
259 try writeEscaped(out, src[token.loc.start..token.loc.end]);
260 try out.writeAll("</span>");
261 },
262
263 .doc_comment,
264 .container_doc_comment,
265 => {
266 try out.writeAll("<span class=\"tok-comment\">");
267 try writeEscaped(out, src[token.loc.start..token.loc.end]);
268 try out.writeAll("</span>");
269 },
270
271 .identifier => {
272 const tok_bytes = src[token.loc.start..token.loc.end];
273 if (mem.eql(u8, tok_bytes, "undefined") or
274 mem.eql(u8, tok_bytes, "null") or
275 mem.eql(u8, tok_bytes, "true") or
276 mem.eql(u8, tok_bytes, "false"))
277 {
278 try out.writeAll("<span class=\"tok-null\">");
279 try writeEscaped(out, tok_bytes);
280 try out.writeAll("</span>");
281 } else if (prev_tok_was_fn) {
282 try out.writeAll("<span class=\"tok-fn\">");
283 try writeEscaped(out, tok_bytes);
284 try out.writeAll("</span>");
285 } else {
286 const is_int = blk: {
287 if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u')
288 break :blk false;
289 var i = token.loc.start + 1;
290 if (i == token.loc.end)
291 break :blk false;
292 while (i != token.loc.end) : (i += 1) {
293 if (src[i] < '0' or src[i] > '9')
294 break :blk false;
295 }
296 break :blk true;
297 };
298 if (is_int or isType(tok_bytes)) {
299 try out.writeAll("<span class=\"tok-type\">");
300 try writeEscaped(out, tok_bytes);
301 try out.writeAll("</span>");
302 } else {
303 try writeEscaped(out, tok_bytes);
304 }
305 }
306 },
307
308 .integer_literal,
309 .float_literal,
310 => {
311 try out.writeAll("<span class=\"tok-number\">");
312 try writeEscaped(out, src[token.loc.start..token.loc.end]);
313 try out.writeAll("</span>");
314 },
315
316 .bang,
317 .pipe,
318 .pipe_pipe,
319 .pipe_equal,
320 .equal,
321 .equal_equal,
322 .equal_angle_bracket_right,
323 .bang_equal,
324 .l_paren,
325 .r_paren,
326 .semicolon,
327 .percent,
328 .percent_equal,
329 .l_brace,
330 .r_brace,
331 .l_bracket,
332 .r_bracket,
333 .period,
334 .period_asterisk,
335 .ellipsis2,
336 .ellipsis3,
337 .caret,
338 .caret_equal,
339 .plus,
340 .plus_plus,
341 .plus_equal,
342 .plus_percent,
343 .plus_percent_equal,
344 .plus_pipe,
345 .plus_pipe_equal,
346 .minus,
347 .minus_equal,
348 .minus_percent,
349 .minus_percent_equal,
350 .minus_pipe,
351 .minus_pipe_equal,
352 .asterisk,
353 .asterisk_equal,
354 .asterisk_asterisk,
355 .asterisk_percent,
356 .asterisk_percent_equal,
357 .asterisk_pipe,
358 .asterisk_pipe_equal,
359 .arrow,
360 .colon,
361 .slash,
362 .slash_equal,
363 .comma,
364 .ampersand,
365 .ampersand_equal,
366 .question_mark,
367 .angle_bracket_left,
368 .angle_bracket_left_equal,
369 .angle_bracket_angle_bracket_left,
370 .angle_bracket_angle_bracket_left_equal,
371 .angle_bracket_angle_bracket_left_pipe,
372 .angle_bracket_angle_bracket_left_pipe_equal,
373 .angle_bracket_right,
374 .angle_bracket_right_equal,
375 .angle_bracket_angle_bracket_right,
376 .angle_bracket_angle_bracket_right_equal,
377 .tilde,
378 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
379
380 .invalid, .invalid_periodasterisks => return error.ParseError,
381 }
382 index = token.loc.end;
383 }
384 try out.writeAll(end_line ++ "</code></pre>");
385}
386
387fn writeEscapedLines(out: anytype, text: []const u8) !void {
388 for (text) |char| {
389 if (char == '\n') {
390 try out.writeAll(end_line);
391 line_counter += 1;
392 try out.print(start_line, .{line_counter});
393 } else {
394 try writeEscaped(out, &[_]u8{char});
395 }
396 }
397}
398
399fn writeEscaped(out: anytype, input: []const u8) !void {
400 for (input) |c| {
401 try switch (c) {
402 '&' => out.writeAll("&amp;"),
403 '<' => out.writeAll("&lt;"),
404 '>' => out.writeAll("&gt;"),
405 '"' => out.writeAll("&quot;"),
406 else => out.writeByte(c),
407 };
408 }
409}
410
411const builtin_types = [_][]const u8{
412 "f16", "f32", "f64", "f128", "c_longdouble", "c_short",
413 "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong",
414 "c_ulonglong", "c_char", "anyopaque", "void", "bool", "isize",
415 "usize", "noreturn", "type", "anyerror", "comptime_int", "comptime_float",
416};
417
418fn isType(name: []const u8) bool {
419 for (builtin_types) |t| {
420 if (mem.eql(u8, t, name))
421 return true;
422 }
423 return false;
424}