Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/prompts/node/panel/currentEditor.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 { BasePromptElementProps, PromptElement, PromptSizing, UserMessage } from '@vscode/prompt-tsx';
7
import type { NotebookEditor, TextEditor } from 'vscode';
8
import { NotebookDocumentSnapshot } from '../../../../platform/editing/common/notebookDocumentSnapshot';
9
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
10
import { IAlternativeNotebookContentService } from '../../../../platform/notebook/common/alternativeContent';
11
import { ITabsAndEditorsService } from '../../../../platform/tabs/common/tabsAndEditorsService';
12
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
13
import { findCell, findNotebook } from '../../../../util/common/notebooks';
14
import { Schemas } from '../../../../util/vs/base/common/network';
15
import * as path from '../../../../util/vs/base/common/path';
16
import { Position, Range } from '../../../../vscodeTypes';
17
import { PromptReference } from '../../../prompt/common/conversation';
18
import { IPromptEndpoint } from '../base/promptRenderer';
19
import { CodeBlock } from './safeElements';
20
21
export interface CurrentEditorPromptProps extends BasePromptElementProps {
22
}
23
24
export class CurrentEditor extends PromptElement<CurrentEditorPromptProps> {
25
constructor(
26
props: CurrentEditorPromptProps,
27
@IIgnoreService private readonly _ignoreService: IIgnoreService,
28
@ITabsAndEditorsService private readonly _tabsAndEditorsService: ITabsAndEditorsService,
29
@IAlternativeNotebookContentService private readonly _alternativeNotebookContentService: IAlternativeNotebookContentService,
30
@IWorkspaceService private readonly _workspaceService: IWorkspaceService,
31
@IPromptEndpoint private readonly _promptEndpoint: IPromptEndpoint,
32
) {
33
super(props);
34
}
35
36
async render(state: void, sizing: PromptSizing) {
37
const editor = this._tabsAndEditorsService.activeTextEditor;
38
if (editor) {
39
// TODO@DonJayamanne, need to figure out places relying on this and how its used.
40
// E.g. if problems were using this, then we need to translate positions in problems as well, & the like.
41
// return editor.document.uri.scheme === Schemas.vscodeNotebookCell ?
42
// this.renderActiveNotebookCellEditor(editor) :
43
// this.renderActiveTextEditor(editor);
44
return this.renderActiveTextEditor(editor);
45
}
46
47
const notebookEditor = this._tabsAndEditorsService.activeNotebookEditor;
48
if (notebookEditor) {
49
return this.renderActiveNotebookEditor(notebookEditor);
50
}
51
return undefined;
52
}
53
54
async renderActiveTextEditor(editor: TextEditor) {
55
const ranges = editor.visibleRanges;
56
const document = editor.document;
57
58
const isIgnored = await this._ignoreService.isCopilotIgnored(document.uri);
59
if (isIgnored) {
60
return <ignoredFiles value={[document.uri]} />;
61
}
62
63
if (document.getText().trim().length === 0) {
64
// The document is empty or contains only whitespace
65
return (<>
66
<UserMessage priority={this.props.priority}>
67
<references value={[new PromptReference(document.uri)]} />
68
The active {document.languageId} file {path.basename(document.uri.path)} is empty.
69
</UserMessage >
70
</>);
71
}
72
73
if (ranges.length === 0) {
74
return undefined;
75
}
76
77
return (<>
78
<UserMessage priority={this.props.priority}>
79
{ranges.map(range => (
80
<>
81
Excerpt from active file {path.basename(document.uri.path)}, lines {range.start.line + 1} to {range.end.line + 1}:<br />
82
<CodeBlock code={document.getText(range)} languageId={document.languageId} uri={document.uri} references={[new PromptReference({ uri: document.uri, range })]} />
83
<br />
84
<br />
85
</>
86
))}
87
</UserMessage >
88
</>);
89
}
90
91
async renderActiveNotebookCellEditor(editor: TextEditor) {
92
if (editor.document.uri.scheme !== Schemas.vscodeNotebookCell) {
93
return;
94
}
95
const notebook = findNotebook(editor.document.uri, this._workspaceService.notebookDocuments);
96
const cellIndex = notebook && findCell(editor.document.uri, notebook)?.index;
97
if (!notebook || typeof cellIndex === 'undefined' || cellIndex < 0) {
98
return;
99
}
100
const format = this._alternativeNotebookContentService.getFormat(this._promptEndpoint);
101
const document = NotebookDocumentSnapshot.create(notebook, format);
102
const isIgnored = await this._ignoreService.isCopilotIgnored(document.uri);
103
if (isIgnored) {
104
return <ignoredFiles value={[document.uri]} />;
105
}
106
107
if (document.getText().trim().length === 0) {
108
// The document is empty or contains only whitespace
109
return (<>
110
<UserMessage priority={this.props.priority}>
111
<references value={[new PromptReference(document.uri)]} />
112
The active {document.languageId} file {path.basename(document.uri.path)} is empty.
113
</UserMessage >
114
</>);
115
}
116
117
if (editor.visibleRanges.length === 0) {
118
return undefined;
119
}
120
const altDocument = this._alternativeNotebookContentService.create(format).getAlternativeDocument(notebook);
121
const cell = notebook.cellAt(cellIndex);
122
const ranges = editor.visibleRanges.map(range => {
123
const start = altDocument.fromCellPosition(cell, range.start);
124
const end = altDocument.fromCellPosition(cell, range.end);
125
return new Range(start, end);
126
});
127
128
return (<>
129
<UserMessage priority={this.props.priority}>
130
{ranges.map(range => (
131
<>
132
Excerpt from active file {path.basename(document.uri.path)}, lines {range.start.line + 1} to {range.end.line + 1}:<br />
133
<CodeBlock code={document.getText(range)} languageId={document.languageId} uri={document.uri} references={[new PromptReference({ uri: document.uri, range })]} />
134
<br />
135
<br />
136
</>
137
))}
138
</UserMessage >
139
</>);
140
}
141
142
async renderActiveNotebookEditor(editor: NotebookEditor) {
143
const notebookRanges = editor.visibleRanges;
144
const format = this._alternativeNotebookContentService.getFormat(this._promptEndpoint);
145
const document = NotebookDocumentSnapshot.create(editor.notebook, format);
146
const isIgnored = await this._ignoreService.isCopilotIgnored(document.uri);
147
if (isIgnored) {
148
return <ignoredFiles value={[document.uri]} />;
149
}
150
151
if (document.getText().trim().length === 0) {
152
// The document is empty or contains only whitespace
153
return (<>
154
<UserMessage priority={this.props.priority}>
155
<references value={[new PromptReference(document.uri)]} />
156
The active {document.languageId} file {path.basename(document.uri.path)} is empty.
157
</UserMessage >
158
</>);
159
}
160
161
if (notebookRanges.length === 0) {
162
return undefined;
163
}
164
const altDocument = this._alternativeNotebookContentService.create(format).getAlternativeDocument(editor.notebook);
165
const ranges = notebookRanges.map(range => {
166
const cell = editor.notebook.cellAt(range.start);
167
const lastLine = cell.document.lineAt(cell.document.lineCount - 1);
168
const start = altDocument.fromCellPosition(cell, new Position(0, 0));
169
const end = altDocument.fromCellPosition(cell, lastLine.range.end);
170
return new Range(start, end);
171
});
172
173
return (<>
174
<UserMessage priority={this.props.priority}>
175
{ranges.map(range => (
176
<>
177
Excerpt from active file {path.basename(document.uri.path)}, lines {range.start.line + 1} to {range.end.line + 1}:<br />
178
<CodeBlock code={document.getText(range)} languageId={document.languageId} uri={document.uri} references={[new PromptReference({ uri: document.uri, range })]} />
179
<br />
180
<br />
181
</>
182
))}
183
</UserMessage >
184
</>);
185
}
186
}
187
188