Skip to content

Commit 5d32121

Browse files
authored
Support Content Exclusion for Copilot Hover (#13143)
* Use propsed content exclusion APIs
1 parent 9e96d63 commit 5d32121

File tree

6 files changed

+55
-17
lines changed

6 files changed

+55
-17
lines changed

Diff for: Extension/.scripts/common.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const Git = async (...args: Parameters<Awaited<CommandFunction>>) => (awa
4848
export const GitClean = async (...args: Parameters<Awaited<CommandFunction>>) => (await new Command(await git, 'clean'))(...args);
4949

5050
export async function getModifiedIgnoredFiles() {
51-
const {code, error, stdio } = await GitClean('-Xd', '-n');
51+
const { code, error, stdio } = await GitClean('-Xd', '-n');
5252
if (code) {
5353
throw new Error(`\n${error.all().join('\n')}`);
5454
}
@@ -65,11 +65,11 @@ export async function rimraf(...paths: string[]) {
6565
}
6666
if (await filepath.isFolder(each)) {
6767
verbose(`Removing folder ${red(each)}`);
68-
all.push(rm(each, {recursive: true, force: true}));
68+
all.push(rm(each, { recursive: true, force: true }));
6969
continue;
7070
}
7171
verbose(`Removing file ${red(each)}`);
72-
all.push(rm(each, {force: true}));
72+
all.push(rm(each, { force: true }));
7373
}
7474
await Promise.all(all);
7575
}
@@ -345,3 +345,15 @@ export async function checkBinaries() {
345345
}
346346
return failing;
347347
}
348+
349+
export async function checkProposals() {
350+
let failing = false;
351+
352+
await rm(`${$root}/vscode.proposed.chatParticipantAdditions.d.ts`);
353+
failing = await assertAnyFile('vscode.proposed.chatParticipantAdditions.d.ts') && (quiet || warn(`The VSCode import file '${$root}/vscode.proposed.chatParticipantAdditions.d.ts' should not be present.`)) || failing;
354+
355+
if (!failing) {
356+
verbose('VSCode proposals appear to be in place.');
357+
}
358+
return failing;
359+
}

Diff for: Extension/.scripts/verify.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55

6-
import { checkBinaries, checkCompiled, checkDTS, checkPrep, error, green } from './common';
6+
import { checkBinaries, checkCompiled, checkDTS, checkPrep, checkProposals, error, green } from './common';
77
const quiet = process.argv.includes('--quiet');
88

99
export async function main() {
@@ -50,3 +50,12 @@ export async function dts() {
5050
process.exit(1);
5151
}
5252
}
53+
54+
export async function proposals() {
55+
let failing = false;
56+
failing = (await checkProposals() && (quiet || error(`Issue with VSCode proposals. Run ${green('yarn prep')} to fix it.`))) || failing;
57+
58+
if (failing) {
59+
process.exit(1);
60+
}
61+
}

