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()
{
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
{
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)
});
if (Span.HasValue)
{
sb.Append(ConsoleColors.Colorize($" at {Span.Value}", ConsoleColors.Faint));
}
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(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite));
sb.Append('╭');
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 text = File.ReadAllText(Span.Value.FilePath);
var line = lines[i - 1];
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 = 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.Append("│ ");
sb.Append(i.ToString().PadRight(numberPadding));
sb.Append(" │ ");
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens));
// sb.Append(line.PadRight(codePadding));
sb.Append(" │");
sb.AppendLine();
var tokenizer = new Tokenizer(Span.Value.FilePath, text);
tokenizer.Tokenize();
for (var i = contextStartLine; i <= contextEndLine; i++)
if (i >= startLine && i <= endLine)
{
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(i.ToString().PadRight(numberPadding));
sb.Append(new string(' ', numberPadding));
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.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.AppendLine();
sb.Append(ConsoleColors.Colorize($"help: {Help}", ConsoleColors.Cyan));
}
return sb.ToString();
sb.Append('╰');
sb.Append(new string('─', numberPadding + 2));
sb.Append('┴');
sb.Append(new string('─', codePadding + 2));
sb.Append('╯');
}
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)
@@ -219,25 +222,34 @@ public class Diagnostic
var tokenStart = token.Span.Start.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);
sb.Append(beforeToken);
var beforeLength = Math.Min(tokenStart - currentColumn, line.Length - (currentColumn - 1));
if (beforeLength > 0)
{
var beforeToken = line.Substring(currentColumn - 1, beforeLength);
sb.Append(beforeToken);
}
}
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);
sb.Append(coloredToken);
if (actualLength > 0)
{
var tokenText = line.Substring(tokenStart - 1, actualLength);
var coloredToken = ColorizeToken(token, tokenText);
sb.Append(coloredToken);
}
}
currentColumn = tokenEnd;
}
if (currentColumn <= line.Length)
if (currentColumn - 1 < line.Length)
{
var remaining = line[(currentColumn - 1)..];
sb.Append(remaining);

View File

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

View File

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