╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ docgen.zig ───────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
938 ) !void { 939 const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end]; 940 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src); 941 } 942 943 fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock, content: ?[]const u8) !void { 944 const source_type = @tagName(syntax_block.source_type); 945 946 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name }); 947 switch (syntax_block.source_type) { 948 .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token), 949 else => { 950 const raw_source = content orelse docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end]; 951 const trimmed_raw_source = mem.trim(u8, raw_source, " \r\n"); 952 953 try out.writeAll("<code>"); 954 try writeEscapedLines(out, trimmed_raw_source); 955 try out.writeAll("</code>"); 956 }, 957 } 958 try out.writeAll("</pre></figure>"); 959 } 960 961 fn printShell(out: *Writer, shell_content: []const u8, escape: bool) !void { 962 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n"); 963 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>"); 964 var cmd_cont: bool = false; 965 var iter = std.mem.splitScalar(u8, trimmed_shell_content, '\n'); 966 while (iter.next()) |orig_line| { 967 const line = mem.trimEnd(u8, orig_line, " \r"); 968 if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') { 969 try out.writeAll("$ <kbd>"); 970 const s = std.mem.trimStart(u8, line[1..], " "); 971 if (escape) { 972 try writeEscaped(out, s); 973 } else { 974 try out.writeAll(s); 975 } 976 try out.writeAll("</kbd>" ++ "\n"); 977 } else if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] == '\\') { 978 try out.writeAll("$ <kbd>"); 979 const s = std.mem.trimStart(u8, line[1..], " "); 980 if (escape) { 981 try writeEscaped(out, s); 982 } else { 983 try out.writeAll(s); 984 } 985 try out.writeAll("\n"); 986 cmd_cont = true; 987 } else if (line.len > 0 and line[line.len - 1] != '\\' and cmd_cont) { 988 if (escape) { 989 try writeEscaped(out, line); 990 } else { 991 try out.writeAll(line); 992 } 993 try out.writeAll("</kbd>" ++ "\n"); 994 cmd_cont = false; 995 } else { 996 if (escape) { 997 try writeEscaped(out, line); 998 } else { 999 try out.writeAll(line); 1000 } 1001 try out.writeAll("\n"); 1002 } 1003 } 1004 1005 try out.writeAll("</samp></pre></figure>"); 1006 } 1007 1008 fn genHtml( 1009 allocator: Allocator, 1010 io: Io, 1011 tokenizer: *Tokenizer, 1012 toc: *Toc, 1013 code_dir: Path, 1014 grammar: []const u8, 1015 out: *Writer, 1016 ) !void { 1017 for (toc.nodes) |node| { 1018 switch (node) { 1019 .Content => |data| { 1020 try out.writeAll(data); 1021 }, 1022 .Link => |info| { 1023 if (!toc.urls.contains(info.url)) { 1024 return parseError(tokenizer, info.token, "url not found: {s}", .{info.url}); 1025 } 1026 try out.print("<a href=\"#{s}\">{s}</a>", .{ info.url, info.name }); 1027 }, 1028 .Nav => { 1029 try out.writeAll(toc.toc); 1030 }, 1031 .Builtin => |tok| { 1032 try out.writeAll("<figure><figcaption class=\"zig-cap\"><cite>@import(\"builtin\")</cite></figcaption><pre>"); 1033 const builtin_code = @embedFile("builtin"); // 😎 1034 try tokenizeAndPrintRaw(allocator, tokenizer, out, tok, builtin_code); 1035 try out.writeAll("</pre></figure>"); 1036 }, 1037 .HeaderOpen => |info| { 1038 try out.print( 1039 "<h{d} id=\"{s}\"><a href=\"#toc-{s}\">{s}</a> <a class=\"hdr\" href=\"#{s}\">§</a></h{d}>\n", 1040 .{ info.n, info.url, info.url, info.name, info.url, info.n }, 1041 ); 1042 }, 1043 .SeeAlso => |items| { 1044 try out.writeAll("<p>See also:</p><ul>\n"); 1045 for (items) |item| { 1046 const url = try urlize(allocator, item.name); 1047 if (!toc.urls.contains(url)) { 1048 return parseError(tokenizer, item.token, "url not found: {s}", .{url}); 1049 } 1050 try out.print("<li><a href=\"#{s}\">{s}</a></li>\n", .{ url, item.name }); 1051 } 1052 try out.writeAll("</ul>\n"); 1053 }, 1054 .InlineSyntax => |content_tok| { 1055 try tokenizeAndPrint(allocator, tokenizer, out, content_tok); 1056 }, 1057 .Shell => |content_tok| { 1058 const raw_shell_content = tokenizer.buffer[content_tok.start..content_tok.end]; 1059 try printShell(out, raw_shell_content, true); 1060 }, 1061 .SyntaxBlock => |syntax_block| { 1062 try printSourceBlock(allocator, tokenizer, out, syntax_block, null); 1063 }, 1064 .Code => |code| { 1065 const out_basename = try std.fmt.allocPrint(allocator, "{s}.out", .{ 1066 Dir.path.stem(code.name), 1067 }); 1068 defer allocator.free(out_basename); 1069 1070 const out_path: Path = .{ 1071 .root_dir = code_dir.root_dir, 1072 .sub_path = out_basename, 1073 }; 1074 1075 const contents = out_path.root_dir.handle.readFileAlloc(io, out_path.sub_path, allocator, .unlimited) catch |err| { 1076 return parseError(tokenizer, code.token, "failed opening {f}: {t}", .{ out_path, err }); 1077 }; 1078 defer allocator.free(contents); 1079 1080 try out.writeAll(contents); 1081 }, 1082 .Grammar => { 1083 try printSourceBlock(allocator, tokenizer, out, .{ 1084 .source_type = .peg, 1085 .name = "grammar.peg", 1086 .source_token = undefined, 1087 }, grammar); 1088 }, 1089 } 1090 } 1091 } 1092