Diff for: Extension/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"Snippets"
3939
],
4040
"enabledApiProposals": [
41-
"terminalDataWriteEvent"
41+
"terminalDataWriteEvent",
42+
"chatParticipantAdditions"
4243
],
4344
"capabilities": {
4445
"untrustedWorkspaces": {
@@ -6537,7 +6538,7 @@
65376538
"translations-generate": "set NODE_OPTIONS=--no-experimental-fetch && gulp translations-generate",
65386539
"translations-import": "gulp translations-import",
65396540
"import-edge-strings": "ts-node -T ./.scripts/import_edge_strings.ts",
6540-
"prep:dts": "yarn verify dts --quiet || (npx @vscode/dts dev && npx @vscode/dts main)",
6541+
"prep:dts": "yarn verify dts --quiet || (npx @vscode/dts main && npx @vscode/dts dev && yarn verify proposals)",
65416542
"build": "yarn prep:dts && echo [Building TypeScript code] && tsc --build tsconfig.json"
65426543
},
65436544
"devDependencies": {

Diff for: Extension/src/LanguageServer/Providers/CopilotHoverProvider.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import * as vscode from 'vscode';
66
import { Position, ResponseError } from 'vscode-languageclient';
77
import * as nls from 'vscode-nls';
8-
import { DefaultClient, GetCopilotHoverInfoParams, GetCopilotHoverInfoRequest } from '../client';
8+
import { DefaultClient, GetCopilotHoverInfoParams, GetCopilotHoverInfoRequest, GetCopilotHoverInfoResult } from '../client';
99
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
1010
import { CppSettings } from '../settings';
1111

@@ -92,8 +92,8 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
9292
return this.currentCancellationToken;
9393
}
9494

95-
public async getRequestInfo(document: vscode.TextDocument, position: vscode.Position): Promise<string> {
96-
let requestInfo = "";
95+
public async getRequestInfo(document: vscode.TextDocument, position: vscode.Position): Promise<GetCopilotHoverInfoResult> {
96+
let response: GetCopilotHoverInfoResult;
9797
const params: GetCopilotHoverInfoParams = {
9898
textDocument: { uri: document.uri.toString() },
9999
position: Position.create(position.line, position.character)
@@ -105,16 +105,15 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
105105
}
106106

107107
try {
108-
const response = await this.client.languageClient.sendRequest(GetCopilotHoverInfoRequest, params, this.currentCancellationToken);
109-
requestInfo = response.content;
108+
response = await this.client.languageClient.sendRequest(GetCopilotHoverInfoRequest, params, this.currentCancellationToken);
110109
} catch (e: any) {
111110
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
112111
throw new vscode.CancellationError();
113112
}
114113
throw e;
115114
}
116115

117-
return requestInfo;
116+
return response;
118117
}
119118

120119
public isCancelled(document: vscode.TextDocument, position: vscode.Position): boolean {

Diff for: Extension/src/LanguageServer/client.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,9 @@ export interface GetCopilotHoverInfoParams {
540540
position: Position;
541541
}
542542

543-
interface GetCopilotHoverInfoResult {
543+
export interface GetCopilotHoverInfoResult {
544544
content: string;
545+
files: string[];
545546
}
546547

547548
export interface ChatContextResult {

Diff for: Extension/src/LanguageServer/extension.ts

+20-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import * as StreamZip from 'node-stream-zip';
1111
import * as os from 'os';
1212
import * as path from 'path';
1313
import * as vscode from 'vscode';
14-
import { Range } from 'vscode-languageclient';
14+
import { CancellationToken, Range } from 'vscode-languageclient';
1515
import * as nls from 'vscode-nls';
1616
import { TargetPopulation } from 'vscode-tas-client';
1717
import * as which from 'which';
@@ -1430,18 +1430,34 @@ async function onCopilotHover(): Promise<void> {
14301430

14311431
// Gather the content for the query from the client.
14321432
const requestInfo = await copilotHoverProvider.getRequestInfo(hoverDocument, hoverPosition);
1433-
if (requestInfo.length === 0) {
1433+
try {
1434+
for (const file of requestInfo.files) {
1435+
const fileUri = vscode.Uri.file(file);
1436+
if (await vscodelm.fileIsIgnored(fileUri, copilotHoverProvider.getCurrentHoverCancellationToken() ?? CancellationToken.None)) {
1437+
telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available due to content exclusion." });
1438+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available.") + "\n\n" +
1439+
localize("copilot.hover.excluded", "The file containing this symbol's definition or declaration has been excluded from use with Copilot."));
1440+
return;
1441+
}
1442+
}
1443+
} catch (err) {
1444+
if (err instanceof Error) {
1445+
await reportCopilotFailure(copilotHoverProvider, hoverDocument, hoverPosition, err.name);
1446+
}
1447+
return;
1448+
}
1449+
if (requestInfo.content.length === 0) {
14341450
// Context is not available for this symbol.
14351451
telemetry.logLanguageServerEvent("CopilotHover", { "Message": "Copilot summary is not available for this symbol." });
1436-
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable", "Copilot summary is not available for this symbol."));
1452+
await showCopilotContent(copilotHoverProvider, hoverDocument, hoverPosition, localize("copilot.hover.unavailable.symbol", "Copilot summary is not available for this symbol."));
14371453
return;
14381454
}
14391455

14401456
const locale = getLocaleId();
14411457

14421458
const messages = [
14431459
vscode.LanguageModelChatMessage
1444-
.User(requestInfo + locale)];
1460+
.User(requestInfo.content + locale)];
14451461

14461462
const [model] = await vscodelm.selectChatModels(modelSelector);
14471463

0 commit comments

Comments
 (0)