Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/chatContextPickService.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
6
import { IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
7
import { derived, IObservable, ObservablePromise } from '../../../../base/common/observable.js';
8
import { compare } from '../../../../base/common/strings.js';
9
import { ThemeIcon } from '../../../../base/common/themables.js';
10
import { isObject } from '../../../../base/common/types.js';
11
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
12
import { IQuickPickSeparator } from '../../../../platform/quickinput/common/quickInput.js';
13
import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js';
14
import { IChatWidget } from './chat.js';
15
16
17
export interface IChatContextPickerPickItem {
18
label: string;
19
iconClass?: string;
20
description?: string;
21
detail?: string;
22
disabled?: boolean;
23
asAttachment(): IChatRequestVariableEntry | Promise<IChatRequestVariableEntry>;
24
}
25
26
export function isChatContextPickerPickItem(item: unknown): item is IChatContextPickerPickItem {
27
return isObject(item) && typeof (item as IChatContextPickerPickItem).asAttachment === 'function';
28
}
29
30
interface IChatContextItem {
31
readonly label: string;
32
readonly icon: ThemeIcon;
33
readonly commandId?: string;
34
readonly ordinal?: number;
35
isEnabled?(widget: IChatWidget): Promise<boolean> | boolean;
36
}
37
38
export interface IChatContextValueItem extends IChatContextItem {
39
readonly type: 'valuePick';
40
41
asAttachment(widget: IChatWidget): Promise<IChatRequestVariableEntry | IChatRequestVariableEntry[] | undefined>;
42
}
43
44
export type ChatContextPick = IChatContextPickerPickItem | IQuickPickSeparator;
45
46
export interface IChatContextPicker {
47
readonly placeholder: string;
48
/**
49
* Picks that should either be:
50
* - A promise that resolves to the picked items
51
* - A function that maps input query into items to display.
52
*/
53
readonly picks: Promise<ChatContextPick[]> | ((query: IObservable<string>, token: CancellationToken) => IObservable<{ busy: boolean; picks: ChatContextPick[] }>);
54
55
readonly configure?: {
56
label: string;
57
commandId: string;
58
};
59
}
60
61
export interface IChatContextPickerItem extends IChatContextItem {
62
readonly type: 'pickerPick';
63
64
asPicker(widget: IChatWidget): IChatContextPicker;
65
}
66
67
/**
68
* Helper for use in {@IChatContextPickerItem} that wraps a simple query->promise
69
* function into the requisite observable.
70
*/
71
export function picksWithPromiseFn(fn: (query: string, token: CancellationToken) => Promise<ChatContextPick[]>): (query: IObservable<string>, token: CancellationToken) => IObservable<{ busy: boolean; picks: ChatContextPick[] }> {
72
return (query, token) => {
73
const promise = derived(reader => {
74
const queryValue = query.read(reader);
75
const cts = new CancellationTokenSource(token);
76
reader.store.add(toDisposable(() => cts.dispose(true)));
77
return new ObservablePromise(fn(queryValue, cts.token));
78
});
79
80
return promise.map((value, reader) => {
81
const result = value.promiseResult.read(reader);
82
return { picks: result?.data || [], busy: result === undefined };
83
});
84
};
85
}
86
87
export interface IChatContextPickService {
88
_serviceBrand: undefined;
89
90
items: Iterable<IChatContextValueItem | IChatContextPickerItem>;
91
92
/**
93
* Register a value or picker to the "Add Context" flow. A value directly resolved to a
94
* chat attachment and a picker first shows a list of items to pick from and then
95
* resolves the selected item to a chat attachment.
96
*/
97
registerChatContextItem(item: IChatContextValueItem | IChatContextPickerItem): IDisposable;
98
}
99
100
export const IChatContextPickService = createDecorator<IChatContextPickService>('IContextPickService');
101
102
export class ChatContextPickService implements IChatContextPickService {
103
104
declare _serviceBrand: undefined;
105
106
private readonly _picks: IChatContextValueItem[] = [];
107
108
readonly items: Iterable<IChatContextValueItem> = this._picks;
109
110
registerChatContextItem(pick: IChatContextValueItem): IDisposable {
111
this._picks.push(pick);
112
113
this._picks.sort((a, b) => {
114
const valueA = a.ordinal ?? 0;
115
const valueB = b.ordinal ?? 0;
116
if (valueA === valueB) {
117
return compare(a.label, b.label);
118
} else if (valueA < valueB) {
119
return 1;
120
} else {
121
return -1;
122
}
123
});
124
125
return toDisposable(() => {
126
const index = this._picks.indexOf(pick);
127
if (index >= 0) {
128
this._picks.splice(index, 1);
129
}
130
});
131
}
132
}
133
134