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.

CorrespondingLines

errors.CorrespondingLines
const CorrespondingLines = struct

File

Code

const CorrespondingLines = struct {
    // enough room for one more codepoint, just so that we don't have to keep
    // track of this being truncated, since the extra codepoint will ensure
    // the visual line will need to truncate in that case.
    line_buf: [max_source_line_bytes + 4]u8 = undefined,
    line_len: usize = 0,
    visual_line_buf: [max_source_line_bytes]u8 = undefined,
    visual_line_len: usize = 0,
    truncated: bool = false,
    line_num: usize = 1,
    initial_line: bool = true,
    last_byte: u8 = 0,
    at_eof: bool = false,
    span: SourceMappings.CorrespondingSpan,
    file: Io.File,
    file_reader: Io.File.Reader,
    code_page: SupportedCodePage,

    pub fn init(
        io: Io,
        cwd: Io.Dir,
        err_details: ErrorDetails,
        line_for_comparison: []const u8,
        corresponding_span: SourceMappings.CorrespondingSpan,
        corresponding_file: []const u8,
        file_reader_buf: []u8,
    ) !CorrespondingLines {
        // We don't do line comparison for this error, so don't print the note if the line
        // number is different
        if (err_details.err == .string_literal_too_long and err_details.token.line_number != corresponding_span.start_line) {
            return error.NotWorthPrintingNote;
        }

        // Don't print the originating line for this error, we know it's really long
        if (err_details.err == .string_literal_too_long) {
            return error.NotWorthPrintingLines;
        }

        var corresponding_lines = CorrespondingLines{
            .span = corresponding_span,
            .file = try cwd.openFile(io, corresponding_file, .{ .allow_directory = false }),
            .code_page = err_details.code_page,
            .file_reader = undefined,
        };
        corresponding_lines.file_reader = corresponding_lines.file.reader(io, file_reader_buf);
        errdefer corresponding_lines.deinit(io);

        try corresponding_lines.writeLineFromStreamVerbatim(
            &corresponding_lines.file_reader.interface,
            corresponding_span.start_line,
        );

        const visual_line = writeSourceSlice(
            &corresponding_lines.visual_line_buf,
            corresponding_lines.line_buf[0..corresponding_lines.line_len],
            err_details.code_page,
        );
        corresponding_lines.visual_line_len = visual_line.line.len;
        corresponding_lines.truncated = visual_line.truncated;

        // If the lines are the same as they were before preprocessing, skip printing the note entirely
        if (corresponding_span.start_line == corresponding_span.end_line and std.mem.eql(
            u8,
            line_for_comparison,
            corresponding_lines.visual_line_buf[0..corresponding_lines.visual_line_len],
        )) {
            return error.NotWorthPrintingNote;
        }

        return corresponding_lines;
    }

    pub fn next(self: *CorrespondingLines) !?VisualLine {
        if (self.initial_line) {
            self.initial_line = false;
            return .{
                .line = self.visual_line_buf[0..self.visual_line_len],
                .truncated = self.truncated,
            };
        }
        if (self.line_num > self.span.end_line) return null;
        if (self.at_eof) return error.LinesNotFound;

        self.line_len = 0;
        self.visual_line_len = 0;

        try self.writeLineFromStreamVerbatim(
            &self.file_reader.interface,
            self.line_num,
        );

        const visual_line = writeSourceSlice(
            &self.visual_line_buf,
            self.line_buf[0..self.line_len],
            self.code_page,
        );
        self.visual_line_len = visual_line.line.len;

        return visual_line;
    }

    fn writeLineFromStreamVerbatim(self: *CorrespondingLines, input: *std.Io.Reader, line_num: usize) !void {
        while (try readByteOrEof(input)) |byte| {
            switch (byte) {
                '\n', '\r' => {
                    if (!utils.isLineEndingPair(self.last_byte, byte)) {
                        const line_complete = self.line_num == line_num;
                        self.line_num += 1;
                        if (line_complete) {
                            self.last_byte = byte;
                            return;
                        }
                    } else {
                        // reset last_byte to a non-line ending so that
                        // consecutive CRLF pairs don't get treated as one
                        // long line ending 'pair'
                        self.last_byte = 0;
                        continue;
                    }
                },
                else => {
                    if (self.line_num == line_num and self.line_len < self.line_buf.len) {
                        self.line_buf[self.line_len] = byte;
                        self.line_len += 1;
                    }
                },
            }
            self.last_byte = byte;
        }
        self.at_eof = true;
        // hacky way to get next to return null
        self.line_num += 1;
    }

    fn readByteOrEof(reader: *std.Io.Reader) !?u8 {
        return reader.takeByte() catch |err| switch (err) {
            error.EndOfStream => return null,
            else => |e| return e,
        };
    }

    pub fn deinit(self: *CorrespondingLines, io: Io) void {
        self.file.close(io);
    }
}