Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

renderErrorMessage

errors.renderErrorMessage
pub fn renderErrorMessage(
    io: Io,
    t: Io.Terminal,
    cwd: Io.Dir,
    err_details: ErrorDetails,
    source: []const u8,
    strings: []const []const u8,
    source_mappings: ?SourceMappings,
) !void

File

Code

pub fn renderErrorMessage(
    io: Io,
    t: Io.Terminal,
    cwd: Io.Dir,
    err_details: ErrorDetails,
    source: []const u8,
    strings: []const []const u8,
    source_mappings: ?SourceMappings,
) !void {
    if (err_details.type == .hint) return;

    const source_line_start = err_details.token.getLineStartForErrorDisplay(source);
    // Treat tab stops as 1 column wide for error display purposes,
    // and add one to get a 1-based column
    const column = err_details.token.calculateColumn(source, 1, source_line_start) + 1;

    const corresponding_span: ?SourceMappings.CorrespondingSpan = if (source_mappings) |mappings|
        mappings.getCorrespondingSpan(err_details.token.line_number)
    else
        null;
    const corresponding_file: ?[]const u8 = if (source_mappings != null and corresponding_span != null)
        source_mappings.?.files.get(corresponding_span.?.filename_offset)
    else
        null;

    const err_line = if (corresponding_span) |span| span.start_line else err_details.token.line_number;

    const writer = t.writer;
    try t.setColor(.bold);
    if (corresponding_file) |file| {
        try writer.writeAll(file);
    } else {
        try t.setColor(.dim);
        try writer.writeAll("<after preprocessor>");
        try t.setColor(.reset);
        try t.setColor(.bold);
    }
    try writer.print(":{d}:{d}: ", .{ err_line, column });
    switch (err_details.type) {
        .err => {
            try t.setColor(.red);
            try writer.writeAll("error: ");
        },
        .warning => {
            try t.setColor(.yellow);
            try writer.writeAll("warning: ");
        },
        .note => {
            try t.setColor(.cyan);
            try writer.writeAll("note: ");
        },
        .hint => unreachable,
    }
    try t.setColor(.reset);
    try t.setColor(.bold);
    try err_details.render(writer, source, strings);
    try writer.writeByte('\n');
    try t.setColor(.reset);

    if (!err_details.print_source_line) {
        try writer.writeByte('\n');
        return;
    }

    const source_line = err_details.token.getLineForErrorDisplay(source, source_line_start);
    const visual_info = err_details.visualTokenInfo(source_line_start, source_line_start + source_line.len, source);
    const truncated_visual_info = ErrorDetails.VisualTokenInfo{
        .before_len = if (visual_info.point_offset > max_source_line_codepoints and visual_info.before_len > 0)
            (visual_info.before_len + 1) -| (visual_info.point_offset - max_source_line_codepoints)
        else
            visual_info.before_len,
        .point_offset = @min(max_source_line_codepoints + 1, visual_info.point_offset),
        .after_len = if (visual_info.point_offset > max_source_line_codepoints)
            @min(truncated_str.len - 3, visual_info.after_len)
        else
            @min(max_source_line_codepoints - visual_info.point_offset + (truncated_str.len - 2), visual_info.after_len),
    };

    // Need this to determine if the 'line originated from' note is worth printing
    var source_line_for_display_buf: [max_source_line_bytes]u8 = undefined;
    const source_line_for_display = writeSourceSlice(&source_line_for_display_buf, source_line, err_details.code_page);

    try writer.writeAll(source_line_for_display.line);
    if (source_line_for_display.truncated) {
        try t.setColor(.dim);
        try writer.writeAll(truncated_str);
        try t.setColor(.reset);
    }
    try writer.writeByte('\n');

    try t.setColor(.green);
    const num_spaces = truncated_visual_info.point_offset - truncated_visual_info.before_len;
    try writer.splatByteAll(' ', num_spaces);
    try writer.splatByteAll('~', truncated_visual_info.before_len);
    try writer.writeByte('^');
    try writer.splatByteAll('~', truncated_visual_info.after_len);
    try writer.writeByte('\n');
    try t.setColor(.reset);

    if (corresponding_span != null and corresponding_file != null) {
        var worth_printing_lines: bool = true;
        var initial_lines_err: ?anyerror = null;
        var file_reader_buf: [max_source_line_bytes * 2]u8 = undefined;
        var corresponding_lines: ?CorrespondingLines = CorrespondingLines.init(
            io,
            cwd,
            err_details,
            source_line_for_display.line,
            corresponding_span.?,
            corresponding_file.?,
            &file_reader_buf,
        ) catch |err| switch (err) {
            error.NotWorthPrintingLines => blk: {
                worth_printing_lines = false;
                break :blk null;
            },
            error.NotWorthPrintingNote => return,
            else => |e| blk: {
                initial_lines_err = e;
                break :blk null;
            },
        };
        defer if (corresponding_lines) |*cl| cl.deinit(io);

        try t.setColor(.bold);
        if (corresponding_file) |file| {
            try writer.writeAll(file);
        } else {
            try t.setColor(.dim);
            try writer.writeAll("<after preprocessor>");
            try t.setColor(.reset);
            try t.setColor(.bold);
        }
        try writer.print(":{d}:{d}: ", .{ err_line, column });
        try t.setColor(.cyan);
        try writer.writeAll("note: ");
        try t.setColor(.reset);
        try t.setColor(.bold);
        try writer.writeAll("this line originated from line");
        if (corresponding_span.?.start_line != corresponding_span.?.end_line) {
            try writer.print("s {}-{}", .{ corresponding_span.?.start_line, corresponding_span.?.end_line });
        } else {
            try writer.print(" {}", .{corresponding_span.?.start_line});
        }
        try writer.print(" of file '{s}'\n", .{corresponding_file.?});
        try t.setColor(.reset);

        if (!worth_printing_lines) return;

        const write_lines_err: ?anyerror = write_lines: {
            if (initial_lines_err) |err| break :write_lines err;
            while (corresponding_lines.?.next() catch |err| {
                break :write_lines err;
            }) |display_line| {
                try writer.writeAll(display_line.line);
                if (display_line.truncated) {
                    try t.setColor(.dim);
                    try writer.writeAll(truncated_str);
                    try t.setColor(.reset);
                }
                try writer.writeByte('\n');
            }
            break :write_lines null;
        };
        if (write_lines_err) |err| {
            try t.setColor(.red);
            try writer.writeAll(" | ");
            try t.setColor(.reset);
            try t.setColor(.dim);
            try writer.print("unable to print line(s) from file: {s}\n", .{@errorName(err)});
            try t.setColor(.reset);
        }
        try writer.writeByte('\n');
    }
}