| author | |
| committer | |
| log | 53e971226dcc2fd0cb53e3442399b8724700b3e5 |
| tree | 2d23cad4a85858f3a45234ea431be2eb3b746f2c |
| parent | 51a4861a081eea5d9bfd590c63f4a4506305f941 |
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"); |
| 56 | 56 | ||
| 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"); |
| 9 | const Zir = @import("Zir.zig"); | 9 | const Zir = @import("Zir.zig"); |
| 10 | const Ref = Zir.Inst.Ref; | 10 | const Ref = Zir.Inst.Ref; |
| 11 | const log = std.log.scoped(.autodoc); | 11 | const log = std.log.scoped(.autodoc); |
| 12 | const Docgen = @import("Docgen.zig"); | 12 | const Docgen = @import("autodoc/render_source.zig"); |
| 13 | 13 | ||
| 14 | module: *Module, | 14 | module: *Module, |
| 15 | doc_location: Compilation.EmitLoc, | 15 | doc_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 | else | 244 | 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 | } |
| 269 | 270 | ||
| 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", .{}); | ||
| 275 | 277 | ||
| 276 | var files_iterator = self.files.iterator(); | 278 | var files_iterator = self.files.iterator(); |
| 277 | 279 | ||
| 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; |
| 280 | 282 | ||
| 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()); |
| 284 | 286 | ||
| 285 | const out = buffer.writer(); | 287 | const out = buffer.writer(); |
| 286 | 288 | ||
| 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 | } |
| 290 | 293 | ||
| 291 | // copy main.js, index.html | 294 | // copy main.js, index.html |
src/Docgen.zig deleted-425| ... | @@ -1,425 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const io = std.io; | ||
| 4 | const fs = std.fs; | ||
| 5 | const process = std.process; | ||
| 6 | const ChildProcess = std.ChildProcess; | ||
| 7 | const Progress = std.Progress; | ||
| 8 | const print = std.debug.print; | ||
| 9 | const mem = std.mem; | ||
| 10 | const testing = std.testing; | ||
| 11 | const Allocator = std.mem.Allocator; | ||
| 12 | const Module = @import("Module.zig"); | ||
| 13 | |||
| 14 | pub 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 | |||
| 133 | const start_line = "<span class=\"line\" id=\"L{d}\">"; | ||
| 134 | const end_line = "</span>\n"; | ||
| 135 | |||
| 136 | var line_counter: usize = 1; | ||
| 137 | |||
| 138 | pub 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 | |||
| 388 | fn 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 | |||
| 400 | fn 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 | |||
| 412 | const 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 | |||
| 419 | fn 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const io = std.io; | ||
| 4 | const fs = std.fs; | ||
| 5 | const process = std.process; | ||
| 6 | const ChildProcess = std.ChildProcess; | ||
| 7 | const Progress = std.Progress; | ||
| 8 | const print = std.debug.print; | ||
| 9 | const mem = std.mem; | ||
| 10 | const testing = std.testing; | ||
| 11 | const Allocator = std.mem.Allocator; | ||
| 12 | const Module = @import("../Module.zig"); | ||
| 13 | |||
| 14 | pub 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 | |||
| 132 | const start_line = "<span class=\"line\" id=\"L{d}\">"; | ||
| 133 | const end_line = "</span>\n"; | ||
| 134 | |||
| 135 | var line_counter: usize = 1; | ||
| 136 | |||
| 137 | pub 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 | |||
| 387 | fn 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 | |||
| 399 | fn 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 | |||
| 411 | const 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 | |||
| 418 | fn 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 | } | ||