Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/simulation/fixtures/multiFileEdit/fsprovider/src/fileSystemProvider.ts
13406 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 * as path from 'path';
8
import * as vscode from 'vscode';
9
10
export class File implements vscode.FileStat {
11
12
type: vscode.FileType;
13
ctime: number;
14
mtime: number;
15
size: number;
16
17
name: string;
18
data?: Uint8Array;
19
20
constructor(name: string) {
21
this.type = vscode.FileType.File;
22
this.ctime = Date.now();
23
this.mtime = Date.now();
24
this.size = 0;
25
this.name = name;
26
}
27
}
28
29
export class Directory implements vscode.FileStat {
30
31
type: vscode.FileType;
32
ctime: number;
33
mtime: number;
34
size: number;
35
36
name: string;
37
entries: Map<string, File | Directory>;
38
39
constructor(name: string) {
40
this.type = vscode.FileType.Directory;
41
this.ctime = Date.now();
42
this.mtime = Date.now();
43
this.size = 0;
44
this.name = name;
45
this.entries = new Map();
46
}
47
}
48
49
export type Entry = File | Directory;
50
51
export class MemFS implements vscode.FileSystemProvider {
52
53
root = new Directory('');
54
55
// --- manage file metadata
56
57
stat(uri: vscode.Uri): vscode.FileStat {
58
return this._lookup(uri, false);
59
}
60
61
readDirectory(uri: vscode.Uri): [string, vscode.FileType][] {
62
const entry = this._lookupAsDirectory(uri, false);
63
const result: [string, vscode.FileType][] = [];
64
for (const [name, child] of entry.entries) {
65
result.push([name, child.type]);
66
}
67
return result;
68
}
69
70
// --- manage file contents
71
72
readFile(uri: vscode.Uri): Uint8Array {
73
const data = this._lookupAsFile(uri, false).data;
74
if (data) {
75
return data;
76
}
77
throw vscode.FileSystemError.FileNotFound();
78
}
79
80
writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void {
81
const basename = path.posix.basename(uri.path);
82
const parent = this._lookupParentDirectory(uri);
83
let entry = parent.entries.get(basename);
84
if (entry instanceof Directory) {
85
throw vscode.FileSystemError.FileIsADirectory(uri);
86
}
87
if (!entry && !options.create) {
88
throw vscode.FileSystemError.FileNotFound(uri);
89
}
90
if (entry && options.create && !options.overwrite) {
91
throw vscode.FileSystemError.FileExists(uri);
92
}
93
if (!entry) {
94
entry = new File(basename);
95
parent.entries.set(basename, entry);
96
this._fireSoon({ type: vscode.FileChangeType.Created, uri });
97
}
98
entry.mtime = Date.now();
99
entry.size = content.byteLength;
100
entry.data = content;
101
102
this._fireSoon({ type: vscode.FileChangeType.Changed, uri });
103
}
104
105
// --- manage files/folders
106
107
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): void {
108
109
if (!options.overwrite && this._lookup(newUri, true)) {
110
throw vscode.FileSystemError.FileExists(newUri);
111
}
112
113
const entry = this._lookup(oldUri, false);
114
const oldParent = this._lookupParentDirectory(oldUri);
115
116
const newParent = this._lookupParentDirectory(newUri);
117
const newName = path.posix.basename(newUri.path);
118
119
oldParent.entries.delete(entry.name);
120
entry.name = newName;
121
newParent.entries.set(newName, entry);
122
123
this._fireSoon(
124
{ type: vscode.FileChangeType.Deleted, uri: oldUri },
125
{ type: vscode.FileChangeType.Created, uri: newUri }
126
);
127
}
128
129
delete(uri: vscode.Uri): void {
130
const dirname = uri.with({ path: path.posix.dirname(uri.path) });
131
const basename = path.posix.basename(uri.path);
132
const parent = this._lookupAsDirectory(dirname, false);
133
if (!parent.entries.has(basename)) {
134
throw vscode.FileSystemError.FileNotFound(uri);
135
}
136
parent.entries.delete(basename);
137
parent.mtime = Date.now();
138
parent.size -= 1;
139
this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { uri, type: vscode.FileChangeType.Deleted });
140
}
141
142
createDirectory(uri: vscode.Uri): void {
143
const basename = path.posix.basename(uri.path);
144
const dirname = uri.with({ path: path.posix.dirname(uri.path) });
145
const parent = this._lookupAsDirectory(dirname, false);
146
147
const entry = new Directory(basename);
148
parent.entries.set(entry.name, entry);
149
parent.mtime = Date.now();
150
parent.size += 1;
151
this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { type: vscode.FileChangeType.Created, uri });
152
}
153
154
// --- lookup
155
156
private _lookup(uri: vscode.Uri, silent: false): Entry;
157
private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined;
158
private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined {
159
const parts = uri.path.split('/');
160
let entry: Entry = this.root;
161
for (const part of parts) {
162
if (!part) {
163
continue;
164
}
165
let child: Entry | undefined;
166
if (entry instanceof Directory) {
167
child = entry.entries.get(part);
168
}
169
if (!child) {
170
if (!silent) {
171
throw vscode.FileSystemError.FileNotFound(uri);
172
} else {
173
return undefined;
174
}
175
}
176
entry = child;
177
}
178
return entry;
179
}
180
181
private _lookupAsDirectory(uri: vscode.Uri, silent: boolean): Directory {
182
const entry = this._lookup(uri, silent);
183
if (entry instanceof Directory) {
184
return entry;
185
}
186
throw vscode.FileSystemError.FileNotADirectory(uri);
187
}
188
189
private _lookupAsFile(uri: vscode.Uri, silent: boolean): File {
190
const entry = this._lookup(uri, silent);
191
if (entry instanceof File) {
192
return entry;
193
}
194
throw vscode.FileSystemError.FileIsADirectory(uri);
195
}
196
197
private _lookupParentDirectory(uri: vscode.Uri): Directory {
198
const dirname = uri.with({ path: path.posix.dirname(uri.path) });
199
return this._lookupAsDirectory(dirname, false);
200
}
201
202
// --- manage file events
203
204
private _emitter = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
205
private _bufferedEvents: vscode.FileChangeEvent[] = [];
206
private _fireSoonHandle?: NodeJS.Timer;
207
208
readonly onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]> = this._emitter.event;
209
210
watch(_resource: vscode.Uri): vscode.Disposable {
211
// ignore, fires for all changes...
212
return new vscode.Disposable(() => { });
213
}
214
215
private _fireSoon(...events: vscode.FileChangeEvent[]): void {
216
this._bufferedEvents.push(...events);
217
218
if (this._fireSoonHandle) {
219
clearTimeout(this._fireSoonHandle);
220
}
221
222
this._fireSoonHandle = setTimeout(() => {
223
this._emitter.fire(this._bufferedEvents);
224
this._bufferedEvents.length = 0;
225
}, 5);
226
}
227
}
228
// end of MemFS
229
230