@@ -104,6 +104,12 @@ interface ConfigStateReceived {
104104 timeout : boolean ;
105105}
106106
107+ interface PendingTagParsingCall {
108+ promise : ManualPromise < boolean > ;
109+ timer : NodeJS . Timeout ;
110+ cancellationListener : vscode . Disposable ;
111+ }
112+
107113let workspaceHash : string = "" ;
108114
109115let workspaceDisposables : vscode . Disposable [ ] = [ ] ;
@@ -805,6 +811,7 @@ export interface Client {
805811 setCurrentConfigName ( configurationName : string ) : Thenable < void > ;
806812 getCurrentConfigName ( ) : Thenable < string | undefined > ;
807813 getCurrentConfigCustomVariable ( variableName : string ) : Thenable < string > ;
814+ waitForTagParsing ( timeout : number , token : vscode . CancellationToken ) : Promise < boolean > ;
808815 getVcpkgInstalled ( ) : Thenable < boolean > ;
809816 getVcpkgEnabled ( ) : Thenable < boolean > ;
810817 getCurrentCompilerPathAndArgs ( ) : Thenable < util . CompilerPathAndArgs | undefined > ;
@@ -919,6 +926,7 @@ export class DefaultClient implements Client {
919926
920927 private configStateReceived : ConfigStateReceived = { compilers : false , compileCommands : false , configProviders : undefined , timeout : false } ;
921928 private showConfigureIntelliSenseButton : boolean = false ;
929+ private pendingTagParsingCalls : PendingTagParsingCall [ ] = [ ] ;
922930
923931 /** A queue of asynchronous tasks that need to be processed befofe ready is considered active. */
924932 private static queue = new Array < [ ManualPromise < unknown > , ( ) => Promise < unknown > ] | [ ManualPromise < unknown > ] > ( ) ;
@@ -1008,6 +1016,62 @@ export class DefaultClient implements Client {
10081016 } ;
10091017 }
10101018
1019+ // If there are any pending calls that were waiting for tag parsing to complete, we can resolve them since it's finished. If there are no pending calls, this does nothing.
1020+ private resolvePendingTagParsingCallsIfReady ( ) : void {
1021+ if ( ! this . pendingTagParsingCalls . length || this . IsTagParsing ) {
1022+ return ;
1023+ }
1024+
1025+ const pendingCalls : PendingTagParsingCall [ ] = this . pendingTagParsingCalls ;
1026+ this . pendingTagParsingCalls = [ ] ;
1027+ pendingCalls . forEach ( pendingCall => {
1028+ if ( pendingCall . timer ) {
1029+ clearTimeout ( pendingCall . timer ) ;
1030+ }
1031+ pendingCall . cancellationListener . dispose ( ) ;
1032+ pendingCall . promise . resolve ( true ) ;
1033+ } ) ;
1034+ }
1035+
1036+ public async waitForTagParsing ( timeout : number , token : vscode . CancellationToken ) : Promise < boolean > {
1037+ // On initialization, the client has UI bools all set to false which could cause an early return. We want to ensure it's ready first.
1038+ await this . ready ;
1039+
1040+ if ( ! this . IsTagParsing ) {
1041+ return true ;
1042+ }
1043+
1044+ if ( token . isCancellationRequested ) {
1045+ throw new vscode . CancellationError ( ) ;
1046+ }
1047+
1048+ const pendingCall : PendingTagParsingCall = {
1049+ promise : new ManualPromise < boolean > ( ) ,
1050+
1051+ timer : global . setTimeout ( ( ) => {
1052+ const index : number = this . pendingTagParsingCalls . indexOf ( pendingCall ) ;
1053+ if ( index !== - 1 ) {
1054+ this . pendingTagParsingCalls . splice ( index , 1 ) ;
1055+ }
1056+ pendingCall . cancellationListener . dispose ( ) ;
1057+ pendingCall . promise . resolve ( false ) ;
1058+ } , timeout ) ,
1059+
1060+ cancellationListener : token . onCancellationRequested ( ( ) => {
1061+ const index : number = this . pendingTagParsingCalls . indexOf ( pendingCall ) ;
1062+ if ( index !== - 1 ) {
1063+ this . pendingTagParsingCalls . splice ( index , 1 ) ;
1064+ }
1065+ clearTimeout ( pendingCall . timer ) ;
1066+ pendingCall . cancellationListener . dispose ( ) ;
1067+ pendingCall . promise . reject ( new vscode . CancellationError ( ) ) ;
1068+ } )
1069+ } ;
1070+
1071+ this . pendingTagParsingCalls . push ( pendingCall ) ;
1072+ return pendingCall . promise ;
1073+ }
1074+
10111075 private getName ( workspaceFolder ?: vscode . WorkspaceFolder ) : string {
10121076 return workspaceFolder ? workspaceFolder . name : "untitled" ;
10131077 }
@@ -2893,6 +2957,8 @@ export class DefaultClient implements Client {
28932957 } else if ( message . includes ( "/" ) ) {
28942958 this . lastInvokedLspMessage = message ;
28952959 }
2960+
2961+ this . resolvePendingTagParsingCallsIfReady ( ) ;
28962962 }
28972963
28982964 private updateTagParseStatus ( tagParseStatus : TagParseStatus ) : void {
@@ -4208,6 +4274,14 @@ export class DefaultClient implements Client {
42084274 }
42094275
42104276 public dispose ( ) : void {
4277+ this . pendingTagParsingCalls . forEach ( pendingCall => {
4278+ if ( pendingCall . timer ) {
4279+ clearTimeout ( pendingCall . timer ) ;
4280+ }
4281+ pendingCall . cancellationListener . dispose ( ) ;
4282+ pendingCall . promise . resolve ( false ) ;
4283+ } ) ;
4284+ this . pendingTagParsingCalls = [ ] ;
42114285 this . disposables . forEach ( ( d ) => d . dispose ( ) ) ;
42124286 this . disposables = [ ] ;
42134287 if ( this . documentFormattingProviderDisposable ) {
@@ -4360,6 +4434,7 @@ class NullClient implements Client {
43604434 setCurrentConfigName ( configurationName : string ) : Thenable < void > { return Promise . resolve ( ) ; }
43614435 getCurrentConfigName ( ) : Thenable < string > { return Promise . resolve ( "" ) ; }
43624436 getCurrentConfigCustomVariable ( variableName : string ) : Thenable < string > { return Promise . resolve ( "" ) ; }
4437+ waitForTagParsing ( timeout : number , token : vscode . CancellationToken ) : Promise < boolean > { return Promise . resolve ( true ) ; }
43634438 getVcpkgInstalled ( ) : Thenable < boolean > { return Promise . resolve ( false ) ; }
43644439 getVcpkgEnabled ( ) : Thenable < boolean > { return Promise . resolve ( false ) ; }
43654440 getCurrentCompilerPathAndArgs ( ) : Thenable < util . CompilerPathAndArgs | undefined > { return Promise . resolve ( undefined ) ; }
0 commit comments