diff --git a/lib/std/debug.zig b/lib/std/debug.zig index a7badf7ed1..c84a0e0f18 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -462,7 +462,7 @@ pub const TTY = struct { // TODO give this a payload of file handle windows_api, - 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) { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index cff07a2bd2..f60b15f81b 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -31,21 +31,38 @@ pub fn hashSrc(src: []const u8) SrcHash { return out; } -pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } { +pub const Loc = struct { + line: usize, + column: usize, + /// Does not include the trailing newline. + source_line: []const u8, +}; + +pub fn findLineColumn(source: []const u8, byte_offset: usize) Loc { var line: usize = 0; var column: usize = 0; - for (source[0..byte_offset]) |byte| { - switch (byte) { + var line_start: usize = 0; + var i: usize = 0; + while (i < byte_offset) : (i += 1) { + switch (source[i]) { '\n' => { line += 1; column = 0; + line_start = i + 1; }, else => { column += 1; }, } } - return .{ .line = line, .column = column }; + while (i < source.len and source[i] != '\n') { + i += 1; + } + return .{ + .line = line, + .column = column, + .source_line = source[line_start..i], + }; } pub fn lineDelta(source: []const u8, start: usize, end: usize) isize { diff --git a/src/Compilation.zig b/src/Compilation.zig index 080d4bddaa..349963ebe3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -272,28 +272,52 @@ pub const AllErrors = struct { line: u32, column: u32, byte_offset: u32, + /// Does not include the trailing newline. + source_line: ?[]const u8, notes: []Message = &.{}, }, plain: struct { msg: []const u8, }, - pub fn renderToStdErr(msg: Message) void { - return msg.renderToStdErrInner("error"); + pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void { + const stderr_mutex = std.debug.getStderrMutex(); + const held = std.debug.getStderrMutex().acquire(); + defer held.release(); + const stderr = std.io.getStdErr(); + return msg.renderToStdErrInner(ttyconf, stderr, "error", .Red) catch return; } - fn renderToStdErrInner(msg: Message, kind: []const u8) void { + fn renderToStdErrInner( + msg: Message, + ttyconf: std.debug.TTY.Config, + stderr_file: std.fs.File, + kind: []const u8, + color: std.debug.TTY.Color, + ) anyerror!void { + const stderr = stderr_file.writer(); switch (msg) { .src => |src| { - std.debug.print("{s}:{d}:{d}: {s}: {s}\n", .{ + try stderr.print("{s}:{d}:{d}: ", .{ src.src_path, src.line + 1, src.column + 1, - kind, - src.msg, }); + ttyconf.setColor(stderr, color); + try stderr.writeAll(kind); + ttyconf.setColor(stderr, .Bold); + try stderr.print(" {s}\n", .{src.msg}); + ttyconf.setColor(stderr, .Reset); + if (src.source_line) |line| { + try stderr.writeAll(line); + try stderr.writeByte('\n'); + try stderr.writeByteNTimes(' ', src.column); + ttyconf.setColor(stderr, .Green); + try stderr.writeAll("^\n"); + ttyconf.setColor(stderr, .Reset); + } for (src.notes) |note| { - note.renderToStdErrInner("note"); + try note.renderToStdErrInner(ttyconf, stderr_file, "note", .Cyan); } }, .plain => |plain| { @@ -327,6 +351,7 @@ pub const AllErrors = struct { .byte_offset = byte_offset, .line = @intCast(u32, loc.line), .column = @intCast(u32, loc.column), + .source_line = try arena.allocator.dupe(u8, loc.source_line), }, }; } @@ -342,6 +367,7 @@ pub const AllErrors = struct { .line = @intCast(u32, loc.line), .column = @intCast(u32, loc.column), .notes = notes, + .source_line = try arena.allocator.dupe(u8, loc.source_line), }, }); } @@ -1489,6 +1515,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { .byte_offset = 0, .line = err_msg.line, .column = err_msg.column, + .source_line = null, // TODO }, }); } diff --git a/src/main.zig b/src/main.zig index 5fb74db61f..11857fff22 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2106,8 +2106,12 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi defer errors.deinit(comp.gpa); if (errors.list.len != 0) { + const ttyconf: std.debug.TTY.Config = switch (comp.color) { + .auto, .on => std.debug.detectTTYConfig(), + .off => .no_color, + }; for (errors.list) |full_err_msg| { - full_err_msg.renderToStdErr(); + full_err_msg.renderToStdErr(ttyconf); } const log_text = comp.getCompileLogOutput(); if (log_text.len != 0) {