authorgravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2022-07-30 14:13:53+02:00
committergravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2022-12-13 09:11:30+01:00
logd8b4588d5fe685637ebbbb57c139aca7fb12ddf5
tree79256623488e292cff4d5cb9f7e08664727413dc
parent8691fde0f631daf527a4e030d0be9d26c5b16208

fix(terminal): handle some possible errors and resolve TODOs


4 files changed, 71 insertions(+), 82 deletions(-)

lib/std/Progress.zig+17-8
......@@ -210,8 +210,11 @@ fn refreshWithHeldLock(self: *Progress) void {
210210 std.debug.assert(self.is_windows_terminal);
211211
212212 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
213 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE)
214 unreachable;
213 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) {
214 // stop trying to write to this file
215 self.terminal = null;
216 break :winapi;
217 }
215218
216219 var cursor_pos = windows.COORD{
217220 .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written),
......@@ -231,7 +234,7 @@ fn refreshWithHeldLock(self: *Progress) void {
231234 cursor_pos,
232235 &written,
233236 ) != windows.TRUE) {
234 // Stop trying to write to this file.
237 // stop trying to write to this file
235238 self.terminal = null;
236239 break :winapi;
237240 }
......@@ -241,10 +244,16 @@ fn refreshWithHeldLock(self: *Progress) void {
241244 fill_chars,
242245 cursor_pos,
243246 &written,
244 ) != windows.TRUE) unreachable;
245
246 if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE)
247 unreachable;
247 ) != windows.TRUE) {
248 // stop trying to write to this file
249 self.terminal = null;
250 break :winapi;
251 }
252 if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) {
253 // stop trying to write to this file
254 self.terminal = null;
255 break :winapi;
256 }
248257 } else {
249258 // we are in a "dumb" terminal like in acme or writing to a file
250259 self.output_buffer[end] = '\n';
......@@ -288,7 +297,7 @@ fn refreshWithHeldLock(self: *Progress) void {
288297 }
289298
290299 _ = file.write(self.output_buffer[0..end]) catch {
291 // Stop trying to write to this file once it errors.
300 // stop trying to write to this file
292301 self.terminal = null;
293302 };
294303 if (self.timer) |*timer| {
lib/std/debug.zig+35-55
......@@ -119,7 +119,7 @@ pub fn detectTTYConfig() TTY.Config {
119119 if (stderr_file.supportsAnsiEscapeCodes()) {
120120 return .escape_codes;
121121 } else if (native_os == .windows and stderr_file.isTty()) {
122 return .windows_api;
122 return .{ .windows_api = stderr_file };
123123 } else {
124124 return .no_color;
125125 }
......@@ -415,9 +415,9 @@ pub fn writeStackTrace(
415415 if (stack_trace.index > stack_trace.instruction_addresses.len) {
416416 const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len;
417417
418 tty_config.setColor(out_stream, .Bold);
418 tty_config.setColor(out_stream, .Bold) catch {};
419419 try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
420 tty_config.setColor(out_stream, .Reset);
420 tty_config.setColor(out_stream, .Reset) catch {};
421421 }
422422}
423423
......@@ -605,59 +605,39 @@ pub const TTY = struct {
605605 Reset,
606606 };
607607
608 pub const Config = enum {
608 pub const Config = union(enum) {
609609 no_color,
610610 escape_codes,
611 // TODO give this a payload of file handle
612 windows_api,
611 windows_api: File,
613612
614 pub fn setColor(conf: Config, out_stream: anytype, color: Color) void {
613 pub fn setColor(conf: Config, out_stream: anytype, color: Color) !void {
615614 nosuspend switch (conf) {
616615 .no_color => return,
617 .escape_codes => switch (color) {
618 .Red => out_stream.writeAll(RED) catch return,
619 .Green => out_stream.writeAll(GREEN) catch return,
620 .Cyan => out_stream.writeAll(CYAN) catch return,
621 .White => out_stream.writeAll(WHITE) catch return,
622 .Dim => out_stream.writeAll(DIM) catch return,
623 .Bold => out_stream.writeAll(BOLD) catch return,
624 .Reset => out_stream.writeAll(RESET) catch return,
616 .escape_codes => {
617 const color_string = switch (color) {
618 .Red => RED,
619 .Green => GREEN,
620 .Cyan => CYAN,
621 .White => WHITE,
622 .Dim => DIM,
623 .Bold => BOLD,
624 .Reset => RESET,
625 };
626 try out_stream.writeAll(color_string);
625627 },
626 .windows_api => if (native_os == .windows) {
627 const stderr_file = io.getStdErr();
628 const S = struct {
629 var attrs: windows.WORD = undefined;
630 var init_attrs = false;
628 .windows_api => |file| if (native_os == .windows) {
629 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
630 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE)
631 return error.FailedRetrievingTerminalInfo;
632 const attributes = switch (color) {
633 .Red => windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY,
634 .Green => windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
635 .Cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
636 .White, .Bold => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
637 .Dim => windows.FOREGROUND_INTENSITY,
638 .Reset => info.wAttributes,
631639 };
632 if (!S.init_attrs) {
633 S.init_attrs = true;
634 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
635 // TODO handle error
636 _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
637 S.attrs = info.wAttributes;
638 }
639
640 // TODO handle errors
641 switch (color) {
642 .Red => {
643 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {};
644 },
645 .Green => {
646 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {};
647 },
648 .Cyan => {
649 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
650 },
651 .White, .Bold => {
652 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
653 },
654 .Dim => {
655 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {};
656 },
657 .Reset => {
658 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {};
659 },
660 }
640 try windows.SetConsoleTextAttribute(file.handle, attributes);
661641 } else {
662642 unreachable;
663643 },
......@@ -751,7 +731,7 @@ fn printLineInfo(
751731 comptime printLineFromFile: anytype,
752732) !void {
753733 nosuspend {
754 tty_config.setColor(out_stream, .Bold);
734 try tty_config.setColor(out_stream, .Bold);
755735
756736 if (line_info) |*li| {
757737 try out_stream.print("{s}:{d}:{d}", .{ li.file_name, li.line, li.column });
......@@ -759,11 +739,11 @@ fn printLineInfo(
759739 try out_stream.writeAll("???:?:?");
760740 }
761741
762 tty_config.setColor(out_stream, .Reset);
742 try tty_config.setColor(out_stream, .Reset);
763743 try out_stream.writeAll(": ");
764 tty_config.setColor(out_stream, .Dim);
744 try tty_config.setColor(out_stream, .Dim);
765745 try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
766 tty_config.setColor(out_stream, .Reset);
746 try tty_config.setColor(out_stream, .Reset);
767747 try out_stream.writeAll("\n");
768748
769749 // Show the matching source code line if possible
......@@ -774,9 +754,9 @@ fn printLineInfo(
774754 const space_needed = @intCast(usize, li.column - 1);
775755
776756 try out_stream.writeByteNTimes(' ', space_needed);
777 tty_config.setColor(out_stream, .Green);
757 try tty_config.setColor(out_stream, .Green);
778758 try out_stream.writeAll("^");
779 tty_config.setColor(out_stream, .Reset);
759 try tty_config.setColor(out_stream, .Reset);
780760 }
781761 try out_stream.writeAll("\n");
782762 } else |err| switch (err) {
lib/std/testing.zig+4-4
......@@ -387,9 +387,9 @@ fn SliceDiffer(comptime T: type) type {
387387 for (self.expected) |value, i| {
388388 var full_index = self.start_index + i;
389389 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
390 if (diff) self.ttyconf.setColor(writer, .Red);
390 if (diff) try self.ttyconf.setColor(writer, .Red);
391391 try writer.print("[{}]: {any}\n", .{ full_index, value });
392 if (diff) self.ttyconf.setColor(writer, .Reset);
392 if (diff) try self.ttyconf.setColor(writer, .Reset);
393393 }
394394 }
395395 };
......@@ -427,9 +427,9 @@ const BytesDiffer = struct {
427427 }
428428
429429 fn writeByteDiff(self: BytesDiffer, writer: anytype, comptime fmt: []const u8, byte: u8, diff: bool) !void {
430 if (diff) self.ttyconf.setColor(writer, .Red);
430 if (diff) try self.ttyconf.setColor(writer, .Red);
431431 try writer.print(fmt, .{byte});
432 if (diff) self.ttyconf.setColor(writer, .Reset);
432 if (diff) try self.ttyconf.setColor(writer, .Reset);
433433 }
434434
435435 const ChunkIterator = struct {
src/Compilation.zig+15-15
......@@ -428,29 +428,29 @@ pub const AllErrors = struct {
428428 switch (msg) {
429429 .src => |src| {
430430 try counting_stderr.writeByteNTimes(' ', indent);
431 ttyconf.setColor(stderr, .Bold);
431 try ttyconf.setColor(stderr, .Bold);
432432 try counting_stderr.print("{s}:{d}:{d}: ", .{
433433 src.src_path,
434434 src.line + 1,
435435 src.column + 1,
436436 });
437 ttyconf.setColor(stderr, color);
437 try ttyconf.setColor(stderr, color);
438438 try counting_stderr.writeAll(kind);
439439 try counting_stderr.writeAll(": ");
440440 // This is the length of the part before the error message:
441441 // e.g. "file.zig:4:5: error: "
442442 const prefix_len = @intCast(usize, counting_stderr.context.bytes_written);
443 ttyconf.setColor(stderr, .Reset);
444 ttyconf.setColor(stderr, .Bold);
443 try ttyconf.setColor(stderr, .Reset);
444 try ttyconf.setColor(stderr, .Bold);
445445 if (src.count == 1) {
446446 try src.writeMsg(stderr, prefix_len);
447447 try stderr.writeByte('\n');
448448 } else {
449449 try src.writeMsg(stderr, prefix_len);
450 ttyconf.setColor(stderr, .Dim);
450 try ttyconf.setColor(stderr, .Dim);
451451 try stderr.print(" ({d} times)\n", .{src.count});
452452 }
453 ttyconf.setColor(stderr, .Reset);
453 try ttyconf.setColor(stderr, .Reset);
454454 if (src.source_line) |line| {
455455 for (line) |b| switch (b) {
456456 '\t' => try stderr.writeByte(' '),
......@@ -462,19 +462,19 @@ pub const AllErrors = struct {
462462 // -1 since span.main includes the caret
463463 const after_caret = src.span.end - src.span.main -| 1;
464464 try stderr.writeByteNTimes(' ', src.column - before_caret);
465 ttyconf.setColor(stderr, .Green);
465 try ttyconf.setColor(stderr, .Green);
466466 try stderr.writeByteNTimes('~', before_caret);
467467 try stderr.writeByte('^');
468468 try stderr.writeByteNTimes('~', after_caret);
469469 try stderr.writeByte('\n');
470 ttyconf.setColor(stderr, .Reset);
470 try ttyconf.setColor(stderr, .Reset);
471471 }
472472 for (src.notes) |note| {
473473 try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent);
474474 }
475475 if (src.reference_trace.len != 0) {
476 ttyconf.setColor(stderr, .Reset);
477 ttyconf.setColor(stderr, .Dim);
476 try ttyconf.setColor(stderr, .Reset);
477 try ttyconf.setColor(stderr, .Dim);
478478 try stderr.print("referenced by:\n", .{});
479479 for (src.reference_trace) |reference| {
480480 switch (reference) {
......@@ -498,23 +498,23 @@ pub const AllErrors = struct {
498498 }
499499 }
500500 try stderr.writeByte('\n');
501 ttyconf.setColor(stderr, .Reset);
501 try ttyconf.setColor(stderr, .Reset);
502502 }
503503 },
504504 .plain => |plain| {
505 ttyconf.setColor(stderr, color);
505 try ttyconf.setColor(stderr, color);
506506 try stderr.writeByteNTimes(' ', indent);
507507 try stderr.writeAll(kind);
508508 try stderr.writeAll(": ");
509 ttyconf.setColor(stderr, .Reset);
509 try ttyconf.setColor(stderr, .Reset);
510510 if (plain.count == 1) {
511511 try stderr.print("{s}\n", .{plain.msg});
512512 } else {
513513 try stderr.print("{s}", .{plain.msg});
514 ttyconf.setColor(stderr, .Dim);
514 try ttyconf.setColor(stderr, .Dim);
515515 try stderr.print(" ({d} times)\n", .{plain.count});
516516 }
517 ttyconf.setColor(stderr, .Reset);
517 try ttyconf.setColor(stderr, .Reset);
518518 for (plain.notes) |note| {
519519 try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent + 4);
520520 }