Skip to content

Commit 15dac43

Browse files
authored
A non awaiting version of the context provider registration code. (#13924)
1 parent c101b67 commit 15dac43

File tree

3 files changed

+76
-47
lines changed

3 files changed

+76
-47
lines changed

Extension/src/LanguageServer/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1389,7 +1389,7 @@ export class DefaultClient implements Client {
13891389
this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(util.documentSelector, this.semanticTokensProvider, semanticTokensLegend);
13901390
}
13911391

1392-
this.copilotCompletionProvider = await CopilotCompletionContextProvider.Create();
1392+
this.copilotCompletionProvider = CopilotCompletionContextProvider.Create();
13931393
this.disposables.push(this.copilotCompletionProvider);
13941394

13951395
// Listen for messages from the language server.

Extension/src/LanguageServer/copilotCompletionContextProvider.ts

Lines changed: 74 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,9 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
304304
return Math.round(performance.now() - startTime);
305305
}
306306

307-
public static async Create() {
307+
public static Create() {
308308
const copilotCompletionProvider = new CopilotCompletionContextProvider(getOutputChannelLogger());
309-
await copilotCompletionProvider.registerCopilotContextProvider();
309+
copilotCompletionProvider.registerCopilotContextProvider();
310310
return copilotCompletionProvider;
311311
}
312312

@@ -445,58 +445,94 @@ ${copilotCompletionContext?.areSnippetsMissing ? "(missing code snippets)" : ""}
445445
}
446446
}
447447

