@@ -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,8 @@ 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
+ let messageSender : any = { send : ( msg : m . Message ) => process . send ! ( msg ) } ;
44
+
42
45
let sendUpdatedDiagnostics = ( ) => {
43
46
projectsFiles . forEach ( ( { filesWithDiagnostics } , projectRootPath ) => {
44
47
let content = fs . readFileSync (
@@ -60,7 +63,7 @@ let sendUpdatedDiagnostics = () => {
60
63
method : "textDocument/publishDiagnostics" ,
61
64
params : params ,
62
65
} ;
63
- process . send ! ( notification ) ;
66
+ messageSender . send ( notification ) ;
64
67
65
68
filesWithDiagnostics . add ( file ) ;
66
69
} ) ;
@@ -78,7 +81,7 @@ let sendUpdatedDiagnostics = () => {
78
81
method : "textDocument/publishDiagnostics" ,
79
82
params : params ,
80
83
} ;
81
- process . send ! ( notification ) ;
84
+ messageSender . send ( notification ) ;
82
85
filesWithDiagnostics . delete ( file ) ;
83
86
}
84
87
} ) ;
@@ -98,7 +101,7 @@ let deleteProjectDiagnostics = (projectRootPath: string) => {
98
101
method : "textDocument/publishDiagnostics" ,
99
102
params : params ,
100
103
} ;
101
- process . send ! ( notification ) ;
104
+ messageSender . send ( notification ) ;
102
105
} ) ;
103
106
104
107
projectsFiles . delete ( projectRootPath ) ;
@@ -167,7 +170,7 @@ let openedFile = (fileUri: string, fileContent: string) => {
167
170
method : "window/showMessageRequest" ,
168
171
params : params ,
169
172
} ;
170
- process . send ! ( request ) ;
173
+ messageSender . send ( request ) ;
171
174
// the client might send us back the "start build" action, which we'll
172
175
// handle in the isResponseMessage check in the message handling way
173
176
// below
@@ -216,7 +219,31 @@ let getOpenedFileContent = (fileUri: string) => {
216
219
return content ;
217
220
} ;
218
221
219
- process . on ( "message" , ( msg : m . Message ) => {
222
+ let onMessage = ( func : any ) => {
223
+ process . on ( "message" , ( msg : m . Message ) => {
224
+ func ( messageSender . send , msg ) ;
225
+ } )
226
+ } ;
227
+
228
+ let argv = process . argv . slice ( 2 ) ;
229
+ for ( let i = 0 ; i < argv . length ; i ++ ) {
230
+ let arg = argv [ i ] ;
231
+ if ( arg === "--stdio" ) {
232
+ let writer = new rpc . StreamMessageWriter ( process . stdout ) ;
233
+ let reader = new rpc . StreamMessageReader ( process . stdin ) ;
234
+ messageSender . send = ( msg : m . Message ) => writer . write ( msg ) ;
235
+ onMessage = ( ( func : any ) => {
236
+ let callback = ( message : m . Message ) => {
237
+ func ( messageSender . send , message ) ;
238
+ }
239
+ reader . listen ( callback ) ;
240
+ } ) ;
241
+
242
+ break ;
243
+ } ;
244
+ }
245
+
246
+ onMessage ( ( send : any , msg : m . Message ) => {
220
247
if ( m . isNotificationMessage ( msg ) ) {
221
248
// notification message, aka the client ends it and doesn't want a reply
222
249
if ( ! initialized && msg . method !== "exit" ) {
@@ -266,7 +293,7 @@ process.on("message", (msg: m.Message) => {
266
293
message : "Server not initialized." ,
267
294
} ,
268
295
} ;
269
- process . send ! ( response ) ;
296
+ send ( response ) ;
270
297
} else if ( msg . method === "initialize" ) {
271
298
// send the list of features we support
272
299
let result : p . InitializeResult = {
@@ -290,15 +317,15 @@ process.on("message", (msg: m.Message) => {
290
317
result : result ,
291
318
} ;
292
319
initialized = true ;
293
- process . send ! ( response ) ;
320
+ send ( response ) ;
294
321
} else if ( msg . method === "initialized" ) {
295
322
// sent from client after initialize. Nothing to do for now
296
323
let response : m . ResponseMessage = {
297
324
jsonrpc : c . jsonrpcVersion ,
298
325
id : msg . id ,
299
326
result : null ,
300
327
} ;
301
- process . send ! ( response ) ;
328
+ send ( response ) ;
302
329
} else if ( msg . method === "shutdown" ) {
303
330
// https://microsoft.github.io/language-server-protocol/specification#shutdown
304
331
if ( shutdownRequestAlreadyReceived ) {
@@ -310,7 +337,7 @@ process.on("message", (msg: m.Message) => {
310
337
message : `Language server already received the shutdown request` ,
311
338
} ,
312
339
} ;
313
- process . send ! ( response ) ;
340
+ send ( response ) ;
314
341
} else {
315
342
shutdownRequestAlreadyReceived = true ;
316
343
// TODO: recheck logic around init/shutdown...
@@ -322,7 +349,7 @@ process.on("message", (msg: m.Message) => {
322
349
id : msg . id ,
323
350
result : null ,
324
351
} ;
325
- process . send ! ( response ) ;
352
+ send ( response ) ;
326
353
}
327
354
} else if ( msg . method === p . HoverRequest . method ) {
328
355
let emptyHoverResponse : m . ResponseMessage = {
@@ -338,9 +365,9 @@ process.on("message", (msg: m.Message) => {
338
365
...emptyHoverResponse ,
339
366
result : { contents : result . hover } ,
340
367
} ;
341
- process . send ! ( hoverResponse ) ;
368
+ send ( hoverResponse ) ;
342
369
} else {
343
- process . send ! ( emptyHoverResponse ) ;
370
+ send ( emptyHoverResponse ) ;
344
371
}
345
372
} else if ( msg . method === p . DefinitionRequest . method ) {
346
373
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
@@ -361,9 +388,9 @@ process.on("message", (msg: m.Message) => {
361
388
range : result . definition . range ,
362
389
} ,
363
390
} ;
364
- process . send ! ( definitionResponse ) ;
391
+ send ( definitionResponse ) ;
365
392
} else {
366
- process . send ! ( emptyDefinitionResponse ) ;
393
+ send ( emptyDefinitionResponse ) ;
367
394
}
368
395
} else if ( msg . method === p . CompletionRequest . method ) {
369
396
let emptyCompletionResponse : m . ResponseMessage = {
@@ -374,13 +401,13 @@ process.on("message", (msg: m.Message) => {
374
401
let code = getOpenedFileContent ( msg . params . textDocument . uri ) ;
375
402
let result = runCompletionCommand ( msg , code ) ;
376
403
if ( result === null ) {
377
- process . send ! ( emptyCompletionResponse ) ;
404
+ send ( emptyCompletionResponse ) ;
378
405
} else {
379
406
let definitionResponse : m . ResponseMessage = {
380
407
...emptyCompletionResponse ,
381
408
result : result ,
382
409
} ;
383
- process . send ! ( definitionResponse ) ;
410
+ send ( definitionResponse ) ;
384
411
}
385
412
} else if ( msg . method === p . DocumentFormattingRequest . method ) {
386
413
// technically, a formatting failure should reply with the error. Sadly
@@ -409,8 +436,8 @@ process.on("message", (msg: m.Message) => {
409
436
method : "window/showMessage" ,
410
437
params : params ,
411
438
} ;
412
- process . send ! ( fakeSuccessResponse ) ;
413
- process . send ! ( response ) ;
439
+ send ( fakeSuccessResponse ) ;
440
+ send ( response ) ;
414
441
} else {
415
442
// See comment on findBscExeDirOfFile for why we need
416
443
// to recursively search for bsc.exe upward
@@ -425,8 +452,8 @@ process.on("message", (msg: m.Message) => {
425
452
method : "window/showMessage" ,
426
453
params : params ,
427
454
} ;
428
- process . send ! ( fakeSuccessResponse ) ;
429
- process . send ! ( response ) ;
455
+ send ( fakeSuccessResponse ) ;
456
+ send ( response ) ;
430
457
} else {
431
458
let resolvedBscExePath = path . join ( bscExeDir , c . bscExePartialPath ) ;
432
459
// code will always be defined here, even though technically it can be undefined
@@ -454,13 +481,13 @@ process.on("message", (msg: m.Message) => {
454
481
id : msg . id ,
455
482
result : result ,
456
483
} ;
457
- process . send ! ( response ) ;
484
+ send ( response ) ;
458
485
} else {
459
486
// let the diagnostics logic display the updated syntax errors,
460
487
// from the build.
461
488
// Again, not sending the actual errors. See fakeSuccessResponse
462
489
// above for explanation
463
- process . send ! ( fakeSuccessResponse ) ;
490
+ send ( fakeSuccessResponse ) ;
464
491
}
465
492
}
466
493
}
@@ -473,7 +500,7 @@ process.on("message", (msg: m.Message) => {
473
500
message : "Unrecognized editor request." ,
474
501
} ,
475
502
} ;
476
- process . send ! ( response ) ;
503
+ send ( response ) ;
477
504
}
478
505
} else if ( m . isResponseMessage ( msg ) ) {
479
506
// response message. Currently the client should have only sent a response
0 commit comments