@@ -434,11 +434,14 @@ export class LanguageClientManager {
434
434
this . languageClient = undefined ;
435
435
return ;
436
436
}
437
- const client = this . createLSPClient ( folder ) ;
438
- return this . startClient ( client ) ;
437
+ const { client, errorHandler } = this . createLSPClient ( folder ) ;
438
+ return this . startClient ( client , errorHandler ) ;
439
439
}
440
440
441
- private createLSPClient ( folder ?: vscode . Uri ) : langclient . LanguageClient {
441
+ private createLSPClient ( folder ?: vscode . Uri ) : {
442
+ client : langclient . LanguageClient ;
443
+ errorHandler : SourceKitLSPErrorHandler ;
444
+ } {
442
445
const toolchainSourceKitLSP =
443
446
this . workspaceContext . toolchain . getToolchainExecutable ( "sourcekit-lsp" ) ;
444
447
const lspConfig = configuration . lsp ;
@@ -488,6 +491,7 @@ export class LanguageClientManager {
488
491
workspaceFolder = { uri : folder , name : FolderContext . uriName ( folder ) , index : 0 } ;
489
492
}
490
493
494
+ const errorHandler = new SourceKitLSPErrorHandler ( 5 ) ;
491
495
const clientOptions : langclient . LanguageClientOptions = {
492
496
documentSelector : LanguageClientManager . documentSelector ,
493
497
revealOutputChannelOn : langclient . RevealOutputChannelOn . Never ,
@@ -563,7 +567,10 @@ export class LanguageClientManager {
563
567
} ;
564
568
} ) ( ) ,
565
569
} ,
566
- errorHandler : new SourceKitLSPErrorHandler ( 5 ) ,
570
+ errorHandler,
571
+ // Avoid attempting to reinitialize multiple times. If we fail to initialize
572
+ // we aren't doing anything different the second time and so will fail again.
573
+ initializationFailedHandler : ( ) => false ,
567
574
initializationOptions : {
568
575
"workspace/peekDocuments" : true , // workaround for client capability to handle `PeekDocumentsRequest`
569
576
"textDocument/codeLens" : {
@@ -575,15 +582,21 @@ export class LanguageClientManager {
575
582
} ,
576
583
} ;
577
584
578
- return new langclient . LanguageClient (
579
- "swift.sourcekit-lsp" ,
580
- "SourceKit Language Server" ,
581
- serverOptions ,
582
- clientOptions
583
- ) ;
585
+ return {
586
+ client : new langclient . LanguageClient (
587
+ "swift.sourcekit-lsp" ,
588
+ "SourceKit Language Server" ,
589
+ serverOptions ,
590
+ clientOptions
591
+ ) ,
592
+ errorHandler,
593
+ } ;
584
594
}
585
595
586
- private async startClient ( client : langclient . LanguageClient ) {
596
+ private async startClient (
597
+ client : langclient . LanguageClient ,
598
+ errorHandler : SourceKitLSPErrorHandler
599
+ ) {
587
600
client . onDidChangeState ( e => {
588
601
// if state is now running add in any sub-folder workspaces that
589
602
// we have cached. If this is the first time we are starting then
@@ -595,7 +608,6 @@ export class LanguageClientManager {
595
608
) {
596
609
this . addSubFolderWorkspaces ( client ) ;
597
610
}
598
- //console.log(e);
599
611
} ) ;
600
612
if ( client . clientOptions . workspaceFolder ) {
601
613
this . workspaceContext . outputChannel . log (
@@ -615,6 +627,10 @@ export class LanguageClientManager {
615
627
this . clientReadyPromise = client
616
628
. start ( )
617
629
. then ( ( ) => {
630
+ // Now that we've started up correctly, start the error handler to auto-restart
631
+ // if sourcekit-lsp crashes during normal operation.
632
+ errorHandler . enable ( ) ;
633
+
618
634
if ( this . workspaceContext . swiftVersion . isLessThan ( new Version ( 5 , 7 , 0 ) ) ) {
619
635
this . legacyInlayHints = activateLegacyInlayHints ( client ) ;
620
636
}
@@ -623,7 +639,6 @@ export class LanguageClientManager {
623
639
} )
624
640
. catch ( reason => {
625
641
this . workspaceContext . outputChannel . log ( `${ reason } ` ) ;
626
- // if language client failed to initialise then shutdown and set to undefined
627
642
this . languageClient ?. stop ( ) ;
628
643
this . languageClient = undefined ;
629
644
throw reason ;
@@ -671,10 +686,17 @@ export class LanguageClientManager {
671
686
*/
672
687
class SourceKitLSPErrorHandler implements langclient . ErrorHandler {
673
688
private restarts : number [ ] ;
689
+ private enabled : boolean = false ;
674
690
675
691
constructor ( private maxRestartCount : number ) {
676
692
this . restarts = [ ] ;
677
693
}
694
+ /**
695
+ * Start listening for errors and requesting to restart the LSP server when appropriate.
696
+ */
697
+ enable ( ) {
698
+ this . enabled = true ;
699
+ }
678
700
/**
679
701
* An error has occurred while writing or reading from the connection.
680
702
*
@@ -697,6 +719,13 @@ class SourceKitLSPErrorHandler implements langclient.ErrorHandler {
697
719
* The connection to the server got closed.
698
720
*/
699
721
closed ( ) : langclient . CloseHandlerResult | Promise < langclient . CloseHandlerResult > {
722
+ if ( ! this . enabled ) {
723
+ return {
724
+ action : langclient . CloseAction . DoNotRestart ,
725
+ handled : true ,
726
+ } ;
727
+ }
728
+
700
729
this . restarts . push ( Date . now ( ) ) ;
701
730
if ( this . restarts . length <= this . maxRestartCount ) {
702
731
return { action : langclient . CloseAction . Restart } ;
0 commit comments