@@ -4,8 +4,8 @@ import * as v from "vscode-languageserver";
4
4
import * as rpc from "vscode-jsonrpc/node" ;
5
5
import * as path from "path" ;
6
6
import fs from "fs" ;
7
- // TODO: check DidChangeWatchedFilesNotification.
8
7
import {
8
+ DidChangeWatchedFilesNotification ,
9
9
DidOpenTextDocumentNotification ,
10
10
DidChangeTextDocumentNotification ,
11
11
DidCloseTextDocumentNotification ,
@@ -14,6 +14,7 @@ import {
14
14
InlayHintParams ,
15
15
CodeLensParams ,
16
16
SignatureHelpParams ,
17
+ InitializedNotification ,
17
18
} from "vscode-languageserver-protocol" ;
18
19
import * as lookup from "./lookup" ;
19
20
import * as utils from "./utils" ;
@@ -27,6 +28,10 @@ import * as ic from "./incrementalCompilation";
27
28
import config , { extensionConfiguration } from "./config" ;
28
29
import { projectsFiles } from "./projectFiles" ;
29
30
31
+ // Absolute paths to all the workspace folders
32
+ // Configured during the initialize request
33
+ const workspaceFolders = new Set < string > ( ) ;
34
+
30
35
// This holds client capabilities specific to our extension, and not necessarily
31
36
// related to the LS protocol. It's for enabling/disabling features that might
32
37
// work in one client, like VSCode, but perhaps not in others, like vim.
@@ -209,21 +214,18 @@ let deleteProjectConfigCache = async (rootPath: string) => {
209
214
}
210
215
} ;
211
216
212
- let compilerLogsWatcher = chokidar
213
- . watch ( [ ] , {
214
- awaitWriteFinish : {
215
- stabilityThreshold : 1 ,
216
- } ,
217
- } )
218
- . on ( "all" , async ( _e , changedPath ) => {
219
- if ( changedPath . includes ( "build.ninja" ) ) {
217
+ async function onWorkspaceDidChangeWatchedFiles (
218
+ params : p . DidChangeWatchedFilesParams
219
+ ) {
220
+ await Promise . all ( params . changes . map ( async ( change ) => {
221
+ if ( change . uri . includes ( "build.ninja" ) ) {
220
222
if ( config . extensionConfiguration . cache ?. projectConfig ?. enable === true ) {
221
- let projectRoot = utils . findProjectRootOfFile ( changedPath ) ;
223
+ let projectRoot = utils . findProjectRootOfFile ( change . uri ) ;
222
224
if ( projectRoot != null ) {
223
225
await syncProjectConfigCache ( projectRoot ) ;
224
226
}
225
227
}
226
- } else {
228
+ } else if ( change . uri . includes ( "compiler.log" ) ) {
227
229
try {
228
230
await sendUpdatedDiagnostics ( ) ;
229
231
sendCompilationFinishedMessage ( ) ;
@@ -236,13 +238,11 @@ let compilerLogsWatcher = chokidar
236
238
} catch {
237
239
console . log ( "Error while sending updated diagnostics" ) ;
238
240
}
241
+ } else {
242
+ ic . incrementalCompilationFileChanged ( fileURLToPath ( change . uri ) ) ;
239
243
}
240
- } ) ;
241
-
242
- let stopWatchingCompilerLog = ( ) => {
243
- // TODO: cleanup of compilerLogs?
244
- compilerLogsWatcher . close ( ) ;
245
- } ;
244
+ } ) ) ;
245
+ }
246
246
247
247
type clientSentBuildAction = {
248
248
title : string ;
@@ -280,13 +280,7 @@ let openedFile = async (fileUri: string, fileContent: string) => {
280
280
: false ,
281
281
} ;
282
282
projectsFiles . set ( projectRootPath , projectRootState ) ;
283
- compilerLogsWatcher . add (
284
- path . join ( projectRootPath , c . compilerLogPartialPath )
285
- ) ;
286
283
if ( config . extensionConfiguration . cache ?. projectConfig ?. enable === true ) {
287
- compilerLogsWatcher . add (
288
- path . join ( projectRootPath , c . buildNinjaPartialPath )
289
- ) ;
290
284
await syncProjectConfigCache ( projectRootPath ) ;
291
285
}
292
286
}
@@ -364,12 +358,6 @@ let closedFile = async (fileUri: string) => {
364
358
root . openFiles . delete ( filePath ) ;
365
359
// clear diagnostics too if no open files open in said project
366
360
if ( root . openFiles . size === 0 ) {
367
- compilerLogsWatcher . unwatch (
368
- path . join ( projectRootPath , c . compilerLogPartialPath )
369
- ) ;
370
- compilerLogsWatcher . unwatch (
371
- path . join ( projectRootPath , c . buildNinjaPartialPath )
372
- ) ;
373
361
await deleteProjectConfigCache ( projectRootPath ) ;
374
362
deleteProjectDiagnostics ( projectRootPath ) ;
375
363
if ( root . bsbWatcherByEditor !== null ) {
@@ -1051,7 +1039,7 @@ async function onMessage(msg: p.Message) {
1051
1039
} else {
1052
1040
process . exit ( 1 ) ;
1053
1041
}
1054
- } else if ( msg . method === "initialized" ) {
1042
+ } else if ( msg . method === InitializedNotification . method ) {
1055
1043
/*
1056
1044
The initialized notification is sent from the client to the server after the client received the result of the initialize request
1057
1045
but before the client is sending any other request or notification to the server.
@@ -1060,27 +1048,32 @@ async function onMessage(msg: p.Message) {
1060
1048
We use this to register the file watchers for the project.
1061
1049
The client can watch files for us and send us events via the `workspace/didChangeWatchedFiles`
1062
1050
*/
1063
- const watchers =
1064
- Array . from ( projectsFiles . keys ( ) ) . flatMap ( projectRootPath => [
1051
+ const watchers = Array . from ( workspaceFolders ) . flatMap (
1052
+ ( projectRootPath ) => [
1065
1053
{
1066
1054
globPattern : path . join ( projectRootPath , c . compilerLogPartialPath ) ,
1067
- kind : p . WatchKind . Change | p . WatchKind . Create ,
1055
+ kind : p . WatchKind . Change | p . WatchKind . Create | p . WatchKind . Delete ,
1068
1056
} ,
1069
1057
{
1070
1058
globPattern : path . join ( projectRootPath , c . buildNinjaPartialPath ) ,
1071
- kind : p . WatchKind . Change | p . WatchKind . Create ,
1059
+ kind : p . WatchKind . Change | p . WatchKind . Create | p . WatchKind . Delete ,
1072
1060
} ,
1073
- ] )
1074
- const registrationParams : p . RegistrationParams = {
1075
- registrations :[
1076
1061
{
1077
- id : "rescript_file_watcher" ,
1078
- method : p . DidChangeWatchedFilesNotification . method ,
1079
- registerOptions : {
1080
- watchers
1081
- }
1062
+ globPattern : `${ path . join ( projectRootPath , c . compilerDirPartialPath ) } /**/*.{cmt,cmi}` ,
1063
+ kind : p . WatchKind . Change | p . WatchKind . Delete ,
1082
1064
}
1083
1065
]
1066
+ ) ;
1067
+ const registrationParams : p . RegistrationParams = {
1068
+ registrations : [
1069
+ {
1070
+ id : "rescript_file_watcher" ,
1071
+ method : DidChangeWatchedFilesNotification . method ,
1072
+ registerOptions : {
1073
+ watchers,
1074
+ } ,
1075
+ } ,
1076
+ ] ,
1084
1077
} ;
1085
1078
const req : p . RequestMessage = {
1086
1079
jsonrpc : c . jsonrpcVersion ,
@@ -1089,6 +1082,9 @@ async function onMessage(msg: p.Message) {
1089
1082
params : registrationParams ,
1090
1083
} ;
1091
1084
send ( req ) ;
1085
+ } else if ( msg . method === DidChangeWatchedFilesNotification . method ) {
1086
+ const params = msg . params as p . DidChangeWatchedFilesParams ;
1087
+ await onWorkspaceDidChangeWatchedFiles ( params ) ;
1092
1088
} else if ( msg . method === DidOpenTextDocumentNotification . method ) {
1093
1089
let params = msg . params as p . DidOpenTextDocumentParams ;
1094
1090
await openedFile ( params . textDocument . uri , params . textDocument . text ) ;
@@ -1134,6 +1130,10 @@ async function onMessage(msg: p.Message) {
1134
1130
} else if ( msg . method === "initialize" ) {
1135
1131
// Save initial configuration, if present
1136
1132
let initParams = msg . params as InitializeParams ;
1133
+ for ( const workspaceFolder of initParams . workspaceFolders || [ ] ) {
1134
+ const workspaceRootPath = fileURLToPath ( workspaceFolder . uri ) ;
1135
+ workspaceFolders . add ( workspaceRootPath ) ;
1136
+ }
1137
1137
let initialConfiguration = initParams . initializationOptions
1138
1138
?. extensionConfiguration as extensionConfiguration | undefined ;
1139
1139
@@ -1245,8 +1245,6 @@ async function onMessage(msg: p.Message) {
1245
1245
} else {
1246
1246
shutdownRequestAlreadyReceived = true ;
1247
1247
// TODO: recheck logic around init/shutdown...
1248
- stopWatchingCompilerLog ( ) ;
1249
- // TODO: delete bsb watchers
1250
1248
1251
1249
if ( pullConfigurationPeriodically != null ) {
1252
1250
clearInterval ( pullConfigurationPeriodically ) ;
0 commit comments