Skip to content

Commit fc2e73f

Browse files
committed
Clean up file and location parsing logic
1 parent a8f2692 commit fc2e73f

File tree

1 file changed

+56
-47
lines changed

1 file changed

+56
-47
lines changed

server/src/utils.ts

+56-47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Range } from "vscode-languageserver-textdocument";
21
import * as c from "./constants";
32
import * as childProcess from "child_process";
43
import * as p from "vscode-languageserver-protocol";
@@ -128,37 +127,6 @@ export let runBsbWatcherUsingValidBsbPath = (
128127
// }
129128
};
130129

131-
export let parseDiagnosticLocation = (location: string): Range => {
132-
// example output location:
133-
// 3:9
134-
// 3:5-8
135-
// 3:9-6:1
136-
137-
// language-server position is 0-based. Ours is 1-based. Don't forget to convert
138-
// also, our end character is inclusive. Language-server's is exclusive
139-
let isRange = location.indexOf("-") >= 0;
140-
if (isRange) {
141-
let [from, to] = location.split("-");
142-
let [fromLine, fromChar] = from.split(":");
143-
let isSingleLine = to.indexOf(":") >= 0;
144-
let [toLine, toChar] = isSingleLine ? to.split(":") : [fromLine, to];
145-
return {
146-
start: {
147-
line: parseInt(fromLine) - 1,
148-
character: parseInt(fromChar) - 1,
149-
},
150-
end: { line: parseInt(toLine) - 1, character: parseInt(toChar) },
151-
};
152-
} else {
153-
let [line, char] = location.split(":");
154-
let start = { line: parseInt(line) - 1, character: parseInt(char) };
155-
return {
156-
start: start,
157-
end: start,
158-
};
159-
}
160-
};
161-
162130
// Logic for parsing .compiler.log
163131
/* example .compiler.log content:
164132
@@ -201,19 +169,60 @@ export let parseDiagnosticLocation = (location: string): Range => {
201169
*/
202170

203171
// parser helper
204-
let splitFileAndLocation = (fileAndLocation: string) => {
205-
let isWindows = process.platform === "win32";
206-
// Exclude the two first letters in windows paths to avoid the first colon in eg "c:\\.."
207-
let locationSeparator = isWindows
208-
? fileAndLocation.indexOf(":", 2)
209-
: fileAndLocation.indexOf(":");
210-
211-
let file = fileAndLocation.slice(0, locationSeparator);
212-
let location = fileAndLocation.slice(locationSeparator + 1);
213-
172+
let parseFileAndRange = (fileAndRange: string) => {
173+
// https://github.com/rescript-lang/rescript-compiler/blob/0a3f4bb32ca81e89cefd5a912b8795878836f883/jscomp/super_errors/super_location.ml#L19-L25
174+
/* The file + location format can be:
175+
a/b.res:10:20
176+
a/b.res:10:20-21 <- last number here is the end char of line 10
177+
a/b.res:10:20-30:11
178+
*/
179+
let regex = /(.+)\:(\d+)\:(\d+)(-(\d+)(\:(\d+))?)?$/;
180+
/* ^^ file
181+
^^^ start line
182+
^^^ start character
183+
^ optional range
184+
^^^ end line or chararacter
185+
^^^ end character
186+
*/
187+
// it's not possible that this regex fails. If it does, something's wrong in the caller
188+
let [
189+
_source,
190+
file,
191+
startLine,
192+
startChar,
193+
optionalEndGroup,
194+
endLineOrChar,
195+
_colonPlusEndCharOrNothing,
196+
endCharOrNothing,
197+
] = fileAndRange.match(regex)!;
198+
// language-server position is 0-based. Ours is 1-based. Convert
199+
// also, our end character is inclusive. Language-server's is exclusive
200+
let range;
201+
if (optionalEndGroup == null) {
202+
let start = {
203+
line: parseInt(startLine) - 1,
204+
character: parseInt(startChar),
205+
};
206+
range = {
207+
start: start,
208+
end: start,
209+
};
210+
} else {
211+
let isSingleLine = endCharOrNothing == null;
212+
let [endLine, endChar] = isSingleLine
213+
? [startLine, endLineOrChar]
214+
: [endLineOrChar, endCharOrNothing];
215+
range = {
216+
start: {
217+
line: parseInt(startLine) - 1,
218+
character: parseInt(startChar) - 1,
219+
},
220+
end: { line: parseInt(endLine) - 1, character: parseInt(endChar) },
221+
};
222+
}
214223
return {
215-
file: isWindows ? `file:\\\\\\${file}` : file,
216-
location,
224+
file: process.platform === "win32" ? `file:\\\\\\${file}` : file,
225+
range,
217226
};
218227
};
219228

@@ -297,8 +306,8 @@ export let parseCompilerLogOutput = (
297306

298307
let result: filesDiagnostics = {};
299308
parsedDiagnostics.forEach((parsedDiagnostic) => {
300-
let [fileAndLocationLine, ...diagnosticMessage] = parsedDiagnostic.content;
301-
let { file, location } = splitFileAndLocation(fileAndLocationLine.slice(2));
309+
let [fileAndRangeLine, ...diagnosticMessage] = parsedDiagnostic.content;
310+
let { file, range } = parseFileAndRange(fileAndRangeLine.slice(2));
302311

303312
if (result[file] == null) {
304313
result[file] = [];
@@ -316,7 +325,7 @@ export let parseCompilerLogOutput = (
316325
severity: parsedDiagnostic.severity,
317326
tags: parsedDiagnostic.tag === undefined ? [] : [parsedDiagnostic.tag],
318327
code: parsedDiagnostic.code,
319-
range: parseDiagnosticLocation(location),
328+
range,
320329
source: "ReScript",
321330
message: cleanedUpDiagnostic,
322331
});

0 commit comments

Comments
 (0)