Fix diagnostic print

This commit is contained in:
nub31
2025-10-20 19:07:08 +02:00
parent b71e10f55b
commit 7697f7b7cc
3 changed files with 116 additions and 104 deletions

View File

@@ -82,121 +82,124 @@ public class Diagnostic
public string FormatANSI() public string FormatANSI()
{ {
try var sb = new StringBuilder();
sb.Append(Severity switch
{ {
var sb = new StringBuilder(); DiagnosticSeverity.Error => ConsoleColors.Colorize("error", ConsoleColors.Bold + ConsoleColors.Red),
DiagnosticSeverity.Warning => ConsoleColors.Colorize("warning", ConsoleColors.Bold + ConsoleColors.Yellow),
DiagnosticSeverity.Info => ConsoleColors.Colorize("info", ConsoleColors.Bold + ConsoleColors.Blue),
_ => ConsoleColors.Colorize("unknown", ConsoleColors.Bold + ConsoleColors.White)
});
sb.Append(Severity switch if (Span.HasValue)
{ {
DiagnosticSeverity.Error => ConsoleColors.Colorize("error", ConsoleColors.Bold + ConsoleColors.Red), sb.Append(ConsoleColors.Colorize($" at {Span.Value}", ConsoleColors.Faint));
DiagnosticSeverity.Warning => ConsoleColors.Colorize("warning", ConsoleColors.Bold + ConsoleColors.Yellow), }
DiagnosticSeverity.Info => ConsoleColors.Colorize("info", ConsoleColors.Bold + ConsoleColors.Blue),
_ => ConsoleColors.Colorize("unknown", ConsoleColors.Bold + ConsoleColors.White)
});
if (Span.HasValue) sb.Append(": ");
sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite));
if (Span.HasValue)
{
sb.AppendLine();
var text = File.ReadAllText(Span.Value.FilePath);
var tokenizer = new Tokenizer(Span.Value.FilePath, text);
tokenizer.Tokenize();
var lines = text.Split('\n');
var startLine = Span.Value.Start.Line;
var endLine = Span.Value.End.Line;
const int CONTEXT_LINES = 3;
var contextStartLine = Math.Max(1, startLine - CONTEXT_LINES);
var contextEndLine = Math.Min(lines.Length, endLine + CONTEXT_LINES);
var numberPadding = contextEndLine.ToString().Length;
var codePadding = 0;
for (var i = contextStartLine - 1; i < contextEndLine && i < lines.Length; i++)
{ {
sb.Append(ConsoleColors.Colorize($" at {Span.Value}", ConsoleColors.Faint)); var lineLength = lines[i].Length;
if (lineLength > codePadding)
{
codePadding = lineLength;
}
} }
sb.Append(": "); sb.Append('╭');
sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite)); sb.Append(new string('─', numberPadding + 2));
sb.Append('┬');
sb.Append(new string('─', codePadding + 2));
sb.Append('╮');
sb.AppendLine();
if (Span.HasValue) for (var i = contextStartLine; i <= contextEndLine; i++)
{ {
sb.AppendLine(); var line = lines[i - 1];
var text = File.ReadAllText(Span.Value.FilePath);
var lines = text.Split('\n'); sb.Append("│ ");
sb.Append(i.ToString().PadRight(numberPadding));
var startLine = Span.Value.Start.Line; sb.Append(" │ ");
var endLine = Span.Value.End.Line; sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens));
// sb.Append(line.PadRight(codePadding));
const int CONTEXT_LINES = 3; sb.Append(" │");
var contextStartLine = Math.Max(1, startLine - CONTEXT_LINES);
var contextEndLine = Math.Min(lines.Length, endLine + CONTEXT_LINES);
var numberPadding = contextEndLine.ToString().Length;
var codePadding = lines.Skip(contextStartLine - 1).Take(contextEndLine - contextStartLine + 1).Max(x => x.Length);
sb.Append('╭');
sb.Append(new string('─', numberPadding + 2));
sb.Append('┬');
sb.Append(new string('─', codePadding + 2));
sb.Append('╮');
sb.AppendLine(); sb.AppendLine();
var tokenizer = new Tokenizer(Span.Value.FilePath, text); if (i >= startLine && i <= endLine)
tokenizer.Tokenize();
for (var i = contextStartLine; i <= contextEndLine; i++)
{ {
var line = lines[i - 1]; var markerStartColumn = 1;
var markerEndColumn = line.Length;
if (i == startLine)
{
markerStartColumn = Span.Value.Start.Column;
}
if (i == endLine)
{
markerEndColumn = Span.Value.End.Column;
}
var markerLength = markerEndColumn - markerStartColumn;
var marker = new string('^', markerLength);
var markerColor = Severity switch
{
DiagnosticSeverity.Info => ConsoleColors.Blue,
DiagnosticSeverity.Warning => ConsoleColors.Yellow,
DiagnosticSeverity.Error => ConsoleColors.Red,
_ => ConsoleColors.White
};
sb.Append("│ "); sb.Append("│ ");
sb.Append(i.ToString().PadRight(numberPadding)); sb.Append(new string(' ', numberPadding));
sb.Append(" │ "); sb.Append(" │ ");
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens)); sb.Append(new string(' ', markerStartColumn - 1));
sb.Append(ConsoleColors.Colorize(marker, markerColor));
sb.Append(new string(' ', codePadding - (markerStartColumn - 1) - markerLength));
sb.Append(" │"); sb.Append(" │");
sb.AppendLine(); sb.AppendLine();
if (i >= startLine && i <= endLine)
{
var markerStartColumn = 1;
var markerEndColumn = line.Length;
if (i == startLine)
{
markerStartColumn = Math.Min(Span.Value.Start.Column, 1);
}
if (i == endLine)
{
markerEndColumn = Math.Min(Span.Value.End.Column, line.Length);
}
var markerLength = markerEndColumn - markerStartColumn;
var marker = new string('^', markerLength);
var markerColor = Severity switch
{
DiagnosticSeverity.Info => ConsoleColors.Blue,
DiagnosticSeverity.Warning => ConsoleColors.Yellow,
DiagnosticSeverity.Error => ConsoleColors.Red,
_ => ConsoleColors.White
};
sb.Append("│ ");
sb.Append(new string(' ', numberPadding));
sb.Append(" │ ");
sb.Append(new string(' ', markerStartColumn - 1));
sb.Append(ConsoleColors.Colorize(marker, markerColor));
sb.Append(new string(' ', codePadding - markerEndColumn + 1));
sb.Append(" │");
sb.AppendLine();
}
} }
sb.Append('╰');
sb.Append(new string('─', numberPadding + 2));
sb.Append('┴');
sb.Append(new string('─', codePadding + 2));
sb.Append('╯');
} }
if (Help != null) sb.Append('╰');
{ sb.Append(new string('─', numberPadding + 2));
sb.AppendLine(); sb.Append('┴');
sb.Append(ConsoleColors.Colorize($"help: {Help}", ConsoleColors.Cyan)); sb.Append(new string('─', codePadding + 2));
} sb.Append('╯');
return sb.ToString();
} }
catch (Exception)
if (Help != null)
{ {
return ConsoleColors.Colorize("Failed to generate error message", ConsoleColors.Red); sb.AppendLine();
sb.Append(ConsoleColors.Colorize($"help: {Help}", ConsoleColors.Cyan));
} }
return sb.ToString();
} }
private static string ApplySyntaxHighlighting(string line, int lineNumber, List<Token> tokens) private static string ApplySyntaxHighlighting(string line, int lineNumber, List<Token> tokens)
@@ -219,25 +222,34 @@ public class Diagnostic
var tokenStart = token.Span.Start.Column; var tokenStart = token.Span.Start.Column;
var tokenEnd = token.Span.End.Column; var tokenEnd = token.Span.End.Column;
if (tokenStart > currentColumn) if (tokenStart > currentColumn && currentColumn - 1 < line.Length)
{ {
var beforeToken = line.Substring(currentColumn - 1, tokenStart - currentColumn); var beforeLength = Math.Min(tokenStart - currentColumn, line.Length - (currentColumn - 1));
sb.Append(beforeToken); if (beforeLength > 0)
{
var beforeToken = line.Substring(currentColumn - 1, beforeLength);
sb.Append(beforeToken);
}
} }
var tokenLength = tokenEnd - tokenStart; var tokenLength = tokenEnd - tokenStart;
if (tokenStart - 1 + tokenLength <= line.Length) if (tokenStart >= 1 && tokenStart - 1 < line.Length && tokenLength > 0)
{ {
var tokenText = line.Substring(tokenStart - 1, tokenLength); var availableLength = line.Length - (tokenStart - 1);
var actualLength = Math.Min(tokenLength, availableLength);
var coloredToken = ColorizeToken(token, tokenText); if (actualLength > 0)
sb.Append(coloredToken); {
var tokenText = line.Substring(tokenStart - 1, actualLength);
var coloredToken = ColorizeToken(token, tokenText);
sb.Append(coloredToken);
}
} }
currentColumn = tokenEnd; currentColumn = tokenEnd;
} }
if (currentColumn <= line.Length) if (currentColumn - 1 < line.Length)
{ {
var remaining = line[(currentColumn - 1)..]; var remaining = line[(currentColumn - 1)..];
sb.Append(remaining); sb.Append(remaining);

View File

@@ -90,23 +90,23 @@ public sealed class Tokenizer
{ {
try try
{ {
// Skip whitespace and increment line counter if newline
var current = Peek()!.Value; var current = Peek()!.Value;
if (char.IsWhiteSpace(current)) if (char.IsWhiteSpace(current))
{ {
if (current is '\n') if (current is '\n')
{ {
_line += 1; _line += 1;
_column = 1; // note(nub31): Next increments the column, so 0 is correct here
_column = 0;
} }
Next(); Next();
continue; continue;
} }
// Skip single line comments but keep newline so next iteration increments the line counter
if (current == '/' && Peek(1) == '/') if (current == '/' && Peek(1) == '/')
{ {
// note(nub31): Keep newline so next iteration increments the line counter
while (Peek() is not '\n') while (Peek() is not '\n')
{ {
Next(); Next();

View File

@@ -4,7 +4,7 @@ module "main"
extern "main" func main(args: []cstring): i64 extern "main" func main(args: []cstring): i64
{ {
raylib::SetConfigFlags(4 | 64) raylib: :SetConfigFlags(4 | 64)
raylib::InitWindow(1600, 900, "Hi from nub-lang") raylib::InitWindow(1600, 900, "Hi from nub-lang")
defer raylib::CloseWindow() defer raylib::CloseWindow()