448-
public async registerCopilotContextProvider(): Promise<void> {
449-
const properties: Record<string, string> = {};
448+
public registerCopilotContextProvider(): void {
450449
const registerCopilotContextProvider = 'registerCopilotContextProvider';
451-
try {
452-
const copilotApi = await getCopilotClientApi();
453-
const copilotChatApi = await getCopilotChatApi();
454-
if (!copilotApi && !copilotChatApi) { throw new CopilotContextProviderException("getCopilotApi() returned null, Copilot is missing or inactive."); }
455-
const contextProvider = {
456-
id: CopilotCompletionContextProvider.providerId,
457-
selector: CopilotCompletionContextProvider.defaultCppDocumentSelector,
458-
resolver: this
459-
};
460-
type InstallSummary = { hasGetContextProviderAPI: boolean; hasAPI: boolean };
461-
const installSummary: { client?: InstallSummary; chat?: InstallSummary } = {};
462-
if (copilotApi) {
463-
installSummary.client = await this.installContextProvider(copilotApi, contextProvider);
450+
const contextProvider = {
451+
id: CopilotCompletionContextProvider.providerId,
452+
selector: CopilotCompletionContextProvider.defaultCppDocumentSelector,
453+
resolver: this
454+
};
455+
type RegistrationResult = { message: string } | boolean;
456+
const clientPromise: Promise<RegistrationResult> = getCopilotClientApi().then(async (api) => {
457+
if (!api) {
458+
throw new CopilotContextProviderException("getCopilotApi() returned null, Copilot client is missing or inactive.");
459+
}
460+
const disposable = await this.installContextProvider(api, contextProvider);
461+
if (disposable) {
462+
this.contextProviderDisposables = this.contextProviderDisposables ?? [];
463+
this.contextProviderDisposables.push(disposable);
464+
return true;
465+
} else {
466+
throw new CopilotContextProviderException("getContextProviderAPI() is not available in Copilot client.");
464467
}
465-
if (copilotChatApi) {
466-
installSummary.chat = await this.installContextProvider(copilotChatApi, contextProvider);
468+
}).catch((e) => {
469+
console.debug("Failed to register the Copilot Context Provider with Copilot client.");
470+
let message = "Failed to register the Copilot Context Provider with Copilot client";
471+
if (e instanceof CopilotContextProviderException) {
472+
message += `: ${e.message} `;
467473
}
468-
if (installSummary.client?.hasAPI || installSummary.chat?.hasAPI) {
469-
properties["cppCodeSnippetsProviderRegistered"] = "true";
474+
return { message };
475+
});
476+
const chatPromise: Promise<RegistrationResult> = getCopilotChatApi().then(async (api) => {
477+
if (!api) {
478+
throw new CopilotContextProviderException("getCopilotChatApi() returned null, Copilot Chat is missing or inactive.");
479+
}
480+
const disposable = await this.installContextProvider(api, contextProvider);
481+
if (disposable) {
482+
this.contextProviderDisposables = this.contextProviderDisposables ?? [];
483+
this.contextProviderDisposables.push(disposable);
484+
return true;
470485
} else {
471-
if (installSummary.client?.hasGetContextProviderAPI === false &&
472-
installSummary.chat?.hasGetContextProviderAPI === false) {
473-
throw new CopilotContextProviderException("getContextProviderAPI() is not available.");
474-
} else {
475-
throw new CopilotContextProviderException("getContextProviderAPI(v1) returned null.");
476-
}
486+
throw new CopilotContextProviderException("getContextProviderAPI() is not available in Copilot Chat.");
477487
}
478-
} catch (e) {
479-
console.debug("Failed to register the Copilot Context Provider.");
480-
properties["error"] = "Failed to register the Copilot Context Provider";
488+
}).catch((e) => {
489+
console.debug("Failed to register the Copilot Context Provider with Copilot Chat.");
490+
let message = "Failed to register the Copilot Context Provider with Copilot Chat";
481491
if (e instanceof CopilotContextProviderException) {
482-
properties["error"] += `: ${e.message} `;
492+
message += `: ${e.message} `;
483493
}
484-
} finally {
494+
return { message };
495+
});
496+
// The client usually doesn't block. So test it first.
497+
clientPromise.then((clientResult) => {
498+
const properties: Record<string, string> = {};
499+
if (isBoolean(clientResult) && clientResult) {
500+
properties["cppCodeSnippetsProviderRegistered"] = "true";
501+
telemetry.logCopilotEvent(registerCopilotContextProvider, { ...properties });
502+
return;
503+
}
504+
return chatPromise.then((chatResult) => {
505+
const properties: Record<string, string> = {};
506+
if (isBoolean(chatResult) && chatResult) {
507+
properties["cppCodeSnippetsProviderRegistered"] = "true";
508+
telemetry.logCopilotEvent(registerCopilotContextProvider, { ...properties });
509+
return;
510+
} else if (!isBoolean(clientResult) && isString(clientResult.message)) {
511+
properties["error"] = clientResult.message;
512+
} else if (!isBoolean(chatResult) && isString(chatResult.message)) {
513+
properties["error"] = chatResult.message;
514+
} else {
515+
properties["error"] = "Failed to register the Copilot Context Provider for unknown reason.";
516+
}
517+
telemetry.logCopilotEvent(registerCopilotContextProvider, { ...properties });
518+
});
519+
}).catch((e) => {
520+
const properties: Record<string, string> = {};
521+
properties["error"] = `Failed to register the Copilot Context Provider with exception: ${e}`;
485522
telemetry.logCopilotEvent(registerCopilotContextProvider, { ...properties });
486-
}
523+
});
487524
}
488525

489-
private async installContextProvider(copilotAPI: CopilotContextProviderAPI, contextProvider: ContextProvider<SupportedContextItem>): Promise<{ hasGetContextProviderAPI: boolean; hasAPI: boolean }> {
526+
private async installContextProvider(copilotAPI: CopilotContextProviderAPI, contextProvider: ContextProvider<SupportedContextItem>): Promise<vscode.Disposable | undefined> {
490527
const hasGetContextProviderAPI = typeof copilotAPI.getContextProviderAPI === 'function';
491528
if (hasGetContextProviderAPI) {
492529
const contextAPI = await copilotAPI.getContextProviderAPI("v1");
493530
if (contextAPI) {
494-
this.contextProviderDisposables = this.contextProviderDisposables ?? [];
495-
this.contextProviderDisposables.push(contextAPI.registerContextProvider(contextProvider));
531+
return contextAPI.registerContextProvider(contextProvider);
496532
}
497-
return { hasGetContextProviderAPI, hasAPI: contextAPI !== undefined };
533+
return undefined;
498534
} else {
499-
return { hasGetContextProviderAPI: false, hasAPI: false };
535+
return undefined;
500536
}
501537
}
502538
}

Extension/src/LanguageServer/copilotProviders.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,7 @@ export async function getCopilotChatApi(): Promise<CopilotContextProviderAPI | u
159159
let exports: CopilotChatApi | undefined;
160160
if (!copilotExtension.isActive) {
161161
try {
162-
exports = await Promise.race([
163-
copilotExtension.activate(),
164-
new Promise<undefined>(resolve => {
165-
setTimeout(() => {
166-
resolve(undefined);
167-
}, 3000);
168-
})
169-
]);
162+
exports = await copilotExtension.activate();
170163
} catch {
171164
return undefined;
172165
}

0 commit comments

Comments
 (0)