Skip to content

Commit 871cab2

Browse files
authored
Add "variable references" (microsoft#208478)
Towards microsoft/vscode-copilot-release#926
1 parent 32c524a commit 871cab2

File tree

9 files changed

+104
-65
lines changed

9 files changed

+104
-65
lines changed

src/vs/workbench/api/common/extHostTypeConverters.ts

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,15 +2439,38 @@ export namespace ChatResponseCommandButtonPart {
24392439

24402440
export namespace ChatResponseReferencePart {
24412441
export function to(part: vscode.ChatResponseReferencePart): Dto<IChatContentReference> {
2442+
if ('variableName' in part.value) {
2443+
return {
2444+
kind: 'reference',
2445+
reference: {
2446+
variableName: part.value.variableName,
2447+
value: URI.isUri(part.value.value) ?
2448+
part.value.value :
2449+
Location.from(<vscode.Location>part.value.value)
2450+
}
2451+
};
2452+
}
2453+
24422454
return {
24432455
kind: 'reference',
2444-
reference: !URI.isUri(part.value) ? Location.from(<vscode.Location>part.value) : part.value
2456+
reference: URI.isUri(part.value) ?
2457+
part.value :
2458+
Location.from(<vscode.Location>part.value)
24452459
};
24462460
}
24472461
export function from(part: Dto<IChatContentReference>): vscode.ChatResponseReferencePart {
24482462
const value = revive<IChatContentReference>(part);
2463+
2464+
const mapValue = (value: URI | languages.Location): vscode.Uri | vscode.Location => URI.isUri(value) ?
2465+
value :
2466+
Location.to(value);
2467+
24492468
return new types.ChatResponseReferencePart(
2450-
URI.isUri(value.reference) ? value.reference : Location.to(value.reference)
2469+
'variableName' in value.reference ? {
2470+
variableName: value.reference.variableName,
2471+
value: value.reference.value && mapValue(value.reference.value)
2472+
} :
2473+
mapValue(value.reference)
24512474
);
24522475
}
24532476
}
@@ -2556,36 +2579,6 @@ export namespace ChatResponseProgress {
25562579
}
25572580
}
25582581

2559-
export function to(progress: extHostProtocol.IChatProgressDto): vscode.ChatProgress | undefined {
2560-
switch (progress.kind) {
2561-
case 'markdownContent':
2562-
case 'inlineReference':
2563-
case 'treeData':
2564-
return ChatResponseProgress.to(progress);
2565-
case 'content':
2566-
return { content: progress.content };
2567-
case 'usedContext':
2568-
return { documents: progress.documents.map(d => ({ uri: URI.revive(d.uri), version: d.version, ranges: d.ranges.map(r => Range.to(r)) })) };
2569-
case 'reference':
2570-
return {
2571-
reference:
2572-
isUriComponents(progress.reference) ?
2573-
URI.revive(progress.reference) :
2574-
Location.to(progress.reference)
2575-
};
2576-
case 'agentDetection':
2577-
// For simplicity, don't sent back the 'extended' types
2578-
return undefined;
2579-
case 'progressMessage':
2580-
return { message: progress.content.value };
2581-
case 'vulnerability':
2582-
return { content: progress.content, vulnerabilities: progress.vulnerabilities };
2583-
default:
2584-
// Unknown type, eg something in history that was removed? Ignore
2585-
return undefined;
2586-
}
2587-
}
2588-
25892582
export function toProgressContent(progress: extHostProtocol.IChatContentProgressDto, commandsConverter: Command.ICommandsConverter): vscode.ChatContentProgress | undefined {
25902583
switch (progress.kind) {
25912584
case 'markdownContent':

src/vs/workbench/api/common/extHostTypes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4298,8 +4298,8 @@ export class ChatResponseCommandButtonPart {
42984298
}
42994299

43004300
export class ChatResponseReferencePart {
4301-
value: vscode.Uri | vscode.Location;
4302-
constructor(value: vscode.Uri | vscode.Location) {
4301+
value: vscode.Uri | vscode.Location | { variableName: string; value?: vscode.Uri | vscode.Location };
4302+
constructor(value: vscode.Uri | vscode.Location | { variableName: string; value?: vscode.Uri | vscode.Location }) {
43034303
this.value = value;
43044304
}
43054305
}

src/vs/workbench/contrib/chat/browser/chatListRenderer.ts

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { ResourceMap } from 'vs/base/common/map';
2525
import { FileAccess, Schemas, matchesSomeScheme } from 'vs/base/common/network';
2626
import { clamp } from 'vs/base/common/numbers';
2727
import { basename } from 'vs/base/common/path';
28+
import { basenameOrAuthority, dirname } from 'vs/base/common/resources';
2829
import { equalsIgnoreCase } from 'vs/base/common/strings';
2930
import { ThemeIcon } from 'vs/base/common/themables';
3031
import { URI } from 'vs/base/common/uri';
@@ -41,6 +42,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
4142
import { FileKind, FileType } from 'vs/platform/files/common/files';
4243
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
4344
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
45+
import { ILabelService } from 'vs/platform/label/common/label';
4446
import { WorkbenchCompressibleAsyncDataTree, WorkbenchList } from 'vs/platform/list/browser/listService';
4547
import { ILogService } from 'vs/platform/log/common/log';
4648
import { IOpenerService } from 'vs/platform/opener/common/opener';
@@ -58,6 +60,7 @@ import { CONTEXT_CHAT_RESPONSE_SUPPORT_ISSUE_REPORTING, CONTEXT_REQUEST, CONTEXT
5860
import { IChatProgressRenderableResponseContent } from 'vs/workbench/contrib/chat/common/chatModel';
5961
import { chatAgentLeader, chatSubcommandLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
6062
import { IChatCommandButton, IChatContentReference, IChatFollowup, IChatProgressMessage, IChatResponseProgressFileTreeData, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
63+
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
6164
import { IChatProgressMessageRenderData, IChatRenderData, IChatResponseMarkdownRenderData, IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
6265
import { IWordCountResult, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter';
6366
import { createFileIconThemableTreeContainerScope } from 'vs/workbench/contrib/files/browser/views/explorerView';
@@ -800,17 +803,22 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
800803

801804
listDisposables.add(list.onDidOpen((e) => {
802805
if (e.element) {
803-
this.openerService.open(
804-
'uri' in e.element.reference ? e.element.reference.uri : e.element.reference,
805-
{
806-
fromUserGesture: true,
807-
editorOptions: {
808-
...e.editorOptions,
809-
...{
810-
selection: 'range' in e.element.reference ? e.element.reference.range : undefined
806+
const uriOrLocation = 'variableName' in e.element.reference ? e.element.reference.value : e.element.reference;
807+
const uri = URI.isUri(uriOrLocation) ? uriOrLocation :
808+
uriOrLocation?.uri;
809+
if (uri) {
810+
this.openerService.open(
811+
uri,
812+
{
813+
fromUserGesture: true,
814+
editorOptions: {
815+
...e.editorOptions,
816+
...{
817+
selection: 'range' in e.element.reference ? e.element.reference.range : undefined
818+
}
811819
}
812-
}
813-
});
820+
});
821+
}
814822
}
815823
}));
816824
listDisposables.add(list.onContextMenu((e) => {
@@ -1163,10 +1171,13 @@ class ContentReferencesListPool extends Disposable {
11631171
alwaysConsumeMouseWheel: false,
11641172
accessibilityProvider: {
11651173
getAriaLabel: (element: IChatContentReference) => {
1166-
if (URI.isUri(element.reference)) {
1167-
return basename(element.reference.path);
1174+
const reference = element.reference;
1175+
if ('variableName' in reference) {
1176+
return reference.variableName;
1177+
} else if (URI.isUri(reference)) {
1178+
return basename(reference.path);
11681179
} else {
1169-
return basename(element.reference.uri.path);
1180+
return basename(reference.uri.path);
11701181
}
11711182
},
11721183

@@ -1212,6 +1223,8 @@ class ContentReferencesListRenderer implements IListRenderer<IChatContentReferen
12121223

12131224
constructor(
12141225
private labels: ResourceLabels,
1226+
@ILabelService private readonly labelService: ILabelService,
1227+
@IChatVariablesService private readonly chatVariablesService: IChatVariablesService,
12151228
) { }
12161229

12171230
renderTemplate(container: HTMLElement): IChatContentReferenceListTemplate {
@@ -1220,18 +1233,30 @@ class ContentReferencesListRenderer implements IListRenderer<IChatContentReferen
12201233
return { templateDisposables, label };
12211234
}
12221235

1223-
renderElement(element: IChatContentReference, index: number, templateData: IChatContentReferenceListTemplate, height: number | undefined): void {
1236+
renderElement(data: IChatContentReference, index: number, templateData: IChatContentReferenceListTemplate, height: number | undefined): void {
1237+
const reference = data.reference;
12241238
templateData.label.element.style.display = 'flex';
1225-
const uri = 'uri' in element.reference ? element.reference.uri : element.reference;
1226-
if (matchesSomeScheme(uri, Schemas.mailto, Schemas.http, Schemas.https)) {
1227-
templateData.label.setResource({ resource: uri, name: uri.toString() }, { icon: Codicon.globe });
1239+
if ('variableName' in reference) {
1240+
if (reference.value) {
1241+
const uri = URI.isUri(reference.value) ? reference.value : reference.value.uri;
1242+
const title = this.labelService.getUriLabel(dirname(uri), { relative: true });
1243+
templateData.label.setResource({ resource: uri, name: basenameOrAuthority(uri), description: `#${reference.variableName}` }, { title });
1244+
} else {
1245+
const variable = this.chatVariablesService.getVariable(reference.variableName);
1246+
templateData.label.setLabel(`#${reference.variableName}`, undefined, { title: variable?.description });
1247+
}
12281248
} else {
1229-
templateData.label.setFile(uri, {
1230-
fileKind: FileKind.FILE,
1231-
// Should not have this live-updating data on a historical reference
1232-
fileDecorations: { badges: false, colors: false },
1233-
range: 'range' in element.reference ? element.reference.range : undefined
1234-
});
1249+
const uri = 'uri' in reference ? reference.uri : reference;
1250+
if (matchesSomeScheme(uri, Schemas.mailto, Schemas.http, Schemas.https)) {
1251+
templateData.label.setResource({ resource: uri, name: uri.toString() }, { icon: Codicon.globe });
1252+
} else {
1253+
templateData.label.setFile(uri, {
1254+
fileKind: FileKind.FILE,
1255+
// Should not have this live-updating data on a historical reference
1256+
fileDecorations: { badges: false, colors: false },
1257+
range: 'range' in reference ? reference.range : undefined
1258+
});
1259+
}
12351260
}
12361261
}
12371262

src/vs/workbench/contrib/chat/browser/chatVariables.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ export class ChatVariablesService implements IChatVariablesService {
7373
return this._resolver.has(name.toLowerCase());
7474
}
7575

76+
getVariable(name: string): IChatVariableData | undefined {
77+
return this._resolver.get(name.toLowerCase())?.data;
78+
}
79+
7680
getVariables(): Iterable<Readonly<IChatVariableData>> {
7781
const all = Iterable.map(this._resolver.values(), data => data.data);
7882
return Iterable.filter(all, data => !data.hidden);

src/vs/workbench/contrib/chat/common/chatService.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,13 @@ export function isIUsedContext(obj: unknown): obj is IChatUsedContext {
7474
);
7575
}
7676

77+
export interface IChatContentVariableReference {
78+
variableName: string;
79+
value?: URI | Location;
80+
}
81+
7782
export interface IChatContentReference {
78-
reference: URI | Location;
83+
reference: URI | Location | IChatContentVariableReference;
7984
kind: 'reference';
8085
}
8186

src/vs/workbench/contrib/chat/common/chatVariables.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface IChatVariablesService {
4141
_serviceBrand: undefined;
4242
registerVariable(data: IChatVariableData, resolver: IChatVariableResolver): IDisposable;
4343
hasVariable(name: string): boolean;
44+
getVariable(name: string): IChatVariableData | undefined;
4445
getVariables(): Iterable<Readonly<IChatVariableData>>;
4546
getDynamicVariables(sessionId: string): ReadonlyArray<IDynamicVariable>; // should be its own service?
4647

src/vs/workbench/contrib/chat/common/codeBlockModelCollection.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,22 @@ export class CodeBlockModelCollection extends Disposable {
108108

109109
return {
110110
references: chat.contentReferences.map(ref => {
111-
if (URI.isUri(ref.reference)) {
111+
const uriOrLocation = 'variableName' in ref.reference ?
112+
ref.reference.value :
113+
ref.reference;
114+
if (!uriOrLocation) {
115+
return;
116+
}
117+
118+
if (URI.isUri(uriOrLocation)) {
112119
return {
113-
uri: ref.reference.toJSON()
120+
uri: uriOrLocation.toJSON()
114121
};
115122
}
116123

117124
return {
118-
uri: ref.reference.uri.toJSON(),
119-
range: ref.reference.range,
125+
uri: uriOrLocation.uri.toJSON(),
126+
range: uriOrLocation.range,
120127
};
121128
})
122129
};

src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ export class MockChatVariablesService implements IChatVariablesService {
1515
throw new Error('Method not implemented.');
1616
}
1717

18+
getVariable(name: string): IChatVariableData | undefined {
19+
throw new Error('Method not implemented.');
20+
}
21+
1822
hasVariable(name: string): boolean {
1923
throw new Error('Method not implemented.');
2024
}

src/vscode-dts/vscode.proposed.chatParticipant.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ declare module 'vscode' {
392392
* @param value A uri or location
393393
* @returns This stream.
394394
*/
395-
reference(value: Uri | Location): ChatResponseStream;
395+
reference(value: Uri | Location | { variableName: string; value?: Uri | Location }): ChatResponseStream;
396396

397397
/**
398398
* Pushes a part to this stream.
@@ -430,8 +430,8 @@ declare module 'vscode' {
430430
}
431431

432432
export class ChatResponseReferencePart {
433-
value: Uri | Location;
434-
constructor(value: Uri | Location);
433+
value: Uri | Location | { variableName: string; value?: Uri | Location };
434+
constructor(value: Uri | Location | { variableName: string; value?: Uri | Location });
435435
}
436436

437437
export class ChatResponseCommandButtonPart {

0 commit comments

Comments
 (0)