Skip to content

Commit a4e2efd

Browse files
committed
Better diagnostics handling
1 parent 21140d9 commit a4e2efd

File tree

3 files changed

+33
-26
lines changed

3 files changed

+33
-26
lines changed

CONTRIBUTING.md

+5-7
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ They should be synced in from the `bsb` build. Don't take them from other places
1111
The build output is streamed into `lib/bs/.compiler.log`. Here are its various states, numbered here:
1212

1313
1. Doesn't exist: artifacts not built yet, or cleaned away.
14-
2. Present but empty: currently building, no error yet.
15-
3. Present, non-empty, without a final line `# Done`: still building.
16-
4. Present, with the final line `# Done`: finished building.
14+
2. Present, without a final line `#Done`: still building.
15+
3. Present, with the final line `#Done`: finished building.
1716

18-
Barring FS errors, there should be no other state to `.compiler.log`.
17+
Barring FS errors, there should be no other state to `.compiler.log`. Among others, this means the file is never present but empty.
1918

2019
### State 1
2120

@@ -25,9 +24,8 @@ Artifacts cleaning through `bsb -clean` removes `.compiler.log` and turns into s
2524

2625
After saving a file and running the build, the results stream into the log file. Unfortunately, UX-wise, in the editor, this might look like the diagnostics are suddenly gone then coming back in file by file. This looks bad. To remediate:
2726

28-
- If the log file is in state 2 (see state numbers above), don't wipe the existing diagnostics yet.
29-
- If it's in state 3, update those particular files' diagnostics.
30-
- If in state 4, finish by clean up the rest of the old diagnostics. This means there's a bit of bookeeping needed here. Make sure you get it right. It's possible for a build to be interrupted (and therefore state 4 never reached) and restarted.
27+
- If it's in state 2, update those particular files' diagnostics but don't wipe the files' diagnostics yet.
28+
- If in state 3, finish by clean up the rest of the old diagnostics. This means there's a bit of bookeeping needed here. Make sure you get it right. It's possible for a build to be interrupted (and therefore state 4 never reached) and restarted.
3129

3230
Even this fix isn't great. Ideally, the editor's diagnostics can be greyed out while we're updating them...
3331

server/src/server.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,14 @@ let previouslyDiagnosedFiles: Set<string> = new Set()
2323
let compilerLogPaths: Set<string> = new Set()
2424

2525
let sendUpdatedDiagnostics = () => {
26-
let diagnosedFiles: { [key: string]: t.Diagnostic[] } = {}
26+
let diagnosedFiles: utils.filesDiagnostics = {}
2727
compilerLogPaths.forEach(compilerLogPath => {
2828
let content = fs.readFileSync(compilerLogPath, { encoding: 'utf-8' });
2929
console.log("new log content: ", content)
30-
let filesAndErrors = utils.parseCompilerLogOutput(content, ":")
31-
Object.keys(filesAndErrors).forEach(file => {
32-
// assumption: there's no existing files[file] entry
33-
// this is true; see the lines above. A file can only belong to one .compiler.log root
34-
diagnosedFiles[file] = filesAndErrors[file]
35-
})
30+
let { done: buildDone, result: filesAndErrors } = utils.parseCompilerLogOutput(content)
31+
// A file can only belong to one .compiler.log root. So we're not overriding
32+
// any existing key here
33+
Object.assign(diagnosedFiles, filesAndErrors)
3634
});
3735

3836
// Send new diagnostic, wipe old ones

server/src/utils.ts

+23-12
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,18 @@ export let parseDiagnosticLocation = (location: string): Range => {
8888
}
8989
}
9090

91-
export let parseCompilerLogOutput = (content: string, separator: string) => {
91+
export type filesDiagnostics = {
92+
[key: string]: p.Diagnostic[];
93+
}
94+
type parsedCompilerLogResult = {
95+
done: boolean,
96+
result: filesDiagnostics,
97+
}
98+
export let parseCompilerLogOutput = (content: string): parsedCompilerLogResult => {
9299
/* example .compiler.log file content that we're gonna parse:
93100
101+
#Start(1600519680823)
102+
94103
Syntax error!
95104
/Users/chenglou/github/reason-react/src/test.res:1:8-2:3
96105
@@ -121,11 +130,10 @@ export let parseCompilerLogOutput = (content: string, separator: string) => {
121130
2 │ let b = "hi"
122131
3 │ let a = b + 1
123132
124-
This has type:
125-
string
133+
This has type: string
134+
Somewhere wanted: int
126135
127-
But somewhere wanted:
128-
int
136+
#Done(1600519680836)
129137
*/
130138

131139
type parsedDiagnostic = {
@@ -136,6 +144,8 @@ export let parseCompilerLogOutput = (content: string, separator: string) => {
136144
}
137145
let parsedDiagnostics: parsedDiagnostic[] = [];
138146
let lines = content.split('\n');
147+
let done = false;
148+
139149
for (let i = 0; i < lines.length; i++) {
140150
let line = lines[i];
141151
if (line.startsWith(' We\'ve found a bug for you!')) {
@@ -184,22 +194,23 @@ export let parseCompilerLogOutput = (content: string, separator: string) => {
184194
tag: undefined,
185195
content: []
186196
})
197+
} else if (line.startsWith('#Done(')) {
198+
done = true
187199
} else if (/^ +[0-9]+ /.test(line)) {
188200
// code display. Swallow
189201
} else if (line.startsWith(' ')) {
190202
parsedDiagnostics[parsedDiagnostics.length - 1].content.push(line)
191203
}
192204
}
193205

194-
// map of file path to list of diagnostic
195-
let ret: { [key: string]: t.Diagnostic[] } = {}
206+
let result: filesDiagnostics = {}
196207
parsedDiagnostics.forEach(parsedDiagnostic => {
197208
let [fileAndLocation, ...diagnosticMessage] = parsedDiagnostic.content
198-
let locationSeparator = fileAndLocation.indexOf(separator)
209+
let locationSeparator = fileAndLocation.indexOf(':')
199210
let file = fileAndLocation.substring(2, locationSeparator)
200211
let location = fileAndLocation.substring(locationSeparator + 1)
201-
if (ret[file] == null) {
202-
ret[file] = []
212+
if (result[file] == null) {
213+
result[file] = []
203214
}
204215
let cleanedUpDiagnostic = diagnosticMessage
205216
.map(line => {
@@ -209,7 +220,7 @@ export let parseCompilerLogOutput = (content: string, separator: string) => {
209220
.join('\n')
210221
// remove start and end whitespaces/newlines
211222
.trim() + '\n';
212-
ret[file].push({
223+
result[file].push({
213224
severity: parsedDiagnostic.severity,
214225
tags: parsedDiagnostic.tag === undefined ? [] : [parsedDiagnostic.tag],
215226
code: parsedDiagnostic.code,
@@ -219,5 +230,5 @@ export let parseCompilerLogOutput = (content: string, separator: string) => {
219230
})
220231
})
221232

222-
return ret
233+
return { done, result }
223234
}

0 commit comments

Comments
 (0)