@@ -34,7 +34,7 @@ import {
3434 DocumentOnTypeFormattingRequest , RenameRequest , DocumentSymbolRequest , DocumentLinkRequest , DocumentColorRequest , DeclarationRequest , FoldingRangeRequest ,
3535 ImplementationRequest , SelectionRangeRequest , TypeDefinitionRequest , CallHierarchyPrepareRequest , SemanticTokensRegistrationType , LinkedEditingRangeRequest ,
3636 TypeHierarchyPrepareRequest , InlineValueRequest , InlayHintRequest , WorkspaceSymbolRequest , TextDocumentRegistrationOptions , FileOperationRegistrationOptions ,
37- ConnectionOptions , PositionEncodingKind , DocumentDiagnosticRequest , NotebookDocumentSyncRegistrationType , NotebookDocumentSyncRegistrationOptions
37+ ConnectionOptions , PositionEncodingKind , DocumentDiagnosticRequest , NotebookDocumentSyncRegistrationType , NotebookDocumentSyncRegistrationOptions , ErrorCodes
3838} from 'vscode-languageserver-protocol' ;
3939
4040import * as c2p from './codeConverter' ;
@@ -431,6 +431,13 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
431431 private _clientOptions : ResolvedClientOptions ;
432432
433433 private _state : ClientState ;
434+ private _onStart : Promise < void > | undefined ;
435+ private _onStop : Promise < void > | undefined ;
436+ private _connection : Connection | undefined ;
437+ private _idleInterval : Disposable | undefined ;
438+ private readonly _ignoredRegistrations : Set < string > ;
439+ // private _idleStart: number | undefined;
440+
434441 private readonly _notificationHandlers : Map < string , GenericNotificationHandler > ;
435442 private readonly _notificationDisposables : Map < string , Disposable > ;
436443 private readonly _pendingNotificationHandlers : Map < string , GenericNotificationHandler > ;
@@ -441,12 +448,6 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
441448 private readonly _pendingProgressHandlers : Map < string | number , { type : ProgressType < any > ; handler : NotificationHandler < any > } > ;
442449 private readonly _progressDisposables : Map < string | number , Disposable > ;
443450
444- private _onStart : Promise < void > | undefined ;
445- private _onStop : Promise < void > | undefined ;
446- private _connection : Connection | undefined ;
447- private _idleInterval : Disposable | undefined ;
448- // private _idleStart: number | undefined;
449-
450451 private _initializeResult : InitializeResult | undefined ;
451452 private _outputChannel : OutputChannel | undefined ;
452453 private _disposeOutputChannel : boolean ;
@@ -510,6 +511,8 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
510511 this . _clientOptions . synchronize = this . _clientOptions . synchronize || { } ;
511512
512513 this . _state = ClientState . Initial ;
514+ this . _ignoredRegistrations = new Set ( ) ;
515+
513516 this . _notificationHandlers = new Map ( ) ;
514517 this . _pendingNotificationHandlers = new Map ( ) ;
515518 this . _notificationDisposables = new Map ( ) ;
@@ -642,6 +645,9 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
642645 public sendRequest < R > ( method : string , token ?: CancellationToken ) : Promise < R > ;
643646 public sendRequest < R > ( method : string , param : any , token ?: CancellationToken ) : Promise < R > ;
644647 public async sendRequest < R > ( type : string | MessageSignature , ...params : any [ ] ) : Promise < R > {
648+ if ( this . $state === ClientState . StartFailed || this . $state === ClientState . Stopping || this . $state === ClientState . Stopped ) {
649+ return Promise . reject ( new ResponseError ( ErrorCodes . ConnectionInactive , `Client is not running` ) ) ;
650+ }
645651 try {
646652 // Ensure we have a connection before we force the document sync.
647653 const connection = await this . $start ( ) ;
@@ -702,6 +708,9 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
702708 public sendNotification ( method : string ) : Promise < void > ;
703709 public sendNotification ( method : string , params : any ) : Promise < void > ;
704710 public async sendNotification < P > ( type : string | MessageSignature , params ?: P ) : Promise < void > {
711+ if ( this . $state === ClientState . StartFailed || this . $state === ClientState . Stopping || this . $state === ClientState . Stopped ) {
712+ return Promise . reject ( new ResponseError ( ErrorCodes . ConnectionInactive , `Client is not running` ) ) ;
713+ }
705714 try {
706715 // Ensure we have a connection before we force the document sync.
707716 const connection = await this . $start ( ) ;
@@ -925,12 +934,15 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
925934 if ( this . _onStart !== undefined ) {
926935 return this . _onStart ;
927936 }
937+ const [ promise , resolve , reject ] = this . createOnStartPromise ( ) ;
938+ this . _onStart = promise ;
939+
940+ // We are currently stopping the language client. Await the stop
941+ // before continuing.
928942 if ( this . _onStop !== undefined ) {
929943 await this . _onStop ;
930944 this . _onStop = undefined ;
931945 }
932- const [ promise , resolve , reject ] = this . createOnStartPromise ( ) ;
933- this . _onStart = promise ;
934946 // If we restart then the diagnostics collection is reused.
935947 if ( this . _diagnostics === undefined ) {
936948 this . _diagnostics = this . _clientOptions . diagnosticCollectionName
@@ -1206,12 +1218,12 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
12061218 return undefined ;
12071219 }
12081220
1209- public async stop ( timeout : number = 2000 ) : Promise < void > {
1221+ public stop ( timeout : number = 2000 ) : Promise < void > {
12101222 // Wait 2 seconds on stop
12111223 return this . shutdown ( 'stop' , timeout ) ;
12121224 }
12131225
1214- public async suspend ( ) : Promise < void > {
1226+ public suspend ( ) : Promise < void > {
12151227 // Wait 5 seconds on suspend.
12161228 return this . shutdown ( 'suspend' , 5000 ) ;
12171229 }
@@ -1259,6 +1271,7 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
12591271 this . _onStart = undefined ;
12601272 this . _onStop = undefined ;
12611273 this . _connection = undefined ;
1274+ this . _ignoredRegistrations . clear ( ) ;
12621275 } ) ;
12631276 }
12641277
@@ -1699,6 +1712,15 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
16991712 }
17001713
17011714 private async handleRegistrationRequest ( params : RegistrationParams ) : Promise < void > {
1715+ // We will not receive a registration call before a client is running
1716+ // from a server. However if we stop or shutdown we might which might
1717+ // try to restart the server. So ignore registrations if we are not running
1718+ if ( ! this . isRunning ( ) ) {
1719+ for ( const registration of params . registrations ) {
1720+ this . _ignoredRegistrations . add ( registration . id ) ;
1721+ }
1722+ return ;
1723+ }
17021724 interface WithDocumentSelector {
17031725 documentSelector : DocumentSelector | undefined ;
17041726 }
@@ -1723,6 +1745,9 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
17231745
17241746 private async handleUnregistrationRequest ( params : UnregistrationParams ) : Promise < void > {
17251747 for ( let unregistration of params . unregisterations ) {
1748+ if ( this . _ignoredRegistrations . has ( unregistration . id ) ) {
1749+ continue ;
1750+ }
17261751 const feature = this . _dynamicFeatures . get ( unregistration . method ) ;
17271752 if ( ! feature ) {
17281753 return Promise . reject ( new Error ( `No feature implementation for ${ unregistration . method } found. Unregistration failed.` ) ) ;
@@ -1771,6 +1796,11 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
17711796 public handleFailedRequest < T > ( type : MessageSignature , token : CancellationToken | undefined , error : any , defaultValue : T , showNotification : boolean = true ) : T {
17721797 // If we get a request cancel or a content modified don't log anything.
17731798 if ( error instanceof ResponseError ) {
1799+ // The connection got disposed while we were waiting for a response.
1800+ // Simply return the default value. Is the best we can do.
1801+ if ( error . code === ErrorCodes . PendingResponseRejected || error . code === ErrorCodes . ConnectionInactive ) {
1802+ return defaultValue ;
1803+ }
17741804 if ( error . code === LSPErrorCodes . RequestCancelled || error . code === LSPErrorCodes . ServerCancelled ) {
17751805 if ( token !== undefined && token . isCancellationRequested ) {
17761806 return defaultValue ;
0 commit comments