diff --git a/CHANGELOG.md b/CHANGELOG.md index 69fc35eace17a56e0bbf99eff1626fbb96ce9cf0..ff2f16993cefa6a4e096634687b07948833207b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - feat: clarify "defined runtime representation" and "can be represented at runtime" - fix(sema): fix passing structs as function params +- fix: diagnostic box drawing characters line up after line 9 +- fix: diagnostics on last line of file print correctly ## 0.1.4 diff --git a/src/core/Report.zig b/src/core/Report.zig index c58c32f0234448ed1f24c073a6de01e0c17bd1a8..86c8df1f8bf7d39d1f66ff2819448a91ebb0a289 100644 --- a/src/core/Report.zig +++ b/src/core/Report.zig @@ -610,8 +610,8 @@ const Prefix = enum { fn symbol(prefix: Prefix, ascii: bool) []const u8 { return switch (prefix) { - .@"error" => if (ascii) " X " else " ✘ ", - .warn => if (ascii) " ! " else " ▲ ", + .@"error" => if (ascii) "X" else "✘", + .warn => if (ascii) "!" else "▲", .note => "", }; } @@ -676,6 +676,17 @@ pub fn formatItem( assert(ctx.components.items.len > 0); + const width = brk: { + var max: usize = 0; + for (ctx.components.items) |component| { + if (component.location) |loc| { + max = @max(loc.loc.line.oneBased(), max); + } + } + + break :brk if (max > 0) std.fmt.count("{d}", .{max}) else 0; + }; + for (ctx.components.items, 1..) |component, i| { const prefix: Prefix = if (i == 1) switch (item_type) { @@ -686,15 +697,18 @@ pub fn formatItem( const is_last = i == ctx.components.items.len; + try writer.writeByteNTimes(' ', width); + if (i != 1) { try tty.setColor(writer, .dim); - try writer.writeAll(" │ "); + try writer.writeAll("│"); try tty.setColor(writer, .reset); } try tty.setColor(writer, prefix.color()); try tty.setColor(writer, .bold); try writer.writeAll(prefix.symbol(false)); + try writer.writeAll(" "); try writer.writeAll(@tagName(prefix)); try tty.setColor(writer, .reset); try tty.setColor(writer, .dim); @@ -712,7 +726,8 @@ pub fn formatItem( const at = component.location orelse { if (is_last) { try tty.setColor(writer, .dim); - try writer.print(" {s}", .{"┴"}); + try writer.writeByteNTimes(' ', width); + try writer.print("{s}", .{"┴"}); try writer.writeAll("\n"); try tty.setColor(writer, .reset); } @@ -721,8 +736,13 @@ pub fn formatItem( const line_before = utf8_source[at.loc.line_start..at.byte]; const trimmed_before = std.mem.trimLeft(u8, line_before, " \t\r"); - const line_after = utf8_source[at.byte + at.slice.len .. at.loc.line_end + 1]; - const width = std.fmt.count("{d}", .{at.loc.line.oneBased()}); + // The text after the highlighted component can be out of bounds if the + // highlighted token is EOF, which is hardcoded to " " to highlight + // empty space after the line. + const line_after = if (at.byte + at.slice.len < at.loc.line_end) + utf8_source[at.byte + at.slice.len .. at.loc.line_end] + else + ""; try tty.setColor(writer, .dim); try writer.writeByteNTimes(' ', width); @@ -741,12 +761,13 @@ pub fn formatItem( try writer.writeAll(at.slice); try tty.setColor(writer, .reset); try writer.writeAll(line_after); + try writer.writeAll("\n"); try tty.setColor(writer, .dim); - try writer.writeAll(if (is_last) " ╰" else " ├"); + try writer.writeByteNTimes(' ', width); + try writer.writeAll(if (is_last) "╰" else "├"); try writer.writeBytesNTimes( "─", - width + - (at.byte - at.loc.line_start) - + 1 + (at.byte - at.loc.line_start) - (line_before.len - trimmed_before.len), ); try tty.setColor(writer, .reset); @@ -912,7 +933,10 @@ pub const Highlight = union(enum) { break :loc .{ .loc = location, - .slice = if (token.tag != .eof) token.slice(ast.utf8_source) else "\n", + .slice = if (token.tag != .eof) + token.slice(ast.utf8_source) + else + " ", .byte = token.offset, }; },