╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ docgen.zig ───────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
858 .bang, 859 .pipe, 860 .pipe_pipe, 861 .pipe_equal, 862 .equal, 863 .equal_equal, 864 .equal_angle_bracket_right, 865 .bang_equal, 866 .l_paren, 867 .r_paren, 868 .semicolon, 869 .percent, 870 .percent_equal, 871 .l_brace, 872 .r_brace, 873 .l_bracket, 874 .r_bracket, 875 .period, 876 .period_asterisk, 877 .ellipsis2, 878 .ellipsis3, 879 .caret, 880 .caret_equal, 881 .plus, 882 .plus_plus, 883 .plus_equal, 884 .plus_percent, 885 .plus_percent_equal, 886 .plus_pipe, 887 .plus_pipe_equal, 888 .minus, 889 .minus_equal, 890 .minus_percent, 891 .minus_percent_equal, 892 .minus_pipe, 893 .minus_pipe_equal, 894 .asterisk, 895 .asterisk_equal, 896 .asterisk_percent, 897 .asterisk_percent_equal, 898 .asterisk_pipe, 899 .asterisk_pipe_equal, 900 .arrow, 901 .colon, 902 .slash, 903 .slash_equal, 904 .comma, 905 .ampersand, 906 .ampersand_equal, 907 .question_mark, 908 .angle_bracket_left, 909 .angle_bracket_left_equal, 910 .angle_bracket_angle_bracket_left, 911 .angle_bracket_angle_bracket_left_equal, 912 .angle_bracket_angle_bracket_left_pipe, 913 .angle_bracket_angle_bracket_left_pipe_equal, 914 .angle_bracket_right, 915 .angle_bracket_right_equal, 916 .angle_bracket_angle_bracket_right, 917 .angle_bracket_angle_bracket_right_equal, 918 .tilde, 919 => try writeEscaped(out, src[token.loc.start..token.loc.end]), 920 921 .invalid => return parseError( 922 docgen_tokenizer, 923 source_token, 924 "syntax error", 925 .{}, 926 ), 927 } 928 index = token.loc.end; 929 } 930 try out.writeAll("</code>"); 931 } 932 933 fn tokenizeAndPrint( 934 allocator: Allocator, 935 docgen_tokenizer: *Tokenizer, 936 out: *Writer, 937 source_token: Token, 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