Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/util/common/test/shims/editing.ts
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
7
import { coalesceInPlace } from '../../../vs/base/common/arrays';
8
import { ResourceMap } from '../../../vs/base/common/map';
9
import { URI as Uri } from '../../../vs/base/common/uri';
10
import { Position } from '../../../vs/workbench/api/common/extHostTypes/position';
11
import { Range } from '../../../vs/workbench/api/common/extHostTypes/range';
12
import { SnippetString } from '../../../vs/workbench/api/common/extHostTypes/snippetString';
13
import { SnippetTextEdit } from '../../../vs/workbench/api/common/extHostTypes/snippetTextEdit';
14
import { TextEdit } from '../../../vs/workbench/api/common/extHostTypes/textEdit';
15
16
export interface WorkspaceEditEntryMetadata {
17
needsConfirmation: boolean;
18
label: string;
19
description?: string;
20
// iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon;
21
}
22
23
export interface IFileOperationOptions {
24
readonly overwrite?: boolean;
25
readonly ignoreIfExists?: boolean;
26
readonly ignoreIfNotExists?: boolean;
27
readonly recursive?: boolean;
28
readonly contents?: Uint8Array;
29
}
30
31
export const enum FileEditType {
32
File = 1,
33
Text = 2,
34
Cell = 3,
35
CellReplace = 5,
36
Snippet = 6,
37
}
38
39
export interface IFileOperation {
40
readonly _type: FileEditType.File;
41
readonly from?: Uri;
42
readonly to?: Uri;
43
readonly options?: IFileOperationOptions;
44
readonly metadata?: WorkspaceEditEntryMetadata;
45
}
46
47
export interface IFileTextEdit {
48
readonly _type: FileEditType.Text;
49
readonly uri: Uri;
50
readonly edit: TextEdit;
51
readonly metadata?: WorkspaceEditEntryMetadata;
52
}
53
54
export interface IFileSnippetTextEdit {
55
readonly _type: FileEditType.Snippet;
56
readonly uri: Uri;
57
readonly range: Range;
58
readonly edit: SnippetString;
59
readonly metadata?: WorkspaceEditEntryMetadata;
60
}
61
62
type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileSnippetTextEdit;
63
64
export class WorkspaceEdit {
65
private readonly _edits: WorkspaceEditEntry[] = [];
66
67
_allEntries(): ReadonlyArray<WorkspaceEditEntry> {
68
return this._edits;
69
}
70
71
// --- file
72
73
renameFile(
74
from: Uri,
75
to: Uri,
76
options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean },
77
metadata?: WorkspaceEditEntryMetadata
78
): void {
79
this._edits.push({ _type: FileEditType.File, from, to, options, metadata });
80
}
81
82
createFile(
83
uri: Uri,
84
options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean; readonly contents?: Uint8Array },
85
metadata?: WorkspaceEditEntryMetadata
86
): void {
87
this._edits.push({ _type: FileEditType.File, from: undefined, to: uri, options, metadata });
88
}
89
90
deleteFile(
91
uri: Uri,
92
options?: { readonly recursive?: boolean; readonly ignoreIfNotExists?: boolean },
93
metadata?: WorkspaceEditEntryMetadata
94
): void {
95
this._edits.push({ _type: FileEditType.File, from: uri, to: undefined, options, metadata });
96
}
97
98
// --- text
99
100
replace(uri: Uri, range: Range, newText: string, metadata?: WorkspaceEditEntryMetadata): void {
101
this._edits.push({ _type: FileEditType.Text, uri, edit: new TextEdit(range, newText), metadata });
102
}
103
104
insert(resource: Uri, position: Position, newText: string, metadata?: WorkspaceEditEntryMetadata): void {
105
this.replace(resource, new Range(position, position), newText, metadata);
106
}
107
108
delete(resource: Uri, range: Range, metadata?: WorkspaceEditEntryMetadata): void {
109
this.replace(resource, range, '', metadata);
110
}
111
112
// --- text (Maplike)
113
114
has(uri: Uri): boolean {
115
return this._edits.some(edit => edit._type === FileEditType.Text && edit.uri.toString() === uri.toString());
116
}
117
118
set(uri: Uri, edits: ReadonlyArray<TextEdit | SnippetTextEdit>): void;
119
set(uri: Uri, edits: ReadonlyArray<[TextEdit | SnippetTextEdit, WorkspaceEditEntryMetadata]>): void;
120
121
set(
122
uri: Uri,
123
edits:
124
| null
125
| undefined
126
| ReadonlyArray<TextEdit | SnippetTextEdit | [TextEdit | SnippetTextEdit, WorkspaceEditEntryMetadata]>
127
): void {
128
if (!edits) {
129
// remove all text, snippet, or notebook edits for `uri`
130
for (let i = 0; i < this._edits.length; i++) {
131
const element = this._edits[i];
132
switch (element._type) {
133
case FileEditType.Text:
134
case FileEditType.Snippet:
135
if (element.uri.toString() === uri.toString()) {
136
this._edits[i] = undefined!; // will be coalesced down below
137
}
138
break;
139
}
140
}
141
coalesceInPlace(this._edits);
142
} else {
143
// append edit to the end
144
for (const editOrTuple of edits) {
145
if (!editOrTuple) {
146
continue;
147
}
148
let edit: TextEdit | SnippetTextEdit;
149
let metadata: WorkspaceEditEntryMetadata | undefined;
150
if (Array.isArray(editOrTuple)) {
151
edit = editOrTuple[0];
152
metadata = editOrTuple[1];
153
} else {
154
edit = editOrTuple;
155
}
156
if (SnippetTextEdit.isSnippetTextEdit(edit)) {
157
this._edits.push({
158
_type: FileEditType.Snippet,
159
uri,
160
range: edit.range,
161
edit: edit.snippet,
162
metadata,
163
});
164
} else {
165
this._edits.push({ _type: FileEditType.Text, uri, edit, metadata });
166
}
167
}
168
}
169
}
170
171
get(uri: Uri): TextEdit[] {
172
const res: TextEdit[] = [];
173
for (const candidate of this._edits) {
174
if (candidate._type === FileEditType.Text && candidate.uri.toString() === uri.toString()) {
175
res.push(candidate.edit);
176
}
177
}
178
return res;
179
}
180
181
entries(): [Uri, TextEdit[]][] {
182
const textEdits = new ResourceMap<[Uri, TextEdit[]]>();
183
for (const candidate of this._edits) {
184
if (candidate._type === FileEditType.Text) {
185
let textEdit = textEdits.get(candidate.uri);
186
if (!textEdit) {
187
textEdit = [candidate.uri, []];
188
textEdits.set(candidate.uri, textEdit);
189
}
190
textEdit[1].push(candidate.edit);
191
}
192
}
193
return [...textEdits.values()];
194
}
195
196
get size(): number {
197
return this.entries().length;
198
}
199
200
toJSON(): any {
201
return this.entries();
202
}
203
}
204
205
206
/**
207
* Represents sources that can cause {@link window.onDidChangeTextEditorSelection selection change events}.
208
*/
209
export enum TextEditorSelectionChangeKind {
210
/**
211
* Selection changed due to typing in the editor.
212
*/
213
Keyboard = 1,
214
/**
215
* Selection change due to clicking in the editor.
216
*/
217
Mouse = 2,
218
/**
219
* Selection changed because a command ran.
220
*/
221
Command = 3
222
}
223
224
/**
225
* Reasons for why a text document has changed.
226
*/
227
export enum TextDocumentChangeReason {
228
/** The text change is caused by an undo operation. */
229
Undo = 1,
230
231
/** The text change is caused by an redo operation. */
232
Redo = 2,
233
}
234