Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ export interface Client {
setCurrentConfigName(configurationName: string): Thenable<void>;
getCurrentConfigName(): Thenable<string | undefined>;
getCurrentConfigCustomVariable(variableName: string): Thenable<string>;
waitForTagParsing(timeout: number, token: vscode.CancellationToken): Promise<boolean>;
getVcpkgInstalled(): Thenable<boolean>;
getVcpkgEnabled(): Thenable<boolean>;
getCurrentCompilerPathAndArgs(): Thenable<util.CompilerPathAndArgs | undefined>;
Expand Down Expand Up @@ -919,6 +920,7 @@ export class DefaultClient implements Client {

private configStateReceived: ConfigStateReceived = { compilers: false, compileCommands: false, configProviders: undefined, timeout: false };
private showConfigureIntelliSenseButton: boolean = false;
private pendingTagParsingCalls: { promise: ManualPromise<boolean>; timer?: NodeJS.Timeout; cancellationListener?: vscode.Disposable }[] = [];

/** A queue of asynchronous tasks that need to be processed befofe ready is considered active. */
private static queue = new Array<[ManualPromise<unknown>, () => Promise<unknown>] | [ManualPromise<unknown>]>();
Expand Down Expand Up @@ -1008,6 +1010,64 @@ export class DefaultClient implements Client {
};
}

// 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.
private resolvePendingTagParsingCallsIfReady(): void {
if (!this.pendingTagParsingCalls.length || this.IsTagParsing) {
return;
}

const pendingCalls: { promise: ManualPromise<boolean>; timer?: NodeJS.Timeout; cancellationListener?: vscode.Disposable }[] = this.pendingTagParsingCalls;
this.pendingTagParsingCalls = [];
pendingCalls.forEach(pendingCall => {
if (pendingCall.timer) {
clearTimeout(pendingCall.timer);
}
pendingCall.cancellationListener?.dispose();
pendingCall.promise.resolve(true);
});
}

public async waitForTagParsing(timeout: number, token: vscode.CancellationToken): Promise<boolean> {
// 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.
await this.ready;

if (!this.IsTagParsing) {
return true;
}

if (token.isCancellationRequested) {
throw new vscode.CancellationError();
}

const pendingCall: { promise: ManualPromise<boolean>; timer?: NodeJS.Timeout; cancellationListener?: vscode.Disposable } = {
promise: new ManualPromise<boolean>()
};

pendingCall.timer = global.setTimeout(() => {
const index: number = this.pendingTagParsingCalls.indexOf(pendingCall);
if (index !== -1) {
this.pendingTagParsingCalls.splice(index, 1);
}
pendingCall.cancellationListener?.dispose();
pendingCall.promise.resolve(false);
}, timeout);

pendingCall.cancellationListener = token.onCancellationRequested(() => {
const index: number = this.pendingTagParsingCalls.indexOf(pendingCall);
if (index !== -1) {
this.pendingTagParsingCalls.splice(index, 1);
}
if (pendingCall.timer) {
clearTimeout(pendingCall.timer);
}
pendingCall.cancellationListener?.dispose();
pendingCall.promise.reject(new vscode.CancellationError());
});

this.pendingTagParsingCalls.push(pendingCall);
return pendingCall.promise;
}

private getName(workspaceFolder?: vscode.WorkspaceFolder): string {
return workspaceFolder ? workspaceFolder.name : "untitled";
}
Expand Down Expand Up @@ -2893,6 +2953,8 @@ export class DefaultClient implements Client {
} else if (message.includes("/")) {
this.lastInvokedLspMessage = message;
}

this.resolvePendingTagParsingCallsIfReady();
}

private updateTagParseStatus(tagParseStatus: TagParseStatus): void {
Expand Down Expand Up @@ -4208,6 +4270,14 @@ export class DefaultClient implements Client {
}

public dispose(): void {
this.pendingTagParsingCalls.forEach(pendingCall => {
if (pendingCall.timer) {
clearTimeout(pendingCall.timer);
}
pendingCall.cancellationListener?.dispose();
pendingCall.promise.resolve(false);
});
this.pendingTagParsingCalls = [];
this.disposables.forEach((d) => d.dispose());
this.disposables = [];
if (this.documentFormattingProviderDisposable) {
Expand Down Expand Up @@ -4360,6 +4430,7 @@ class NullClient implements Client {
setCurrentConfigName(configurationName: string): Thenable<void> { return Promise.resolve(); }
getCurrentConfigName(): Thenable<string> { return Promise.resolve(""); }
getCurrentConfigCustomVariable(variableName: string): Thenable<string> { return Promise.resolve(""); }
waitForTagParsing(timeout: number, token: vscode.CancellationToken): Promise<boolean> { return token.isCancellationRequested ? Promise.reject(new vscode.CancellationError()) : Promise.resolve(true); }
getVcpkgInstalled(): Thenable<boolean> { return Promise.resolve(false); }
getVcpkgEnabled(): Thenable<boolean> { return Promise.resolve(false); }
getCurrentCompilerPathAndArgs(): Thenable<util.CompilerPathAndArgs | undefined> { return Promise.resolve(undefined); }
Expand Down
5 changes: 5 additions & 0 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ export async function registerCommands(enabled: boolean): Promise<void> {
commandDisposables.push(vscode.commands.registerCommand('cpptools.activeConfigName', enabled ? onGetActiveConfigName : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('cpptools.activeConfigCustomVariable', enabled ? onGetActiveConfigCustomVariable : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('cpptools.setActiveConfigName', enabled ? onSetActiveConfigName : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.waitForTagParsing', enabled ? onWaitForTagParsing : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RestartIntelliSenseForFile', enabled ? onRestartIntelliSenseForFile : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.GenerateDoxygenComment', enabled ? onGenerateDoxygenComment : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CreateDeclarationOrDefinition', enabled ? onCreateDeclarationOrDefinition : onDisabledCommand));
Expand Down Expand Up @@ -977,6 +978,10 @@ function onGetActiveConfigCustomVariable(variableName: string): Thenable<string>
return clients.ActiveClient.getCurrentConfigCustomVariable(variableName);
}

async function onWaitForTagParsing(timeout: number, token: vscode.CancellationToken): Promise<boolean> {
return clients.getDefaultClient().waitForTagParsing(timeout, token);
}

function onLogDiagnostics(): Promise<void> {
return clients.ActiveClient.logDiagnostics();
}
Expand Down
Loading