| ... | ... | @@ -344,6 +344,20 @@ pub const AllErrors = struct { |
| 344 | 344 | /// Does not include the trailing newline. |
| 345 | 345 | source_line: ?[]const u8, |
| 346 | 346 | notes: []Message = &.{}, |
| 347 | |
| 348 | /// Splits the error message up into lines to properly indent them |
| 349 | /// to allow for long, good-looking error messages. |
| 350 | /// |
| 351 | /// This is used to split the message in `@compileError("hello\nworld")` for example. |
| 352 | fn writeMsg(src: @This(), stderr: anytype, indent: usize) !void { |
| 353 | var lines = mem.split(u8, src.msg, "\n"); |
| 354 | while (lines.next()) |line| { |
| 355 | try stderr.writeAll(line); |
| 356 | if (lines.index == null) break; |
| 357 | try stderr.writeByte('\n'); |
| 358 | try stderr.writeByteNTimes(' ', indent); |
| 359 | } |
| 360 | } |
| 347 | 361 | }, |
| 348 | 362 | plain: struct { |
| 349 | 363 | msg: []const u8, |
| ... | ... | @@ -367,35 +381,41 @@ pub const AllErrors = struct { |
| 367 | 381 | std.debug.getStderrMutex().lock(); |
| 368 | 382 | defer std.debug.getStderrMutex().unlock(); |
| 369 | 383 | const stderr = std.io.getStdErr(); |
| 370 | | return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red, 0) catch return; |
| 384 | return msg.renderToWriter(ttyconf, stderr.writer(), "error", .Red, 0) catch return; |
| 371 | 385 | } |
| 372 | 386 | |
| 373 | | fn renderToStdErrInner( |
| 387 | pub fn renderToWriter( |
| 374 | 388 | msg: Message, |
| 375 | 389 | ttyconf: std.debug.TTY.Config, |
| 376 | | stderr_file: std.fs.File, |
| 390 | stderr: anytype, |
| 377 | 391 | kind: []const u8, |
| 378 | 392 | color: std.debug.TTY.Color, |
| 379 | 393 | indent: usize, |
| 380 | 394 | ) anyerror!void { |
| 381 | | const stderr = stderr_file.writer(); |
| 395 | var counting_writer = std.io.countingWriter(stderr); |
| 396 | const counting_stderr = counting_writer.writer(); |
| 382 | 397 | switch (msg) { |
| 383 | 398 | .src => |src| { |
| 384 | | try stderr.writeByteNTimes(' ', indent); |
| 399 | try counting_stderr.writeByteNTimes(' ', indent); |
| 385 | 400 | ttyconf.setColor(stderr, .Bold); |
| 386 | | try stderr.print("{s}:{d}:{d}: ", .{ |
| 401 | try counting_stderr.print("{s}:{d}:{d}: ", .{ |
| 387 | 402 | src.src_path, |
| 388 | 403 | src.line + 1, |
| 389 | 404 | src.column + 1, |
| 390 | 405 | }); |
| 391 | 406 | ttyconf.setColor(stderr, color); |
| 392 | | try stderr.writeAll(kind); |
| 407 | try counting_stderr.writeAll(kind); |
| 408 | try counting_stderr.writeAll(": "); |
| 409 | // This is the length of the part before the error message: |
| 410 | // e.g. "file.zig:4:5: error: " |
| 411 | const prefix_len = @intCast(usize, counting_stderr.context.bytes_written); |
| 393 | 412 | ttyconf.setColor(stderr, .Reset); |
| 394 | 413 | ttyconf.setColor(stderr, .Bold); |
| 395 | 414 | if (src.count == 1) { |
| 396 | | try stderr.print(" {s}\n", .{src.msg}); |
| 415 | try src.writeMsg(stderr, prefix_len); |
| 416 | try stderr.writeByte('\n'); |
| 397 | 417 | } else { |
| 398 | | try stderr.print(" {s}", .{src.msg}); |
| 418 | try src.writeMsg(stderr, prefix_len); |
| 399 | 419 | ttyconf.setColor(stderr, .Dim); |
| 400 | 420 | try stderr.print(" ({d} times)\n", .{src.count}); |
| 401 | 421 | } |
| ... | ... | @@ -414,24 +434,25 @@ pub const AllErrors = struct { |
| 414 | 434 | } |
| 415 | 435 | } |
| 416 | 436 | for (src.notes) |note| { |
| 417 | | try note.renderToStdErrInner(ttyconf, stderr_file, "note:", .Cyan, indent); |
| 437 | try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent); |
| 418 | 438 | } |
| 419 | 439 | }, |
| 420 | 440 | .plain => |plain| { |
| 421 | 441 | ttyconf.setColor(stderr, color); |
| 422 | 442 | try stderr.writeByteNTimes(' ', indent); |
| 423 | 443 | try stderr.writeAll(kind); |
| 444 | try stderr.writeAll(": "); |
| 424 | 445 | ttyconf.setColor(stderr, .Reset); |
| 425 | 446 | if (plain.count == 1) { |
| 426 | | try stderr.print(" {s}\n", .{plain.msg}); |
| 447 | try stderr.print("{s}\n", .{plain.msg}); |
| 427 | 448 | } else { |
| 428 | | try stderr.print(" {s}", .{plain.msg}); |
| 449 | try stderr.print("{s}", .{plain.msg}); |
| 429 | 450 | ttyconf.setColor(stderr, .Dim); |
| 430 | 451 | try stderr.print(" ({d} times)\n", .{plain.count}); |
| 431 | 452 | } |
| 432 | 453 | ttyconf.setColor(stderr, .Reset); |
| 433 | 454 | for (plain.notes) |note| { |
| 434 | | try note.renderToStdErrInner(ttyconf, stderr_file, "error:", .Red, indent + 4); |
| 455 | try note.renderToWriter(ttyconf, stderr, "error", .Red, indent + 4); |
| 435 | 456 | } |
| 436 | 457 | }, |
| 437 | 458 | } |