@vmz/diagnostic 0.3.13 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pretty.js +13 -14
- package/dist/utf8.d.ts +13 -2
- package/dist/utf8.js +69 -11
- package/package.json +1 -1
package/dist/pretty.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { displayWidth, expandTabs, utf8ByteSlice, utf8LineAt } from './utf8.js';
|
|
2
2
|
const ANSI = {
|
|
3
3
|
reset: '\x1b[0m',
|
|
4
4
|
bold: '\x1b[1m',
|
|
@@ -26,21 +26,20 @@ function severityStyle(severity) {
|
|
|
26
26
|
function severityLabel(severity) {
|
|
27
27
|
return severity === 'warning' ? 'warning' : severity;
|
|
28
28
|
}
|
|
29
|
-
function formatLocation(path, line, column) {
|
|
29
|
+
function formatLocation(path, line, column, gutterWidth = 1) {
|
|
30
30
|
const where = path ? `${path}:${line}:${column}` : `${line}:${column}`;
|
|
31
|
-
return paint(
|
|
31
|
+
return paint(`${' '.repeat(gutterWidth + 1)}--> ${where}`, ANSI.bold, ANSI.blue);
|
|
32
32
|
}
|
|
33
33
|
function canRenderSnippet(d, opts) {
|
|
34
|
-
return (opts.style ?? 'pretty') === 'pretty' &&
|
|
34
|
+
return ((opts.style ?? 'pretty') === 'pretty' &&
|
|
35
|
+
Boolean(opts.sourceText && opts.position && d.span && d.span.end >= d.span.start));
|
|
35
36
|
}
|
|
36
|
-
function renderSnippetLine(out, gutterWidth, lineNum, lineText,
|
|
37
|
+
function renderSnippetLine(out, gutterWidth, lineNum, lineText, startCell, endCell, severity) {
|
|
37
38
|
const gutter = paint(`${String(lineNum).padStart(gutterWidth)} | `, ANSI.dim);
|
|
38
|
-
out.push(`${gutter}${lineText}`);
|
|
39
|
-
const startIdx = scalarColumnToIndex(lineText, colStart);
|
|
40
|
-
const endIdx = Math.max(startIdx + 1, scalarColumnToIndex(lineText, colEnd + 1));
|
|
39
|
+
out.push(`${gutter}${expandTabs(lineText)}`);
|
|
41
40
|
const marker = paint(`${' '.repeat(gutterWidth)} | `, ANSI.dim) +
|
|
42
|
-
' '.repeat(
|
|
43
|
-
paint('^'.repeat(
|
|
41
|
+
' '.repeat(startCell) +
|
|
42
|
+
paint('^'.repeat(Math.max(1, endCell - startCell)), ...severityStyle(severity));
|
|
44
43
|
out.push(marker);
|
|
45
44
|
}
|
|
46
45
|
export function formatDiagnosticPretty(d, message, opts) {
|
|
@@ -62,19 +61,19 @@ export function formatDiagnosticPretty(d, message, opts) {
|
|
|
62
61
|
const span = d.span;
|
|
63
62
|
const path = d.path || '';
|
|
64
63
|
const startPos = position.lineCol(span.start);
|
|
65
|
-
const endPos = position.lineCol(Math.max(span.start, span.end - 1));
|
|
66
|
-
lines.push(formatLocation(path, startPos.line, startPos.column));
|
|
67
64
|
const startLine = utf8LineAt(source, span.start);
|
|
68
65
|
const endLine = utf8LineAt(source, Math.max(span.start, span.end - 1));
|
|
69
66
|
const gutterWidth = String(endLine.line).length;
|
|
67
|
+
lines.push(formatLocation(path, startPos.line, startPos.column, gutterWidth));
|
|
70
68
|
if (startLine.line === endLine.line) {
|
|
71
|
-
renderSnippetLine(lines, gutterWidth, startLine.line, startLine.text,
|
|
69
|
+
renderSnippetLine(lines, gutterWidth, startLine.line, startLine.text, displayWidth(utf8ByteSlice(source, startLine.lineStart, span.start)), displayWidth(utf8ByteSlice(source, startLine.lineStart, Math.min(span.end, startLine.lineEnd))), d.severity);
|
|
72
70
|
}
|
|
73
71
|
else {
|
|
74
|
-
renderSnippetLine(lines, gutterWidth, startLine.line, startLine.text,
|
|
72
|
+
renderSnippetLine(lines, gutterWidth, startLine.line, startLine.text, displayWidth(utf8ByteSlice(source, startLine.lineStart, span.start)), displayWidth(startLine.text), d.severity);
|
|
75
73
|
if (endLine.line > startLine.line + 1) {
|
|
76
74
|
lines.push(paint(`${' '.repeat(gutterWidth + 3)}...`, ANSI.dim));
|
|
77
75
|
}
|
|
76
|
+
renderSnippetLine(lines, gutterWidth, endLine.line, endLine.text, 0, displayWidth(utf8ByteSlice(source, endLine.lineStart, Math.min(span.end, endLine.lineEnd))), d.severity);
|
|
78
77
|
}
|
|
79
78
|
return lines.join('\n');
|
|
80
79
|
}
|
package/dist/utf8.d.ts
CHANGED
|
@@ -11,5 +11,16 @@ export type Utf8LineSlice = {
|
|
|
11
11
|
export declare function utf8LineAt(source: string, offset: number): Utf8LineSlice;
|
|
12
12
|
/** 1-based Unicode scalar column within a line slice (matches compiler OffsetIndex). */
|
|
13
13
|
export declare function unicodeScalarColumn(lineText: string, byteOffsetInLine: number): number;
|
|
14
|
-
/**
|
|
15
|
-
export declare function
|
|
14
|
+
/** Terminal cells occupied by one Unicode scalar (wide CJK/emoji render as two, CR as zero). */
|
|
15
|
+
export declare function scalarDisplayWidth(ch: string): number;
|
|
16
|
+
/** Tab stops used when rendering source snippets, matching rustc and miette defaults. */
|
|
17
|
+
export declare const SNIPPET_TAB_WIDTH = 4;
|
|
18
|
+
/** Display width of a line fragment in terminal cells (tabs advance to the next stop). */
|
|
19
|
+
export declare function displayWidth(text: string): number;
|
|
20
|
+
/**
|
|
21
|
+
* Expand tabs to spaces so the printed source line and the caret row agree in
|
|
22
|
+
* any terminal, regardless of that terminal's own tab-stop configuration.
|
|
23
|
+
* Carriage returns from CRLF sources are dropped because they terminate the
|
|
24
|
+
* line rather than occupy a cell.
|
|
25
|
+
*/
|
|
26
|
+
export declare function expandTabs(text: string): string;
|
package/dist/utf8.js
CHANGED
|
@@ -40,17 +40,75 @@ export function unicodeScalarColumn(lineText, byteOffsetInLine) {
|
|
|
40
40
|
return 1;
|
|
41
41
|
return buf.subarray(0, end).toString('utf8').length > 0 ? [...buf.subarray(0, end).toString('utf8')].length : 1;
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const ZERO_WIDTH_PATTERN = /\p{Mn}|\p{Me}|\p{Cf}/u;
|
|
44
|
+
function isWideCodePoint(cp) {
|
|
45
|
+
return ((cp >= 0x1100 && cp <= 0x115f) ||
|
|
46
|
+
cp === 0x2329 ||
|
|
47
|
+
cp === 0x232a ||
|
|
48
|
+
(cp >= 0x2e80 && cp <= 0x303e) ||
|
|
49
|
+
(cp >= 0x3041 && cp <= 0x33ff) ||
|
|
50
|
+
(cp >= 0x3400 && cp <= 0x4dbf) ||
|
|
51
|
+
(cp >= 0x4e00 && cp <= 0x9fff) ||
|
|
52
|
+
(cp >= 0xa000 && cp <= 0xa4cf) ||
|
|
53
|
+
(cp >= 0xa960 && cp <= 0xa97f) ||
|
|
54
|
+
(cp >= 0xac00 && cp <= 0xd7a3) ||
|
|
55
|
+
(cp >= 0xf900 && cp <= 0xfaff) ||
|
|
56
|
+
(cp >= 0xfe10 && cp <= 0xfe19) ||
|
|
57
|
+
(cp >= 0xfe30 && cp <= 0xfe6f) ||
|
|
58
|
+
(cp >= 0xff00 && cp <= 0xff60) ||
|
|
59
|
+
(cp >= 0xffe0 && cp <= 0xffe6) ||
|
|
60
|
+
(cp >= 0x1b000 && cp <= 0x1b2ff) ||
|
|
61
|
+
(cp >= 0x1f000 && cp <= 0x1f02f) ||
|
|
62
|
+
(cp >= 0x1f0a0 && cp <= 0x1f0ff) ||
|
|
63
|
+
(cp >= 0x1f100 && cp <= 0x1f1ad) ||
|
|
64
|
+
(cp >= 0x1f300 && cp <= 0x1f64f) ||
|
|
65
|
+
(cp >= 0x1f680 && cp <= 0x1f6ff) ||
|
|
66
|
+
(cp >= 0x1f900 && cp <= 0x1f9ff) ||
|
|
67
|
+
(cp >= 0x1fa70 && cp <= 0x1faff) ||
|
|
68
|
+
(cp >= 0x20000 && cp <= 0x3fffd));
|
|
69
|
+
}
|
|
70
|
+
/** Terminal cells occupied by one Unicode scalar (wide CJK/emoji render as two, CR as zero). */
|
|
71
|
+
export function scalarDisplayWidth(ch) {
|
|
72
|
+
const cp = ch.codePointAt(0) ?? 0;
|
|
73
|
+
if (cp === 0 || cp === 0x0d || ZERO_WIDTH_PATTERN.test(ch))
|
|
46
74
|
return 0;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
return isWideCodePoint(cp) ? 2 : 1;
|
|
76
|
+
}
|
|
77
|
+
/** Tab stops used when rendering source snippets, matching rustc and miette defaults. */
|
|
78
|
+
export const SNIPPET_TAB_WIDTH = 4;
|
|
79
|
+
/** Display width of a line fragment in terminal cells (tabs advance to the next stop). */
|
|
80
|
+
export function displayWidth(text) {
|
|
81
|
+
let cells = 0;
|
|
82
|
+
for (const ch of text) {
|
|
83
|
+
if (ch === '\t') {
|
|
84
|
+
cells += SNIPPET_TAB_WIDTH - (cells % SNIPPET_TAB_WIDTH);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
cells += scalarDisplayWidth(ch);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return cells;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Expand tabs to spaces so the printed source line and the caret row agree in
|
|
94
|
+
* any terminal, regardless of that terminal's own tab-stop configuration.
|
|
95
|
+
* Carriage returns from CRLF sources are dropped because they terminate the
|
|
96
|
+
* line rather than occupy a cell.
|
|
97
|
+
*/
|
|
98
|
+
export function expandTabs(text) {
|
|
99
|
+
let cells = 0;
|
|
100
|
+
let out = '';
|
|
101
|
+
for (const ch of text) {
|
|
102
|
+
if (ch === '\r')
|
|
103
|
+
continue;
|
|
104
|
+
if (ch === '\t') {
|
|
105
|
+
const pad = SNIPPET_TAB_WIDTH - (cells % SNIPPET_TAB_WIDTH);
|
|
106
|
+
out += ' '.repeat(pad);
|
|
107
|
+
cells += pad;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
out += ch;
|
|
111
|
+
cells += scalarDisplayWidth(ch);
|
|
54
112
|
}
|
|
55
|
-
return
|
|
113
|
+
return out;
|
|
56
114
|
}
|
package/package.json
CHANGED