@@ -2,6 +2,7 @@ import process from "process";
2
2
import * as p from "vscode-languageserver-protocol" ;
3
3
import * as m from "vscode-jsonrpc/lib/messages" ;
4
4
import * as v from "vscode-languageserver" ;
5
+ import * as rpc from "vscode-jsonrpc" ;
5
6
import * as path from "path" ;
6
7
import fs from "fs" ;
7
8
// TODO: check DidChangeWatchedFilesNotification.
@@ -39,6 +40,9 @@ let projectsFiles: Map<
39
40
> = new Map ( ) ;
40
41
// ^ caching AND states AND distributed system. Why does LSP has to be stupid like this
41
42
43
+ // will be properly defined later depending on the mode (stdio/node-rpc)
44
+ let send : ( msg : m . Message ) => void = ( _ ) => { } ;
45
+
42
46
let sendUpdatedDiagnostics = ( ) => {
43
47
projectsFiles . forEach ( ( { filesWithDiagnostics } , projectRootPath ) => {
44
48
let content = fs . readFileSync (
@@ -60,7 +64,7 @@ let sendUpdatedDiagnostics = () => {
60
64
method : "textDocument/publishDiagnostics" ,
61
65
params : params ,
62
66
} ;
63
- process . send ! ( notification ) ;
67
+ send ( notification ) ;
64
68
65
69
filesWithDiagnostics . add ( file ) ;
66
70
} ) ;
@@ -78,7 +82,7 @@ let sendUpdatedDiagnostics = () => {
78
82
method : "textDocument/publishDiagnostics" ,
79
83
params : params ,
80
84
} ;
81
- process . send ! ( notification ) ;
85
+ send ( notification ) ;
82
86
filesWithDiagnostics . delete ( file ) ;
83
87
}
84
88
} ) ;
@@ -98,7 +102,7 @@ let deleteProjectDiagnostics = (projectRootPath: string) => {
98
102
method : "textDocument/publishDiagnostics" ,
99
103
params : params ,
100
104
} ;
101
- process . send ! ( notification ) ;
105
+ send ( notification ) ;
102
106
} ) ;
103
107
104
108
projectsFiles . delete ( projectRootPath ) ;
@@ -167,7 +171,7 @@ let openedFile = (fileUri: string, fileContent: string) => {
167
171
method : "window/showMessageRequest" ,
168
172
params : params ,
169
173
} ;
170
- process . send ! ( request ) ;
174
+ send ( request ) ;
171
175
// the client might send us back the "start build" action, which we'll
172
176
// handle in the isResponseMessage check in the message handling way
173
177
// below
@@ -216,7 +220,22 @@ let getOpenedFileContent = (fileUri: string) => {
216
220
return content ;
217
221
} ;
218
222
219
- process . on ( "message" , ( msg : m . Message ) => {
223
+ // Start listening now!
224
+ // We support two modes: the regular node RPC mode for VSCode, and the --stdio
225
+ // mode for other editors The latter is _technically unsupported_. It's an
226
+ // implementation detail that might change at any time
227
+ if ( process . argv . includes ( "--stdio" ) ) {
228
+ let writer = new rpc . StreamMessageWriter ( process . stdout ) ;
229
+ let reader = new rpc . StreamMessageReader ( process . stdin ) ;
230
+ // proper `this` scope for writer
231
+ send = ( msg : m . Message ) => writer . write ( msg ) ;
232
+ reader . listen ( onMessage ) ;
233
+ } else {
234
+ // proper `this` scope for process
235
+ send = ( msg : m . Message ) => process . send ! ( msg ) ;
236
+ process . on ( "message" , onMessage ) ;
237
+ }
238
+ function onMessage ( msg : m . Message ) {
220
239
if ( m . isNotificationMessage ( msg ) ) {
221
240
// notification message, aka the client ends it and doesn't want a reply
222
241
if ( ! initialized && msg . method !== "exit" ) {
@@ -266,7 +285,7 @@ process.on("message", (msg: m.Message) => {
266
285
message : "Server not initialized." ,
267
286
} ,
268
287
} ;
269
- process . send ! ( response ) ;
288
+ send ( response ) ;
270
289
} else if ( msg . method === "initialize" ) {
271
290
// send the list of features we support
272
291
let result : p . InitializeResult = {
@@ -290,15 +309,15 @@ process.on("message", (msg: m.Message) => {
290
309
result : result ,
291
310
} ;
292
311
initialized = true ;
293
- process . send ! ( response ) ;
312
+ send ( response ) ;
294
313
} else if ( msg . method === "initialized" ) {
295
314
// sent from client after initialize. Nothing to do for now
296
315
let response : m . ResponseMessage = {
297
316
jsonrpc : c . jsonrpcVersion ,
298
317
id : msg . id ,
299
318
result : null ,
300
319
} ;
301
- process . send ! ( response ) ;
320
+ send ( response ) ;
302
321
} else if ( msg . method === "shutdown" ) {
303
322
// https://microsoft.github.io/language-server-protocol/specification#shutdown
304
323
if ( shutdownRequestAlreadyReceived ) {
@@ -310,7 +329,7 @@ process.on("message", (msg: m.Message) => {
310
329
message : `Language server already received the shutdown request` ,
311
330
} ,
312
331
} ;
313
- process . send ! ( response ) ;
332
+ send ( response ) ;
314
333
} else {
315
334
shutdownRequestAlreadyReceived = true ;
316
335
// TODO: recheck logic around init/shutdown...
@@ -322,7 +341,7 @@ process.on("message", (msg: m.Message) => {
322
341
id : msg . id ,
323
342
result : null ,
324
343
} ;
325
- process . send ! ( response ) ;
344
+ send ( response ) ;
326
345
}
327
346
} else if ( msg . method === p . HoverRequest . method ) {
328
347
let emptyHoverResponse : m . ResponseMessage = {
@@ -338,9 +357,9 @@ process.on("message", (msg: m.Message) => {
338
357
...emptyHoverResponse ,
339
358
result : { contents : result . hover } ,
340
359
} ;
341
- process . send ! ( hoverResponse ) ;
360
+ send ( hoverResponse ) ;
342
361
} else {
343
- process . send ! ( emptyHoverResponse ) ;
362
+ send ( emptyHoverResponse ) ;
344
363
}
345
364
} else if ( msg . method === p . DefinitionRequest . method ) {
346
365
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
@@ -361,9 +380,9 @@ process.on("message", (msg: m.Message) => {
361
380
range : result . definition . range ,
362
381
} ,
363
382
} ;
364
- process . send ! ( definitionResponse ) ;
383
+ send ( definitionResponse ) ;
365
384
} else {
366
- process . send ! ( emptyDefinitionResponse ) ;
385
+ send ( emptyDefinitionResponse ) ;
367
386
}
368
387
} else if ( msg . method === p . CompletionRequest . method ) {
369
388
let emptyCompletionResponse : m . ResponseMessage = {
@@ -374,13 +393,13 @@ process.on("message", (msg: m.Message) => {
374
393
let code = getOpenedFileContent ( msg . params . textDocument . uri ) ;
375
394
let result = runCompletionCommand ( msg , code ) ;
376
395
if ( result === null ) {
377
- process . send ! ( emptyCompletionResponse ) ;
396
+ send ( emptyCompletionResponse ) ;
378
397
} else {
379
398
let definitionResponse : m . ResponseMessage = {
380
399
...emptyCompletionResponse ,
381
400
result : result ,
382
401
} ;
383
- process . send ! ( definitionResponse ) ;
402
+ send ( definitionResponse ) ;
384
403
}
385
404
} else if ( msg . method === p . DocumentFormattingRequest . method ) {
386
405
// technically, a formatting failure should reply with the error. Sadly
@@ -409,8 +428,8 @@ process.on("message", (msg: m.Message) => {
409
428
method : "window/showMessage" ,
410
429
params : params ,
411
430
} ;
412
- process . send ! ( fakeSuccessResponse ) ;
413
- process . send ! ( response ) ;
431
+ send ( fakeSuccessResponse ) ;
432
+ send ( response ) ;
414
433
} else {
415
434
// See comment on findBscExeDirOfFile for why we need
416
435
// to recursively search for bsc.exe upward
@@ -425,8 +444,8 @@ process.on("message", (msg: m.Message) => {
425
444
method : "window/showMessage" ,
426
445
params : params ,
427
446
} ;
428
- process . send ! ( fakeSuccessResponse ) ;
429
- process . send ! ( response ) ;
447
+ send ( fakeSuccessResponse ) ;
448
+ send ( response ) ;
430
449
} else {
431
450
let resolvedBscExePath = path . join ( bscExeDir , c . bscExePartialPath ) ;
432
451
// code will always be defined here, even though technically it can be undefined
@@ -454,13 +473,13 @@ process.on("message", (msg: m.Message) => {
454
473
id : msg . id ,
455
474
result : result ,
456
475
} ;
457
- process . send ! ( response ) ;
476
+ send ( response ) ;
458
477
} else {
459
478
// let the diagnostics logic display the updated syntax errors,
460
479
// from the build.
461
480
// Again, not sending the actual errors. See fakeSuccessResponse
462
481
// above for explanation
463
- process . send ! ( fakeSuccessResponse ) ;
482
+ send ( fakeSuccessResponse ) ;
464
483
}
465
484
}
466
485
}
@@ -473,7 +492,7 @@ process.on("message", (msg: m.Message) => {
473
492
message : "Unrecognized editor request." ,
474
493
} ,
475
494
} ;
476
- process . send ! ( response ) ;
495
+ send ( response ) ;
477
496
}
478
497
} else if ( m . isResponseMessage ( msg ) ) {
479
498
// response message. Currently the client should have only sent a response
@@ -505,4 +524,4 @@ process.on("message", (msg: m.Message) => {
505
524
}
506
525
}
507
526
}
508
- } ) ;
527
+ }
0 commit comments