@@ -82,6 +82,7 @@ export interface ForkOptions {
82
82
env ?: any ;
83
83
encoding ?: string ;
84
84
execArgv ?: string [ ] ;
85
+ detached ?: boolean ;
85
86
}
86
87
87
88
export interface NodeModule {
@@ -130,6 +131,7 @@ export class LanguageClient extends BaseLanguageClient {
130
131
private readonly _serverOptions : ServerOptions ;
131
132
private readonly _forceDebug : boolean ;
132
133
private _serverProcess : ChildProcess | undefined ;
134
+ /** Use {@link _setDetached} to set the value unless necessary */
133
135
private _isDetached : boolean | undefined ;
134
136
private _isInDebugMode : boolean ;
135
137
@@ -285,20 +287,22 @@ export class LanguageClient extends BaseLanguageClient {
285
287
if ( Is . func ( server ) ) {
286
288
return server ( ) . then ( ( result ) => {
287
289
if ( MessageTransports . is ( result ) ) {
288
- this . _isDetached = ! ! result . detached ;
290
+ this . _setDetached ( ! ! result . detached ) ;
289
291
return result ;
290
292
} else if ( StreamInfo . is ( result ) ) {
291
- this . _isDetached = ! ! result . detached ;
293
+ this . _setDetached ( ! ! result . detached ) ;
292
294
return { reader : new StreamMessageReader ( result . reader ) , writer : new StreamMessageWriter ( result . writer ) } ;
293
295
} else {
294
296
let cp : ChildProcess ;
297
+ let isDetached ;
295
298
if ( ChildProcessInfo . is ( result ) ) {
296
299
cp = result . process ;
297
- this . _isDetached = result . detached ;
300
+ isDetached = result . detached ;
298
301
} else {
299
302
cp = result ;
300
- this . _isDetached = false ;
303
+ isDetached = false ;
301
304
}
305
+ this . _setDetached ( isDetached , cp ) ;
302
306
cp . stderr ! . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
303
307
return { reader : new StreamMessageReader ( cp . stdout ! ) , writer : new StreamMessageWriter ( cp . stdin ! ) } ;
304
308
}
@@ -348,13 +352,17 @@ export class LanguageClient extends BaseLanguageClient {
348
352
} else if ( Transport . isSocket ( transport ) ) {
349
353
args . push ( `--socket=${ transport . port } ` ) ;
350
354
}
355
+ if ( node . options ?. detached ) {
356
+ args . push ( '--detached' ) ;
357
+ }
351
358
args . push ( `--clientProcessId=${ process . pid . toString ( ) } ` ) ;
352
359
if ( transport === TransportKind . ipc || transport === TransportKind . stdio ) {
353
360
const serverProcess = cp . spawn ( runtime , args , execOptions ) ;
354
361
if ( ! serverProcess || ! serverProcess . pid ) {
355
362
return handleChildProcessStartError ( serverProcess , `Launching server using runtime ${ runtime } failed.` ) ;
356
363
}
357
364
this . _serverProcess = serverProcess ;
365
+ this . _setDetached ( ! ! node . options ?. detached , serverProcess ) ;
358
366
serverProcess . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
359
367
if ( transport === TransportKind . ipc ) {
360
368
serverProcess . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
@@ -369,6 +377,7 @@ export class LanguageClient extends BaseLanguageClient {
369
377
return handleChildProcessStartError ( process , `Launching server using runtime ${ runtime } failed.` ) ;
370
378
}
371
379
this . _serverProcess = process ;
380
+ this . _setDetached ( ! ! node . options ?. detached , process ) ;
372
381
process . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
373
382
process . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
374
383
return transport . onConnected ( ) . then ( ( protocol ) => {
@@ -382,6 +391,7 @@ export class LanguageClient extends BaseLanguageClient {
382
391
return handleChildProcessStartError ( process , `Launching server using runtime ${ runtime } failed.` ) ;
383
392
}
384
393
this . _serverProcess = process ;
394
+ this . _setDetached ( ! ! node . options ?. detached , process ) ;
385
395
process . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
386
396
process . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
387
397
return transport . onConnected ( ) . then ( ( protocol ) => {
@@ -404,6 +414,9 @@ export class LanguageClient extends BaseLanguageClient {
404
414
args . push ( `--socket=${ transport . port } ` ) ;
405
415
}
406
416
args . push ( `--clientProcessId=${ process . pid . toString ( ) } ` ) ;
417
+ if ( node . options ?. detached ) {
418
+ args . push ( '--detached' ) ;
419
+ }
407
420
const options : cp . ForkOptions = node . options ?? Object . create ( null ) ;
408
421
options . env = getEnvironment ( options . env , true ) ;
409
422
options . execArgv = options . execArgv || [ ] ;
@@ -413,6 +426,7 @@ export class LanguageClient extends BaseLanguageClient {
413
426
const sp = cp . fork ( node . module , args || [ ] , options ) ;
414
427
assertStdio ( sp ) ;
415
428
this . _serverProcess = sp ;
429
+ this . _setDetached ( ! ! options . detached , sp ) ;
416
430
sp . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
417
431
if ( transport === TransportKind . ipc ) {
418
432
sp . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
@@ -425,6 +439,7 @@ export class LanguageClient extends BaseLanguageClient {
425
439
const sp = cp . fork ( node . module , args || [ ] , options ) ;
426
440
assertStdio ( sp ) ;
427
441
this . _serverProcess = sp ;
442
+ this . _setDetached ( ! ! options . detached , sp ) ;
428
443
sp . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
429
444
sp . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
430
445
transport . onConnected ( ) . then ( ( protocol ) => {
@@ -436,6 +451,7 @@ export class LanguageClient extends BaseLanguageClient {
436
451
const sp = cp . fork ( node . module , args || [ ] , options ) ;
437
452
assertStdio ( sp ) ;
438
453
this . _serverProcess = sp ;
454
+ this . _setDetached ( ! ! options . detached , sp ) ;
439
455
sp . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
440
456
sp . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
441
457
transport . onConnected ( ) . then ( ( protocol ) => {
@@ -460,6 +476,9 @@ export class LanguageClient extends BaseLanguageClient {
460
476
} else if ( transport === TransportKind . ipc ) {
461
477
throw new Error ( `Transport kind ipc is not support for command executable` ) ;
462
478
}
479
+ if ( command . options ?. detached ) {
480
+ args . push ( '--detached' ) ;
481
+ }
463
482
const options = Object . assign ( { } , command . options ) ;
464
483
options . cwd = options . cwd || serverWorkingDir ;
465
484
if ( transport === undefined || transport === TransportKind . stdio ) {
@@ -469,7 +488,7 @@ export class LanguageClient extends BaseLanguageClient {
469
488
}
470
489
serverProcess . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
471
490
this . _serverProcess = serverProcess ;
472
- this . _isDetached = ! ! options . detached ;
491
+ this . _setDetached ( ! ! options . detached , serverProcess ) ;
473
492
return Promise . resolve ( { reader : new StreamMessageReader ( serverProcess . stdout ) , writer : new StreamMessageWriter ( serverProcess . stdin ) } ) ;
474
493
} else if ( transport === TransportKind . pipe ) {
475
494
return createClientPipeTransport ( pipeName ! ) . then ( ( transport ) => {
@@ -478,7 +497,7 @@ export class LanguageClient extends BaseLanguageClient {
478
497
return handleChildProcessStartError ( serverProcess , `Launching server using command ${ command . command } failed.` ) ;
479
498
}
480
499
this . _serverProcess = serverProcess ;
481
- this . _isDetached = ! ! options . detached ;
500
+ this . _setDetached ( ! ! options . detached , serverProcess ) ;
482
501
serverProcess . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
483
502
serverProcess . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
484
503
return transport . onConnected ( ) . then ( ( protocol ) => {
@@ -492,7 +511,7 @@ export class LanguageClient extends BaseLanguageClient {
492
511
return handleChildProcessStartError ( serverProcess , `Launching server using command ${ command . command } failed.` ) ;
493
512
}
494
513
this . _serverProcess = serverProcess ;
495
- this . _isDetached = ! ! options . detached ;
514
+ this . _setDetached ( ! ! options . detached , serverProcess ) ;
496
515
serverProcess . stderr . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
497
516
serverProcess . stdout . on ( 'data' , data => this . outputChannel . append ( Is . string ( data ) ? data : data . toString ( encoding ) ) ) ;
498
517
return transport . onConnected ( ) . then ( ( protocol ) => {
@@ -568,6 +587,21 @@ export class LanguageClient extends BaseLanguageClient {
568
587
return Promise . resolve ( undefined ) ;
569
588
}
570
589
590
+ /**
591
+ * Setter that should be used for {@link _isDetached}. It performs additional
592
+ * actions based on the value set for detached.
593
+ */
594
+ private _setDetached ( isDetached : boolean , serverProcess ?: cp . ChildProcess ) {
595
+ if ( ! isDetached ) {
596
+ this . _isDetached = false ;
597
+ return ;
598
+ }
599
+
600
+ this . _isDetached = true ;
601
+ // Ensures the parent can exit even if the child (server) is still running
602
+ serverProcess ?. unref ( ) ;
603
+ }
604
+
571
605
}
572
606
573
607
export class SettingMonitor {
0 commit comments