Prettier errors
This commit is contained in:
parent
e389e46852
commit
3d1cd89067
6 changed files with 313 additions and 48 deletions
|
|
@ -93,6 +93,21 @@ export class SourceText {
|
|||
// TODO: Consider removing \r or \n from the end if they exist.
|
||||
return this.sliceByCp(startCp, endCp);
|
||||
}
|
||||
|
||||
getLineRange(line: number): { start: CodePointIndex, end: CodePointIndex } {
|
||||
const lineIndex = line - 1;
|
||||
if (lineIndex < 0 || lineIndex >= this.lineStarts.length) {
|
||||
// TODO: This is a bit suspicious. Maybe return undefined?
|
||||
return { start: 0, end: 0 };
|
||||
}
|
||||
|
||||
const start = this.lineStarts[lineIndex];
|
||||
const end = (lineIndex + 1 < this.lineStarts.length)
|
||||
? this.lineStarts[lineIndex + 1]
|
||||
: this.chars.length;
|
||||
|
||||
return { start, end };
|
||||
}
|
||||
}
|
||||
|
||||
export function sourceText(s: string) {
|
||||
|
|
@ -100,17 +115,15 @@ export function sourceText(s: string) {
|
|||
}
|
||||
|
||||
export type Span = {
|
||||
start: StringIndex,
|
||||
end: StringIndex,
|
||||
line: number,
|
||||
column: number,
|
||||
start: SourceLocation;
|
||||
end: SourceLocation;
|
||||
}
|
||||
|
||||
export type SourceLocation = {
|
||||
index: CodePointIndex;
|
||||
line: number; // 1-based
|
||||
column: number; // 1-based
|
||||
};
|
||||
}
|
||||
|
||||
// Whitespace
|
||||
export const NEW_LINE: CodePoint = char('\n');
|
||||
|
|
@ -130,3 +143,97 @@ export const UPPERCASE_A: CodePoint = char('A');
|
|||
export const LOWERCASE_f: CodePoint = char('f');
|
||||
export const UPPERCASE_F: CodePoint = char('F');
|
||||
|
||||
// === Rendering Utilities ===
|
||||
|
||||
export type LineView = {
|
||||
lineNo: number;
|
||||
sourceLine: string; // The full raw text of the line
|
||||
|
||||
// These split the line into 3 parts for coloring:
|
||||
// prefix | highlight | suffix
|
||||
prefix: string;
|
||||
highlight: string;
|
||||
suffix: string;
|
||||
|
||||
// Helpers for underlines (e.g., " ^^^^^")
|
||||
gutterPad: string; // Padding to align line numbers
|
||||
underline: string; // The literal "^^^" string for CLI usage
|
||||
};
|
||||
|
||||
export function renderSpan(text: SourceText, span: Span, contextLines = 1): LineView[] {
|
||||
const views: LineView[] = [];
|
||||
|
||||
// Determine range of lines to show (including context)
|
||||
const startLine = Math.max(1, span.start.line - contextLines);
|
||||
const endLine = Math.min(text.lineStarts.length, span.end.line + contextLines);
|
||||
|
||||
// Calculate the max width of line numbers for nice padding (e.g. " 9 |" vs " 10 |")
|
||||
const maxLineNoWidth = endLine.toString().length;
|
||||
|
||||
for (let lineNo = startLine; lineNo <= endLine; lineNo++) {
|
||||
const lineRange = text.getLineRange(lineNo);
|
||||
|
||||
// We strip the trailing newline for display purposes
|
||||
let lineRaw = text.sliceByCp(lineRange.start, lineRange.end);
|
||||
if (lineRaw.endsWith('\n') || lineRaw.endsWith('\r')) {
|
||||
lineRaw = lineRaw.trimEnd();
|
||||
}
|
||||
|
||||
// Determine the intersection of the Span with this specific Line
|
||||
|
||||
// 1. Where does the highlight start on this line?
|
||||
// If this is the start line, use span.column. Otherwise start at 0 (beginning of line)
|
||||
// We subtract 1 because columns are 1-based, string indices are 0-based.
|
||||
const highlightStartCol = (lineNo === span.start.line)
|
||||
? span.start.column - 1
|
||||
: 0;
|
||||
|
||||
// 2. Where does the highlight end on this line?
|
||||
// If this is the end line, use span.column. Otherwise end at the string length.
|
||||
const highlightEndCol = (lineNo === span.end.line)
|
||||
? span.end.column - 1
|
||||
: lineRaw.length;
|
||||
|
||||
// Logic to distinguish context lines from error lines
|
||||
const isErrorLine = lineNo >= span.start.line && lineNo <= span.end.line;
|
||||
|
||||
let prefix = "", highlight = "", suffix = "";
|
||||
|
||||
if (isErrorLine) {
|
||||
// Clamp indices to bounds (safety)
|
||||
const safeStart = Math.max(0, Math.min(highlightStartCol, lineRaw.length));
|
||||
const safeEnd = Math.max(0, Math.min(highlightEndCol, lineRaw.length));
|
||||
|
||||
prefix = lineRaw.substring(0, safeStart);
|
||||
highlight = lineRaw.substring(safeStart, safeEnd);
|
||||
suffix = lineRaw.substring(safeEnd);
|
||||
} else {
|
||||
// Pure context line
|
||||
prefix = lineRaw;
|
||||
}
|
||||
|
||||
// Build the "underline" string (e.g., " ^^^^")
|
||||
// Note: This naive approach assumes monospaced fonts and no fancy unicode widths,
|
||||
// which usually holds for code.
|
||||
let underline = "";
|
||||
if (isErrorLine) {
|
||||
// Spaces for prefix
|
||||
underline += " ".repeat(prefix.length);
|
||||
// Carets for highlight (ensure at least 1 if it's a zero-width cursor position)
|
||||
const hlLen = Math.max(1, highlight.length);
|
||||
underline += "^".repeat(hlLen);
|
||||
}
|
||||
|
||||
views.push({
|
||||
lineNo,
|
||||
sourceLine: lineRaw,
|
||||
prefix,
|
||||
highlight,
|
||||
suffix,
|
||||
gutterPad: " ".repeat(maxLineNoWidth - lineNo.toString().length),
|
||||
underline
|
||||
});
|
||||
}
|
||||
|
||||
return views;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue