Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/prompts/node/panel/currentSelection.tsx
13405 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
6
import { AssistantMessage, BasePromptElementProps, PromptElement, PromptPiece, PromptSizing, UserMessage } from '@vscode/prompt-tsx';
7
import type { Range } from 'vscode';
8
import { TextDocumentSnapshot } from '../../../../platform/editing/common/textDocumentSnapshot';
9
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
10
import { ILogService } from '../../../../platform/log/common/logService';
11
import { ITabsAndEditorsService } from '../../../../platform/tabs/common/tabsAndEditorsService';
12
import * as path from '../../../../util/vs/base/common/path';
13
import { Location } from '../../../../vscodeTypes';
14
import { PromptReference } from '../../../prompt/common/conversation';
15
import { CurrentEditor } from './currentEditor';
16
import { CodeBlock } from './safeElements';
17
18
interface CurrentSelectionProps extends BasePromptElementProps {
19
document?: TextDocumentSnapshot;
20
range?: Range;
21
includeFilepath?: boolean;
22
}
23
24
interface CurrentSelectionState {
25
exceedsTokenBudget: boolean;
26
isIgnored: boolean;
27
}
28
29
export class CurrentSelection extends PromptElement<CurrentSelectionProps, CurrentSelectionState> {
30
31
constructor(
32
props: CurrentSelectionProps,
33
@IIgnoreService private readonly ignoreService: IIgnoreService,
34
@ILogService private readonly logger: ILogService,
35
@ITabsAndEditorsService private readonly _tabsAndEditorsService: ITabsAndEditorsService,
36
) {
37
super(props);
38
}
39
40
override async prepare(sizing: PromptSizing): Promise<CurrentSelectionState> {
41
if (!this.props.document) {
42
return { isIgnored: false, exceedsTokenBudget: false };
43
}
44
const isIgnored = await this.ignoreService.isCopilotIgnored(this.props.document.uri);
45
46
let exceedsTokenBudget = false;
47
const selection = CurrentSelection.getCurrentSelection(this._tabsAndEditorsService);
48
if (selection && (await sizing.countTokens(selection?.selectedText)) * 1.1 > sizing.tokenBudget) {
49
exceedsTokenBudget = true;
50
}
51
52
return { isIgnored, exceedsTokenBudget };
53
}
54
55
override render(state: CurrentSelectionState, sizing: PromptSizing): PromptPiece<any, any> | undefined {
56
const selection = CurrentSelection.getCurrentSelection(this._tabsAndEditorsService);
57
if (!selection) {
58
return <CurrentEditor />;
59
}
60
61
const references = [new PromptReference(new Location(selection.activeDocument.uri, selection.range))];
62
const urisUsed = [selection.activeDocument.uri];
63
64
if (state.isIgnored) {
65
return <ignoredFiles value={urisUsed} />;
66
}
67
if (state.exceedsTokenBudget) {
68
this.logger.info(`Dropped current selection (${sizing.tokenBudget} / ${sizing.endpoint.modelMaxPromptTokens} tokens)`);
69
return (<>
70
<AssistantMessage priority={this.props.priority} name='selection-too-large'>
71
Your active selection ({selection.fileName && <>{selection.selectedText.split('\n').length} lines from {path.basename(selection.fileName)}</>}) exceeded my maximum context size and was dropped. Please reduce the selection to the most relevant part.
72
</AssistantMessage>
73
</>);
74
}
75
76
return (<>
77
<UserMessage priority={this.props.priority}>
78
Active selection:<br />
79
<br />
80
<br />
81
{selection.fileName && <>From the file: {path.basename(selection.fileName)}<br /></>}
82
<CodeBlock code={selection.selectedText} languageId={selection.languageId} uri={selection.activeDocument.uri} references={references} />
83
<br />
84
<br />
85
</UserMessage >
86
</>);
87
}
88
89
static getCurrentSelection(tabsAndEditorsService: ITabsAndEditorsService, allowEmptySelection = false) {
90
const editor = tabsAndEditorsService.activeTextEditor;
91
const activeDocument = editor?.document;
92
if (activeDocument) {
93
const activeDocumentSelection = editor.selection;
94
if (activeDocumentSelection && (!activeDocumentSelection.isEmpty
95
|| activeDocumentSelection.isEmpty && allowEmptySelection)) {
96
const languageId = activeDocument.languageId;
97
const selectedText = activeDocument.getText(activeDocumentSelection);
98
return {
99
languageId,
100
selectedText,
101
activeDocument,
102
range: activeDocumentSelection,
103
fileName: activeDocument.fileName
104
};
105
}
106
}
107
}
108
}
109
110