Commit d8b4588d5f

r00ster91 <r00ster91@proton.me>
2022-07-30 14:13:53
fix(terminal): handle some possible errors and resolve TODOs
1 parent 8691fde
lib/std/debug.zig
@@ -119,7 +119,7 @@ pub fn detectTTYConfig() TTY.Config {
         if (stderr_file.supportsAnsiEscapeCodes()) {
             return .escape_codes;
         } else if (native_os == .windows and stderr_file.isTty()) {
-            return .windows_api;
+            return .{ .windows_api = stderr_file };
         } else {
             return .no_color;
         }
@@ -415,9 +415,9 @@ pub fn writeStackTrace(
     if (stack_trace.index > stack_trace.instruction_addresses.len) {
         const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len;
 
-        tty_config.setColor(out_stream, .Bold);
+        tty_config.setColor(out_stream, .Bold) catch {};
         try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
-        tty_config.setColor(out_stream, .Reset);
+        tty_config.setColor(out_stream, .Reset) catch {};
     }
 }
 
@@ -605,59 +605,39 @@ pub const TTY = struct {
         Reset,
     };
 
-    pub const Config = enum {
+    pub const Config = union(enum) {
         no_color,
         escape_codes,
-        // TODO give this a payload of file handle
-        windows_api,
+        windows_api: File,
 
-        pub fn setColor(conf: Config, out_stream: anytype, color: Color) void {
+        pub fn setColor(conf: Config, out_stream: anytype, color: Color) !void {
             nosuspend switch (conf) {
                 .no_color => return,
-                .escape_codes => switch (color) {
-                    .Red => out_stream.writeAll(RED) catch return,
-                    .Green => out_stream.writeAll(GREEN) catch return,
-                    .Cyan => out_stream.writeAll(CYAN) catch return,
-                    .White => out_stream.writeAll(WHITE) catch return,
-                    .Dim => out_stream.writeAll(DIM) catch return,
-                    .Bold => out_stream.writeAll(BOLD) catch return,
-                    .Reset => out_stream.writeAll(RESET) catch return,
+                .escape_codes => {
+                    const color_string = switch (color) {
+                        .Red => RED,
+                        .Green => GREEN,
+                        .Cyan => CYAN,
+                        .White => WHITE,
+                        .Dim => DIM,
+                        .Bold => BOLD,
+                        .Reset => RESET,
+                    };
+                    try out_stream.writeAll(color_string);
                 },
-                .windows_api => if (native_os == .windows) {
-                    const stderr_file = io.getStdErr();
-                    const S = struct {
-                        var attrs: windows.WORD = undefined;
-                        var init_attrs = false;
+                .windows_api => |file| if (native_os == .windows) {
+                    var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
+                    if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE)
+                        return error.FailedRetrievingTerminalInfo;
+                    const attributes = switch (color) {
+                        .Red => windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY,
+                        .Green => windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
+                        .Cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
+                        .White, .Bold => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
+                        .Dim => windows.FOREGROUND_INTENSITY,
+                        .Reset => info.wAttributes,
                     };
-                    if (!S.init_attrs) {
-                        S.init_attrs = true;
-                        var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
-                        // TODO handle error
-                        _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
-                        S.attrs = info.wAttributes;
-                    }
-
-                    // TODO handle errors
-                    switch (color) {
-                        .Red => {
-                            _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {};
-                        },
-                        .Green => {
-                            _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {};
-                        },
-                        .Cyan => {
-                            _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
-                        },
-                        .White, .Bold => {
-                            _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
-                        },
-                        .Dim => {
-                            _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {};
-                        },
-                        .Reset => {
-                            _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {};
-                        },
-                    }
+                    try windows.SetConsoleTextAttribute(file.handle, attributes);
                 } else {
                     unreachable;
                 },
@@ -751,7 +731,7 @@ fn printLineInfo(
     comptime printLineFromFile: anytype,
 ) !void {
     nosuspend {
-        tty_config.setColor(out_stream, .Bold);
+        try tty_config.setColor(out_stream, .Bold);
 
         if (line_info) |*li| {
             try out_stream.print("{s}:{d}:{d}", .{ li.file_name, li.line, li.column });
@@ -759,11 +739,11 @@ fn printLineInfo(
             try out_stream.writeAll("???:?:?");
         }
 
-        tty_config.setColor(out_stream, .Reset);
+        try tty_config.setColor(out_stream, .Reset);
         try out_stream.writeAll(": ");
-        tty_config.setColor(out_stream, .Dim);
+        try tty_config.setColor(out_stream, .Dim);
         try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
-        tty_config.setColor(out_stream, .Reset);
+        try tty_config.setColor(out_stream, .Reset);
         try out_stream.writeAll("\n");
 
         // Show the matching source code line if possible
@@ -774,9 +754,9 @@ fn printLineInfo(
                     const space_needed = @intCast(usize, li.column - 1);
 
                     try out_stream.writeByteNTimes(' ', space_needed);
-                    tty_config.setColor(out_stream, .Green);
+                    try tty_config.setColor(out_stream, .Green);
                     try out_stream.writeAll("^");
-                    tty_config.setColor(out_stream, .Reset);
+                    try tty_config.setColor(out_stream, .Reset);
                 }
                 try out_stream.writeAll("\n");
             } else |err| switch (err) {
lib/std/Progress.zig
@@ -210,8 +210,11 @@ fn refreshWithHeldLock(self: *Progress) void {
             std.debug.assert(self.is_windows_terminal);
 
             var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
-            if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE)
-                unreachable;
+            if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) {
+                // stop trying to write to this file
+                self.terminal = null;
+                break :winapi;
+            }
 
             var cursor_pos = windows.COORD{
                 .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written),
@@ -231,7 +234,7 @@ fn refreshWithHeldLock(self: *Progress) void {
                 cursor_pos,
                 &written,
             ) != windows.TRUE) {
-                // Stop trying to write to this file.
+                // stop trying to write to this file
                 self.terminal = null;
                 break :winapi;
             }
@@ -241,10 +244,16 @@ fn refreshWithHeldLock(self: *Progress) void {
                 fill_chars,
                 cursor_pos,
                 &written,
-            ) != windows.TRUE) unreachable;
-
-            if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE)
-                unreachable;
+            ) != windows.TRUE) {
+                // stop trying to write to this file
+                self.terminal = null;
+                break :winapi;
+            }
+            if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) {
+                // stop trying to write to this file
+                self.terminal = null;
+                break :winapi;
+            }
         } else {
             // we are in a "dumb" terminal like in acme or writing to a file
             self.output_buffer[end] = '\n';
@@ -288,7 +297,7 @@ fn refreshWithHeldLock(self: *Progress) void {
     }
 
     _ = file.write(self.output_buffer[0..end]) catch {
-        // Stop trying to write to this file once it errors.
+        // stop trying to write to this file
         self.terminal = null;
     };
     if (self.timer) |*timer| {
lib/std/testing.zig
@@ -387,9 +387,9 @@ fn SliceDiffer(comptime T: type) type {
             for (self.expected) |value, i| {
                 var full_index = self.start_index + i;
                 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
-                if (diff) self.ttyconf.setColor(writer, .Red);
+                if (diff) try self.ttyconf.setColor(writer, .Red);
                 try writer.print("[{}]: {any}\n", .{ full_index, value });
-                if (diff) self.ttyconf.setColor(writer, .Reset);
+                if (diff) try self.ttyconf.setColor(writer, .Reset);
             }
         }
     };
@@ -427,9 +427,9 @@ const BytesDiffer = struct {
     }
 
     fn writeByteDiff(self: BytesDiffer, writer: anytype, comptime fmt: []const u8, byte: u8, diff: bool) !void {
-        if (diff) self.ttyconf.setColor(writer, .Red);
+        if (diff) try self.ttyconf.setColor(writer, .Red);
         try writer.print(fmt, .{byte});
-        if (diff) self.ttyconf.setColor(writer, .Reset);
+        if (diff) try self.ttyconf.setColor(writer, .Reset);
     }
 
     const ChunkIterator = struct {
src/Compilation.zig
@@ -428,29 +428,29 @@ pub const AllErrors = struct {
             switch (msg) {
                 .src => |src| {
                     try counting_stderr.writeByteNTimes(' ', indent);
-                    ttyconf.setColor(stderr, .Bold);
+                    try ttyconf.setColor(stderr, .Bold);
                     try counting_stderr.print("{s}:{d}:{d}: ", .{
                         src.src_path,
                         src.line + 1,
                         src.column + 1,
                     });
-                    ttyconf.setColor(stderr, color);
+                    try ttyconf.setColor(stderr, color);
                     try counting_stderr.writeAll(kind);
                     try counting_stderr.writeAll(": ");
                     // This is the length of the part before the error message:
                     // e.g. "file.zig:4:5: error: "
                     const prefix_len = @intCast(usize, counting_stderr.context.bytes_written);
-                    ttyconf.setColor(stderr, .Reset);
-                    ttyconf.setColor(stderr, .Bold);
+                    try ttyconf.setColor(stderr, .Reset);
+                    try ttyconf.setColor(stderr, .Bold);
                     if (src.count == 1) {
                         try src.writeMsg(stderr, prefix_len);
                         try stderr.writeByte('\n');
                     } else {
                         try src.writeMsg(stderr, prefix_len);
-                        ttyconf.setColor(stderr, .Dim);
+                        try ttyconf.setColor(stderr, .Dim);
                         try stderr.print(" ({d} times)\n", .{src.count});
                     }
-                    ttyconf.setColor(stderr, .Reset);
+                    try ttyconf.setColor(stderr, .Reset);
                     if (src.source_line) |line| {
                         for (line) |b| switch (b) {
                             '\t' => try stderr.writeByte(' '),
@@ -462,19 +462,19 @@ pub const AllErrors = struct {
                         // -1 since span.main includes the caret
                         const after_caret = src.span.end - src.span.main -| 1;
                         try stderr.writeByteNTimes(' ', src.column - before_caret);
-                        ttyconf.setColor(stderr, .Green);
+                        try ttyconf.setColor(stderr, .Green);
                         try stderr.writeByteNTimes('~', before_caret);
                         try stderr.writeByte('^');
                         try stderr.writeByteNTimes('~', after_caret);
                         try stderr.writeByte('\n');
-                        ttyconf.setColor(stderr, .Reset);
+                        try ttyconf.setColor(stderr, .Reset);
                     }
                     for (src.notes) |note| {
                         try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent);
                     }
                     if (src.reference_trace.len != 0) {
-                        ttyconf.setColor(stderr, .Reset);
-                        ttyconf.setColor(stderr, .Dim);
+                        try ttyconf.setColor(stderr, .Reset);
+                        try ttyconf.setColor(stderr, .Dim);
                         try stderr.print("referenced by:\n", .{});
                         for (src.reference_trace) |reference| {
                             switch (reference) {
@@ -498,23 +498,23 @@ pub const AllErrors = struct {
                             }
                         }
                         try stderr.writeByte('\n');
-                        ttyconf.setColor(stderr, .Reset);
+                        try ttyconf.setColor(stderr, .Reset);
                     }
                 },
                 .plain => |plain| {
-                    ttyconf.setColor(stderr, color);
+                    try ttyconf.setColor(stderr, color);
                     try stderr.writeByteNTimes(' ', indent);
                     try stderr.writeAll(kind);
                     try stderr.writeAll(": ");
-                    ttyconf.setColor(stderr, .Reset);
+                    try ttyconf.setColor(stderr, .Reset);
                     if (plain.count == 1) {
                         try stderr.print("{s}\n", .{plain.msg});
                     } else {
                         try stderr.print("{s}", .{plain.msg});
-                        ttyconf.setColor(stderr, .Dim);
+                        try ttyconf.setColor(stderr, .Dim);
                         try stderr.print(" ({d} times)\n", .{plain.count});
                     }
-                    ttyconf.setColor(stderr, .Reset);
+                    try ttyconf.setColor(stderr, .Reset);
                     for (plain.notes) |note| {
                         try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent + 4);
                     }