Skip to content

Commit f8cdde6

Browse files
committed
Copilot summary should now only show up when there is already hover content from the main hover provider. Show error message on failure to prevent getting stuck showing the spinner.
1 parent d6a340f commit f8cdde6

File tree

4 files changed

+42
-21
lines changed

4 files changed

+42
-21
lines changed

Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
2626
this.client = client;
2727
}
2828

29-
public async provideHover(document: vscode.TextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise<vscode.Hover | undefined> {
29+
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | undefined> {
3030
await this.client.ready;
3131
const settings: CppSettings = new CppSettings(vscode.workspace.getWorkspaceFolder(document.uri)?.uri);
3232
if (settings.hover === "disabled") {
@@ -35,7 +35,7 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
3535

3636
if (!this.isNewHover(document, position)) {
3737
if (this.ready) {
38-
const contentMarkdown = new vscode.MarkdownString(`$(sparkle) Copilot\n\n${this.content}\n\n_AI-generated content may be incorrect._`, true);
38+
const contentMarkdown = new vscode.MarkdownString(`$(sparkle) Copilot\n\n${this.content}\n\n_${localize("copilot.disclaimer", "AI-generated content may be incorrect.")}_`, true);
3939
return new vscode.Hover(contentMarkdown);
4040
}
4141
if (this.waiting) {
@@ -46,6 +46,14 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
4646

4747
// Fresh hover, reset state.
4848
this.reset();
49+
// Wait for the main hover provider to finish and confirm it has content.
50+
const hoverProvider = this.client.getHoverProvider();
51+
if (!await hoverProvider?.contentReady) {
52+
return undefined;
53+
}
54+
if (token.isCancellationRequested) {
55+
throw new vscode.CancellationError();
56+
}
4957
this.currentDocument = document;
5058
this.currentPosition = position;
5159
const commandString = "$(sparkle) [" + localize("generate.copilot.description", "Generate Copilot summary") + "](command:C_Cpp.ShowCopilotHover)";

Extension/src/LanguageServer/Providers/HoverProvider.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
66
import { Position, ResponseError, TextDocumentPositionParams } from 'vscode-languageclient';
7+
import { ManualSignal } from '../../Utility/Async/manualSignal';
78
import { DefaultClient, HoverRequest } from '../client';
89
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
910
import { CppSettings } from '../settings';
1011

1112
export class HoverProvider implements vscode.HoverProvider {
1213
private client: DefaultClient;
14+
private readonly hasContent = new ManualSignal<boolean>(true);
1315
constructor(client: DefaultClient) {
1416
this.client = client;
1517
}
1618

1719
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | undefined> {
20+
this.hasContent.reset();
1821
const settings: CppSettings = new CppSettings(vscode.workspace.getWorkspaceFolder(document.uri)?.uri);
1922
if (settings.hover === "disabled") {
2023
return undefined;
@@ -52,6 +55,11 @@ export class HoverProvider implements vscode.HoverProvider {
5255
hoverResult.range.end.line, hoverResult.range.end.character);
5356
}
5457

58+
this.hasContent.resolve(strings.length > 0);
5559
return new vscode.Hover(strings, range);
5660
}
61+
62+
get contentReady(): Promise<boolean> {
63+
return this.hasContent;
64+
}
5765
}

Extension/src/LanguageServer/client.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ export class DefaultClient implements Client {
836836
private settingsTracker: SettingsTracker;
837837
private loggingLevel: number = 1;
838838
private configurationProvider?: string;
839+
private hoverProvider: HoverProvider | undefined;
839840
private copilotHoverProvider: CopilotHoverProvider | undefined;
840841

841842
public lastCustomBrowseConfiguration: PersistentFolderState<WorkspaceBrowseConfiguration | undefined> | undefined;
@@ -1270,14 +1271,15 @@ export class DefaultClient implements Client {
12701271
this.registerFileWatcher();
12711272
initializedClientCount = 0;
12721273
this.inlayHintsProvider = new InlayHintsProvider();
1274+
this.hoverProvider = new HoverProvider(this);
12731275

12741276
const settings: CppSettings = new CppSettings();
12751277
if (settings.copilotHover === "enabled" ||
12761278
(settings.copilotHover === "default" && await telemetry.isFlightEnabled("cpp.copilotHover"))) {
12771279
this.copilotHoverProvider = new CopilotHoverProvider(this);
12781280
this.disposables.push(vscode.languages.registerHoverProvider(util.documentSelector, this.copilotHoverProvider));
12791281
}
1280-
this.disposables.push(vscode.languages.registerHoverProvider(util.documentSelector, new HoverProvider(this)));
1282+
this.disposables.push(vscode.languages.registerHoverProvider(util.documentSelector, this.hoverProvider));
12811283
this.disposables.push(vscode.languages.registerInlayHintsProvider(util.documentSelector, this.inlayHintsProvider));
12821284
this.disposables.push(vscode.languages.registerRenameProvider(util.documentSelector, new RenameProvider(this)));
12831285
this.disposables.push(vscode.languages.registerReferenceProvider(util.documentSelector, new FindAllReferencesProvider(this)));
@@ -4033,6 +4035,10 @@ export class DefaultClient implements Client {
40334035
DebugConfigurationProvider.ClearDetectedBuildTasks();
40344036
}
40354037

4038+
public getHoverProvider(): HoverProvider | undefined {
4039+
return this.hoverProvider;
4040+
}
4041+
40364042
public getCopilotHoverProvider(): CopilotHoverProvider | undefined {
40374043
return this.copilotHoverProvider;
40384044
}

Extension/src/LanguageServer/extension.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { modelSelector } from '../constants';
2121
import { getCrashCallStacksChannel } from '../logger';
2222
import { PlatformInformation } from '../platform';
2323
import * as telemetry from '../telemetry';
24+
import { CopilotHoverProvider } from './Providers/CopilotHoverProvider';
2425
import { Client, DefaultClient, DoxygenCodeActionCommandArguments, GetIncludesResult, openFileVersions } from './client';
2526
import { ClientCollection } from './clientCollection';
2627
import { CodeActionDiagnosticInfo, CodeAnalysisDiagnosticIdentifiersAndUri, codeAnalysisAllFixes, codeAnalysisCodeToFixes, codeAnalysisFileToCodeActions } from './codeAnalysis';
@@ -1448,30 +1449,18 @@ async function onCopilotHover(): Promise<void> {
14481449
return;
14491450
}
14501451

1452+
const errorMessage = localize("copilot.hover.error", "An error occurred while generating Copilot summary.");
1453+
14511454
// Prep hover with wait message.
14521455
copilotHoverProvider.showWaiting();
14531456

1454-
// Make sure the hover document has focus.
1455-
await vscode.window.showTextDocument(hoverDocument, { preserveFocus: false, selection: new vscode.Selection(hoverPosition, hoverPosition) });
1456-
1457-
// Workaround to force the editor to update it's content, needs to be called from another location first.
1458-
if (copilotHoverProvider.isCancelled(hoverDocument, hoverPosition)) {
1459-
return;
1460-
}
1461-
await vscode.commands.executeCommand('cursorMove', { to: 'right' });
1462-
await vscode.commands.executeCommand('editor.action.showHover', { focus: 'noAutoFocus' });
1463-
1464-
// Move back and show the correct hover.
1465-
if (copilotHoverProvider.isCancelled(hoverDocument, hoverPosition)) {
1466-
return;
1467-
}
1468-
await vscode.commands.executeCommand('cursorMove', { to: 'left' });
1469-
await vscode.commands.executeCommand('editor.action.showHover', { focus: 'noAutoFocus' });
1457+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition);
14701458

14711459
// Gather the content for the query from the client.
14721460
const requestInfo = await copilotHoverProvider.getRequestInfo(hoverDocument, hoverPosition);
14731461

14741462
if (requestInfo.length === 0) {
1463+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, errorMessage);
14751464
return;
14761465
}
14771466

@@ -1493,6 +1482,7 @@ async function onCopilotHover(): Promise<void> {
14931482
} catch (err) {
14941483
if (err instanceof vscode.LanguageModelError) {
14951484
console.log(err.message, err.code, err.cause);
1485+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, errorMessage);
14961486
} else {
14971487
throw err;
14981488
}
@@ -1501,6 +1491,7 @@ async function onCopilotHover(): Promise<void> {
15011491

15021492
// Ensure we have a valid response from Copilot.
15031493
if (!chatResponse) {
1494+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, errorMessage);
15041495
return;
15051496
}
15061497

@@ -1511,13 +1502,19 @@ async function onCopilotHover(): Promise<void> {
15111502
content += fragment;
15121503
}
15131504
} catch (err) {
1505+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, errorMessage);
15141506
return;
15151507
}
15161508

15171509
if (content.length === 0) {
1510+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, errorMessage);
15181511
return;
15191512
}
15201513

1514+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, content);
1515+
}
1516+
1517+
async function showCopilotContent(copilotHoverProvider: CopilotHoverProvider, hoverDocument: vscode.TextDocument, hoverPosition: vscode.Position, content?: string): Promise<void> {
15211518
// Make sure the hover document has focus.
15221519
await vscode.window.showTextDocument(hoverDocument, { preserveFocus: false, selection: new vscode.Selection(hoverPosition, hoverPosition) });
15231520

@@ -1528,8 +1525,10 @@ async function onCopilotHover(): Promise<void> {
15281525
await vscode.commands.executeCommand('cursorMove', { to: 'right' });
15291526
await vscode.commands.executeCommand('editor.action.showHover', { focus: 'noAutoFocus' });
15301527

1531-
// Prepare and show the real content.
1532-
copilotHoverProvider.showContent(content);
1528+
if (content) {
1529+
copilotHoverProvider.showContent(content);
1530+
}
1531+
15331532
if (copilotHoverProvider.isCancelled(hoverDocument, hoverPosition)) {
15341533
return;
15351534
}

0 commit comments

Comments
 (0)