╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ doctest.zig ──────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
835 index = token.loc.end; 836 } 837 try out.writeAll("</code>"); 838 } 839 840 fn writeEscapedLines(out: *Writer, text: []const u8) !void { 841 return writeEscaped(out, text); 842 } 843 844 const Code = struct { 845 id: Id, 846 mode: std.builtin.Optimize, 847 link_objects: []const []const u8, 848 target_str: ?[]const u8, 849 link_libc: bool, 850 link_mode: ?std.builtin.LinkMode, 851 disable_cache: bool, 852 just_check_syntax: bool, 853 additional_options: []const []const u8, 854 use_llvm: ?bool, 855 856 const Id = union(enum) { 857 @"test", 858 test_error: []const u8, 859 test_safety: []const u8, 860 exe: ExpectedOutcome, 861 obj: ?[]const u8, 862 lib, 863 }; 864 865 const ExpectedOutcome = enum { 866 succeed, 867 fail, 868 build_fail, 869 }; 870 }; 871 872 fn stripManifest(source_bytes: []const u8) []const u8 { 873 const manifest_start = mem.findLast(u8, source_bytes, "\n\n// ") orelse 874 fatal("missing manifest comment", .{}); 875 return source_bytes[0 .. manifest_start + 1]; 876 } 877 878 fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code { 879 const manifest_start = mem.findLast(u8, source_bytes, "\n\n// ") orelse 880 fatal("missing manifest comment", .{}); 881 var it = mem.tokenizeScalar(u8, source_bytes[manifest_start..], '\n'); 882 const first_line = skipPrefix(it.next().?); 883 884 var just_check_syntax = false; 885 const id: Code.Id = if (mem.eql(u8, first_line, "syntax")) blk: { 886 just_check_syntax = true; 887 break :blk .{ .obj = null }; 888 } else if (mem.eql(u8, first_line, "test")) 889 .@"test" 890 else if (mem.eql(u8, first_line, "lib")) 891 .lib 892 else if (mem.eql(u8, first_line, "obj")) 893 .{ .obj = null } 894 else if (mem.startsWith(u8, first_line, "test_error=")) 895 .{ .test_error = first_line["test_error=".len..] } 896 else if (mem.startsWith(u8, first_line, "test_safety=")) 897 .{ .test_safety = first_line["test_safety=".len..] } 898 else if (mem.startsWith(u8, first_line, "exe=")) 899 .{ .exe = std.meta.stringToEnum(Code.ExpectedOutcome, first_line["exe=".len..]) orelse 900 fatal("bad exe expected outcome in line '{s}'", .{first_line}) } 901 else if (mem.startsWith(u8, first_line, "obj=")) 902 .{ .obj = first_line["obj=".len..] } 903 else 904 fatal("unrecognized manifest id: '{s}'", .{first_line}); 905 906 var mode: std.builtin.Optimize = .debug; 907 var link_mode: ?std.builtin.LinkMode = null; 908 var link_objects: std.ArrayList([]const u8) = .empty; 909 var additional_options: std.ArrayList([]const u8) = .empty; 910 var target_str: ?[]const u8 = null; 911 var link_libc = false; 912 var disable_cache = false; 913 var use_llvm: ?bool = null; 914 915 while (it.next()) |prefixed_line| { 916 const line = skipPrefix(prefixed_line); 917 if (mem.startsWith(u8, line, "optimize=")) { 918 mode = std.builtin.Optimize.fromString(line["optimize=".len..]) orelse 919 fatal("bad optimization mode line: {q}", .{line}); 920 } else if (mem.startsWith(u8, line, "link_mode=")) { 921 link_mode = std.meta.stringToEnum(std.builtin.LinkMode, line["link_mode=".len..]) orelse 922 fatal("bad link mode line: {q}", .{line}); 923 } else if (mem.startsWith(u8, line, "link_object=")) { 924 try link_objects.append(arena, line["link_object=".len..]); 925 } else if (mem.startsWith(u8, line, "additional_option=")) { 926 try additional_options.append(arena, line["additional_option=".len..]); 927 } else if (mem.startsWith(u8, line, "target=")) { 928 target_str = line["target=".len..]; 929 } else if (mem.eql(u8, line, "llvm=true")) { 930 use_llvm = true; 931 } else if (mem.eql(u8, line, "llvm=false")) { 932 use_llvm = false; 933 } else if (mem.eql(u8, line, "link_libc")) { 934 link_libc = true; 935 } else if (mem.eql(u8, line, "disable_cache")) { 936 disable_cache = true; 937 } else { 938 fatal("unrecognized manifest line: {s}", .{line}); 939 } 940 } 941 942 return .{ 943 .id = id, 944 .mode = mode, 945 .additional_options = try additional_options.toOwnedSlice(arena), 946 .link_objects = try link_objects.toOwnedSlice(arena), 947 .target_str = target_str, 948 .link_libc = link_libc, 949 .link_mode = link_mode, 950 .disable_cache = disable_cache, 951 .just_check_syntax = just_check_syntax, 952 .use_llvm = use_llvm, 953 }; 954 } 955 956 fn skipPrefix(line: []const u8) []const u8 { 957 if (!mem.startsWith(u8, line, "// ")) { 958 fatal("line does not start with '// ': '{s}", .{line}); 959 } 960 return line[3..]; 961 } 962 963 fn escapeHtml(gpa: Allocator, input: []const u8) ![]u8 { 964 var allocating: Writer.Allocating = .init(gpa); 965 defer allocating.deinit(); 966 try writeEscaped(&allocating.writer, input); 967 return allocating.toOwnedSlice(); 968 } 969 970 fn writeEscaped(w: *Writer, input: []const u8) !void { 971 for (input) |c| try switch (c) { 972 '&' => w.writeAll("&amp;"), 973 '<' => w.writeAll("&lt;"), 974 '>' => w.writeAll("&gt;"), 975 '"' => w.writeAll("&quot;"), 976 else => w.writeByte(c), 977 }; 978 } 979 980 fn termColor(allocator: Allocator, input: []const u8) ![]u8 { 981 // The SRG sequences generates by the Zig compiler are in the format: 982 // ESC [ <foreground-color> ; <n> m 983 // or 984 // ESC [ <n> m 985 // 986 // where 987 // foreground-color is 31 (red), 32 (green), 36 (cyan) 988 // n is 0 (reset), 1 (bold), 2 (dim) 989 // 990 // Note that 37 (white) is currently not used by the compiler. 991 // 992 // See std.debug.TTY.Color. 993 const supported_sgr_colors = [_]u8{ 31, 32, 36 }; 994 const supported_sgr_numbers = [_]u8{ 0, 1, 2 }; 995 996 var buf = std.array_list.Managed(u8).init(allocator); 997 defer buf.deinit(); 998 999 var sgr_param_start_index: usize = undefined; 1000 var sgr_num: u8 = undefined; 1001 var sgr_color: u8 = undefined; 1002 var i: usize = 0; 1003 var state: enum { 1004 start, 1005 escape, 1006 lbracket, 1007 number, 1008 after_number, 1009 arg, 1010 arg_number, 1011 expect_end, 1012 } = .start; 1013 var last_new_line: usize = 0; 1014 var open_span_count: usize = 0; 1015 while (i < input.len) : (i += 1) { 1016 const c = input[i]; 1017 switch (state) { 1018 .start => switch (c) { 1019 '\x1b' => state = .escape, 1020 '\n' => { 1021 try buf.append(c); 1022 last_new_line = buf.items.len; 1023 }, 1024 else => try buf.append(c), 1025 }, 1026 .escape => switch (c) { 1027 '[' => state = .lbracket, 1028 else => return error.UnsupportedEscape, 1029 }, 1030 .lbracket => switch (c) { 1031 '0'...'9' => { 1032 sgr_param_start_index = i; 1033 state = .number; 1034 }, 1035 else => return error.UnsupportedEscape, 1036 }, 1037 .number => switch (c) { 1038 '0'...'9' => {}, 1039 else => { 1040 sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); 1041 sgr_color = 0; 1042 state = .after_number; 1043 i -= 1; 1044 }, 1045 }, 1046 .after_number => switch (c) { 1047 ';' => state = .arg, 1048 'D' => state = .start, 1049 'K' => { 1050 buf.items.len = last_new_line; 1051 state = .start; 1052 }, 1053 else => { 1054 state = .expect_end; 1055 i -= 1; 1056 }, 1057 }, 1058 .arg => switch (c) { 1059 '0'...'9' => { 1060 sgr_param_start_index = i; 1061 state = .arg_number; 1062 }, 1063 else => return error.UnsupportedEscape, 1064 }, 1065 .arg_number => switch (c) { 1066 '0'...'9' => {}, 1067 else => { 1068 // Keep the sequence consistent, foreground color first. 1069 // 32;1m is equivalent to 1;32m, but the latter will 1070 // generate an incorrect HTML class without notice. 1071 sgr_color = sgr_num; 1072 if (!in(&supported_sgr_colors, sgr_color)) return error.UnsupportedForegroundColor; 1073 1074 sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); 1075 if (!in(&supported_sgr_numbers, sgr_num)) return error.UnsupportedNumber; 1076 1077 state = .expect_end; 1078 i -= 1; 1079 }, 1080 }, 1081 .expect_end => switch (c) { 1082 'm' => { 1083 state = .start; 1084 while (open_span_count != 0) : (open_span_count -= 1) { 1085 try buf.appendSlice("</span>"); 1086 } 1087 if (sgr_num == 0) { 1088 if (sgr_color != 0) return error.UnsupportedColor; 1089 continue; 1090 } 1091 if (sgr_color != 0) { 1092 try buf.print("<span class=\"sgr-{d}_{d}m\">", .{ sgr_color, sgr_num }); 1093 } else { 1094 try buf.print("<span class=\"sgr-{d}m\">", .{sgr_num}); 1095 } 1096 open_span_count += 1; 1097 }, 1098 else => return error.UnsupportedEscape, 1099 }, 1100 } 1101 } 1102 return try buf.toOwnedSlice(); 1103 } 1104 1105 // Returns true if number is in slice. 1106 fn in(slice: []const u8, number: u8) bool { 1107 return mem.findScalar(u8, slice, number) != null; 1108 } 1109 1110 fn run( 1111 allocator: Allocator, 1112 io: Io, 1113 environ_map: *const process.Environ.Map, 1114 cwd: []const u8, 1115 args: []const []const u8, 1116 ) !process.RunResult { 1117 const result = try process.run(allocator, io, .{ 1118 .argv = args, 1119 .environ_map = environ_map, 1120 .cwd = .{ .path = cwd }, 1121 }); 1122 switch (result.term) { 1123 .exited => |exit_code| { 1124 if (exit_code != 0) { 1125 std.debug.print("{s}\nThe following command exited with code {}:\n", .{ result.stderr, exit_code }); 1126 dumpArgs(args); 1127 return error.ChildExitError; 1128 } 1129 }, 1130 .signal => |sig| { 1131 std.debug.print("{s}\nThe following command terminated with signal {t}:\n", .{ result.stderr, sig }); 1132 dumpArgs(args); 1133 return error.ChildCrashed; 1134 }, 1135 .stopped => |sig| { 1136 std.debug.print("{s}\nThe following command stopped with signal {t}:\n", .{ result.stderr, sig }); 1137 dumpArgs(args); 1138 return error.ChildCrashed; 1139 }, 1140 .unknown => { 1141 std.debug.print("{s}\nThe following command crashed:\n", .{result.stderr}); 1142 dumpArgs(args); 1143 return error.ChildCrashed; 1144 }, 1145 } 1146 return result; 1147 } 1148 1149 fn printShell(out: *Writer, shell_content: []const u8, escape: bool) !void { 1150 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n"); 1151 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>"); 1152 var cmd_cont: bool = false; 1153 var iter = std.mem.splitScalar(u8, trimmed_shell_content, '\n'); 1154 while (iter.next()) |orig_line| { 1155 const line = mem.trimEnd(u8, orig_line, " \r"); 1156 if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') { 1157 try out.writeAll("$ <kbd>"); 1158 const s = std.mem.trimStart(u8, line[1..], " "); 1159 if (escape) { 1160 try writeEscaped(out, s); 1161 } else { 1162 try out.writeAll(s); 1163 } 1164 try out.writeAll("</kbd>" ++ "\n"); 1165 } else if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] == '\\') { 1166 try out.writeAll("$ <kbd>"); 1167 const s = std.mem.trimStart(u8, line[1..], " "); 1168 if (escape) { 1169 try writeEscaped(out, s); 1170 } else { 1171 try out.writeAll(s); 1172 } 1173 try out.writeAll("\n"); 1174 cmd_cont = true; 1175 } else if (line.len > 0 and line[line.len - 1] != '\\' and cmd_cont) { 1176 if (escape) { 1177 try writeEscaped(out, line); 1178 } else { 1179 try out.writeAll(line); 1180 } 1181 try out.writeAll("</kbd>" ++ "\n"); 1182 cmd_cont = false; 1183 } else { 1184 if (escape) { 1185 try writeEscaped(out, line); 1186 } else { 1187 try out.writeAll(line); 1188 } 1189 try out.writeAll("\n"); 1190 } 1191 } 1192 1193 try out.writeAll("</samp></pre></figure>"); 1194 } 1195 1196 test "term supported colors" { 1197 const test_allocator = testing.allocator; 1198 1199 { 1200 const input = "A\x1b[31;1mred\x1b[0mB"; 1201 const expect = "A<span class=\"sgr-31_1m\">red</span>B"; 1202 1203 const result = try termColor(test_allocator, input); 1204 defer test_allocator.free(result); 1205 try testing.expectEqualSlices(u8, expect, result); 1206 } 1207 1208 { 1209 const input = "A\x1b[32;1mgreen\x1b[0mB"; 1210 const expect = "A<span class=\"sgr-32_1m\">green</span>B"; 1211 1212 const result = try termColor(test_allocator, input); 1213 defer test_allocator.free(result); 1214 try testing.expectEqualSlices(u8, expect, result); 1215 } 1216 1217 { 1218 const input = "A\x1b[36;1mcyan\x1b[0mB"; 1219 const expect = "A<span class=\"sgr-36_1m\">cyan</span>B"; 1220 1221 const result = try termColor(test_allocator, input); 1222 defer test_allocator.free(result); 1223 try testing.expectEqualSlices(u8, expect, result); 1224 } 1225 1226 { 1227 const input = "A\x1b[1mbold\x1b[0mB"; 1228 const expect = "A<span class=\"sgr-1m\">bold</span>B"; 1229 1230 const result = try termColor(test_allocator, input); 1231 defer test_allocator.free(result); 1232 try testing.expectEqualSlices(u8, expect, result); 1233 } 1234 1235 { 1236 const input = "A\x1b[2mdim\x1b[0mB"; 1237 const expect = "A<span class=\"sgr-2m\">dim</span>B"; 1238 1239 const result = try termColor(test_allocator, input); 1240 defer test_allocator.free(result); 1241 try testing.expectEqualSlices(u8, expect, result); 1242 } 1243 } 1244 1245 test "term output from zig" { 1246 // Use data generated by https://github.com/perillo/zig-tty-test-data, 1247 // with zig version 0.11.0-dev.1898+36d47dd19. 1248 const test_allocator = testing.allocator; 1249 1250 { 1251 // 1.1-with-build-progress.out 1252 const input = "Semantic Analysis [1324] \x1b[25D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLD Link... \x1b[12D\x1b[0K"; 1253 const expect = ""; 1254 1255 const result = try termColor(test_allocator, input); 1256 defer test_allocator.free(result); 1257 try testing.expectEqualSlices(u8, expect, result); 1258 } 1259 1260 { 1261 // 2.1-with-reference-traces.out 1262 const input = "\x1b[1msrc/2.1-with-reference-traces.zig:3:7: \x1b[31;1merror: \x1b[0m\x1b[1mcannot assign to constant\n\x1b[0m x += 1;\n \x1b[32;1m~~^~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.1-with-reference-traces.zig:7:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; 1263 const expect = 1264 \\<span class="sgr-1m">src/2.1-with-reference-traces.zig:3:7: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">cannot assign to constant 1265 \\</span> x += 1; 1266 \\ <span class="sgr-32_1m">~~^~~~ 1267 \\</span><span class="sgr-2m">referenced by: 1268 \\ main: src/2.1-with-reference-traces.zig:7:5 1269 \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 1270 \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces 1271 \\ 1272 \\</span> 1273 ; 1274 1275 const result = try termColor(test_allocator, input); 1276 defer test_allocator.free(result); 1277 try testing.expectEqualSlices(u8, expect, result); 1278 } 1279 1280 { 1281 // 2.2-without-reference-traces.out 1282 const input = "\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: \x1b[31;1merror: \x1b[0m\x1b[1minvalid type given to fixedBufferStream\n\x1b[0m else => @compileError(\"invalid type given to fixedBufferStream\"),\n \x1b[32;1m^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\x1b[0m\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: \x1b[36;1mnote: \x1b[0m\x1b[1mcalled from here\n\x1b[0mpub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) {\n; \x1b[32;1m~~~~~^~~~~~~~~~~~~~~~~\n\x1b[0m"; 1283 const expect = 1284 \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">invalid type given to fixedBufferStream 1285 \\</span> else => @compileError("invalid type given to fixedBufferStream"), 1286 \\ <span class="sgr-32_1m">^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1287 \\</span><span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">called from here 1288 \\</span>pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { 1289 \\; <span class="sgr-32_1m">~~~~~^~~~~~~~~~~~~~~~~ 1290 \\</span> 1291 ; 1292 1293 const result = try termColor(test_allocator, input); 1294 defer test_allocator.free(result); 1295 try testing.expectEqualSlices(u8, expect, result); 1296 } 1297 1298 { 1299 // 2.3-with-notes.out 1300 const input = "\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[31;1merror: \x1b[0m\x1b[1mexpected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat'\n\x1b[0m bar(w);\n \x1b[32;1m^\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[36;1mnote: \x1b[0m\x1b[1mpointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp'\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:2:13: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Wat = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:1:14: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Derp = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:4:18: \x1b[36;1mnote: \x1b[0m\x1b[1mparameter type declared here\n\x1b[0mextern fn bar(d: *Derp) void;\n \x1b[32;1m^~~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.3-with-notes.zig:10:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; 1301 const expect = 1302 \\<span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">expected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat' 1303 \\</span> bar(w); 1304 \\ <span class="sgr-32_1m">^ 1305 \\</span><span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">pointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp' 1306 \\</span><span class="sgr-1m">src/2.3-with-notes.zig:2:13: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here 1307 \\</span>const Wat = opaque {}; 1308 \\ <span class="sgr-32_1m">^~~~~~~~~ 1309 \\</span><span class="sgr-1m">src/2.3-with-notes.zig:1:14: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here 1310 \\</span>const Derp = opaque {}; 1311 \\ <span class="sgr-32_1m">^~~~~~~~~ 1312 \\</span><span class="sgr-1m">src/2.3-with-notes.zig:4:18: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">parameter type declared here 1313 \\</span>extern fn bar(d: *Derp) void; 1314 \\ <span class="sgr-32_1m">^~~~~ 1315 \\</span><span class="sgr-2m">referenced by: 1316 \\ main: src/2.3-with-notes.zig:10:5 1317 \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 1318 \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces 1319 \\ 1320 \\</span> 1321 ; 1322 1323 const result = try termColor(test_allocator, input); 1324 defer test_allocator.free(result); 1325 try testing.expectEqualSlices(u8, expect, result); 1326 } 1327 1328 { 1329 // 3.1-with-error-return-traces.out 1330 1331 const input = "error: Error\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:5:5\x1b[0m: \x1b[2m0x20b008 in callee (3.1-with-error-return-traces)\x1b[0m\n return error.Error;\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:9:5\x1b[0m: \x1b[2m0x20b113 in caller (3.1-with-error-return-traces)\x1b[0m\n try callee();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:13:5\x1b[0m: \x1b[2m0x20b153 in main (3.1-with-error-return-traces)\x1b[0m\n try caller();\n \x1b[32;1m^\x1b[0m\n"; 1332 const expect = 1333 \\error: Error 1334 \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:5:5</span>: <span class="sgr-2m">0x20b008 in callee (3.1-with-error-return-traces)</span> 1335 \\ return error.Error; 1336 \\ <span class="sgr-32_1m">^</span> 1337 \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:9:5</span>: <span class="sgr-2m">0x20b113 in caller (3.1-with-error-return-traces)</span> 1338 \\ try callee(); 1339 \\ <span class="sgr-32_1m">^</span> 1340 \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:13:5</span>: <span class="sgr-2m">0x20b153 in main (3.1-with-error-return-traces)</span> 1341 \\ try caller(); 1342 \\ <span class="sgr-32_1m">^</span> 1343 \\ 1344 ; 1345 1346 const result = try termColor(test_allocator, input); 1347 defer test_allocator.free(result); 1348 try testing.expectEqualSlices(u8, expect, result); 1349 } 1350 1351 { 1352 // 3.2-with-stack-trace.out 1353 const input = "\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:561:19\x1b[0m: \x1b[2m0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)\x1b[0m\n while (it.next()) |return_address| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:157:80\x1b[0m: \x1b[2m0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)\x1b[0m\n writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:5:36\x1b[0m: \x1b[2m0x20d3b2 in foo (3.2-with-stack-trace)\x1b[0m\n std.debug.dumpCurrentStackTrace(null);\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:9:8\x1b[0m: \x1b[2m0x20b458 in main (3.2-with-stack-trace)\x1b[0m\n foo();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:607:22\x1b[0m: \x1b[2m0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)\x1b[0m\n root.main();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:376:5\x1b[0m: \x1b[2m0x20a411 in _start (3.2-with-stack-trace)\x1b[0m\n @call(.never_inline, posixCallMainAndExit, .{});\n \x1b[32;1m^\x1b[0m\n"; 1354 const expect = 1355 \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:561:19</span>: <span class="sgr-2m">0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)</span> 1356 \\ while (it.next()) |return_address| { 1357 \\ <span class="sgr-32_1m">^</span> 1358 \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:157:80</span>: <span class="sgr-2m">0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)</span> 1359 \\ writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| { 1360 \\ <span class="sgr-32_1m">^</span> 1361 \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:5:36</span>: <span class="sgr-2m">0x20d3b2 in foo (3.2-with-stack-trace)</span> 1362 \\ std.debug.dumpCurrentStackTrace(null); 1363 \\ <span class="sgr-32_1m">^</span> 1364 \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:9:8</span>: <span class="sgr-2m">0x20b458 in main (3.2-with-stack-trace)</span> 1365 \\ foo(); 1366 \\ <span class="sgr-32_1m">^</span> 1367 \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:607:22</span>: <span class="sgr-2m">0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)</span> 1368 \\ root.main(); 1369 \\ <span class="sgr-32_1m">^</span> 1370 \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:376:5</span>: <span class="sgr-2m">0x20a411 in _start (3.2-with-stack-trace)</span> 1371 \\ @call(.never_inline, posixCallMainAndExit, .{}); 1372 \\ <span class="sgr-32_1m">^</span> 1373 \\ 1374 ; 1375 1376 const result = try termColor(test_allocator, input); 1377 defer test_allocator.free(result); 1378 try testing.expectEqualSlices(u8, expect, result); 1379 } 1380 } 1381 1382 test "printShell" { 1383 const test_allocator = std.testing.allocator; 1384 1385 { 1386 const shell_out = 1387 \\$ zig build test.zig 1388 ; 1389 const expected = 1390 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> 1391 \\</samp></pre></figure> 1392 ; 1393 1394 var buffer: Writer.Allocating = .init(test_allocator); 1395 defer buffer.deinit(); 1396 1397 try printShell(&buffer.writer, shell_out, false); 1398 try testing.expectEqualSlices(u8, expected, buffer.written()); 1399 } 1400 { 1401 const shell_out = 1402 \\$ zig build test.zig 1403 \\build output 1404 ; 1405 const expected = 1406 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> 1407 \\build output 1408 \\</samp></pre></figure> 1409 ; 1410 1411 var buffer: Writer.Allocating = .init(test_allocator); 1412 defer buffer.deinit(); 1413 1414 try printShell(&buffer.writer, shell_out, false); 1415 try testing.expectEqualSlices(u8, expected, buffer.written()); 1416 } 1417 { 1418 const shell_out = "$ zig build test.zig\r\nbuild output\r\n"; 1419 const expected = 1420 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> 1421 \\build output 1422 \\</samp></pre></figure> 1423 ; 1424 1425 var buffer: Writer.Allocating = .init(test_allocator); 1426 defer buffer.deinit(); 1427 1428 try printShell(&buffer.writer, shell_out, false); 1429 try testing.expectEqualSlices(u8, expected, buffer.written()); 1430 } 1431 { 1432 const shell_out = 1433 \\$ zig build test.zig 1434 \\build output 1435 \\$ ./test 1436 ; 1437 const expected = 1438 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> 1439 \\build output 1440 \\$ <kbd>./test</kbd> 1441 \\</samp></pre></figure> 1442 ; 1443 1444 var buffer: Writer.Allocating = .init(test_allocator); 1445 defer buffer.deinit(); 1446 1447 try printShell(&buffer.writer, shell_out, false); 1448 try testing.expectEqualSlices(u8, expected, buffer.written()); 1449 } 1450 { 1451 const shell_out = 1452 \\$ zig build test.zig 1453 \\ 1454 \\$ ./test 1455 \\output 1456 ; 1457 const expected = 1458 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> 1459 \\ 1460 \\$ <kbd>./test</kbd> 1461 \\output 1462 \\</samp></pre></figure> 1463 ; 1464 1465 var buffer: Writer.Allocating = .init(test_allocator); 1466 defer buffer.deinit(); 1467 1468 try printShell(&buffer.writer, shell_out, false); 1469 try testing.expectEqualSlices(u8, expected, buffer.written()); 1470 } 1471 { 1472 const shell_out = 1473 \\$ zig build test.zig 1474 \\$ ./test 1475 \\output 1476 ; 1477 const expected = 1478 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> 1479 \\$ <kbd>./test</kbd> 1480 \\output 1481 \\</samp></pre></figure> 1482 ; 1483 1484 var buffer: Writer.Allocating = .init(test_allocator); 1485 defer buffer.deinit(); 1486 1487 try printShell(&buffer.writer, shell_out, false); 1488 try testing.expectEqualSlices(u8, expected, buffer.written()); 1489 } 1490 { 1491 const shell_out = 1492 \\$ zig build test.zig \ 1493 \\ --build-option 1494 \\build output 1495 \\$ ./test 1496 \\output 1497 ; 1498 const expected = 1499 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ 1500 \\ --build-option</kbd> 1501 \\build output 1502 \\$ <kbd>./test</kbd> 1503 \\output 1504 \\</samp></pre></figure> 1505 ; 1506 1507 var buffer: Writer.Allocating = .init(test_allocator); 1508 defer buffer.deinit(); 1509 1510 try printShell(&buffer.writer, shell_out, false); 1511 try testing.expectEqualSlices(u8, expected, buffer.written()); 1512 } 1513 { 1514 // intentional space after "--build-option1 \" 1515 const shell_out = 1516 \\$ zig build test.zig \ 1517 \\ --build-option1 \ 1518 \\ --build-option2 1519 \\$ ./test 1520 ; 1521 const expected = 1522 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ 1523 \\ --build-option1 \ 1524 \\ --build-option2</kbd> 1525 \\$ <kbd>./test</kbd> 1526 \\</samp></pre></figure> 1527 ; 1528 1529 var buffer: Writer.Allocating = .init(test_allocator); 1530 defer buffer.deinit(); 1531 1532 try printShell(&buffer.writer, shell_out, false); 1533 try testing.expectEqualSlices(u8, expected, buffer.written()); 1534 } 1535 { 1536 const shell_out = 1537 \\$ zig build test.zig \ 1538 \\$ ./test 1539 ; 1540 const expected = 1541 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ 1542 \\$ ./test</kbd> 1543 \\</samp></pre></figure> 1544 ; 1545 1546 var buffer: Writer.Allocating = .init(test_allocator); 1547 defer buffer.deinit(); 1548 1549 try printShell(&buffer.writer, shell_out, false); 1550 try testing.expectEqualSlices(u8, expected, buffer.written()); 1551 } 1552 { 1553 const shell_out = 1554 \\$ zig build test.zig 1555 \\$ ./test 1556 \\$1 1557 ; 1558 const expected = 1559 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> 1560 \\$ <kbd>./test</kbd> 1561 \\$1 1562 \\</samp></pre></figure> 1563 ; 1564 1565 var buffer: Writer.Allocating = .init(test_allocator); 1566 defer buffer.deinit(); 1567 1568 try printShell(&buffer.writer, shell_out, false); 1569 try testing.expectEqualSlices(u8, expected, buffer.written()); 1570 } 1571 { 1572 const shell_out = 1573 \\$zig build test.zig 1574 ; 1575 const expected = 1576 \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$zig build test.zig 1577 \\</samp></pre></figure> 1578 ; 1579 1580 var buffer: Writer.Allocating = .init(test_allocator); 1581 defer buffer.deinit(); 1582 1583 try printShell(&buffer.writer, shell_out, false); 1584 try testing.expectEqualSlices(u8, expected, buffer.written()); 1585 } 1586 } 1587