@codingame/monaco-vscode-api 1.68.7 → 1.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -7
- package/dist/api.js +481 -9583
- package/dist/configuration.d.ts +488 -0
- package/dist/configuration.js +409 -0
- package/dist/extHost.js +14880 -0
- package/dist/files.js +1325 -0
- package/dist/injection.js +15 -0
- package/dist/jsonErrorMessages.js +17 -0
- package/dist/keybindings.d.ts +502 -0
- package/dist/keybindings.js +2352 -0
- package/dist/languageConfiguration.d.ts +158 -0
- package/dist/languageConfiguration.js +929 -0
- package/dist/languageService.js +340 -0
- package/dist/languages.d.ts +477 -0
- package/dist/languages.js +21 -0
- package/dist/layoutService.js +4 -0
- package/dist/messages.d.ts +7 -0
- package/dist/messages.js +3624 -0
- package/dist/missing-services.js +7293 -0
- package/dist/modelEditor.d.ts +164 -0
- package/dist/modelEditor.js +739 -0
- package/dist/monaco.d.ts +4795 -0
- package/dist/monaco.js +243 -0
- package/dist/services.d.ts +14806 -2098
- package/dist/services.js +22 -25
- package/dist/services2.js +423 -0
- package/dist/snippets.d.ts +466 -0
- package/dist/snippets.js +903 -0
- package/dist/textmate.d.ts +682 -0
- package/dist/textmate.js +740 -0
- package/dist/theme.d.ts +22 -0
- package/dist/theme.js +4167 -0
- package/dist/tokenClassification.d.ts +479 -0
- package/dist/tokenClassification.js +304 -0
- package/dist/tokenClassificationRegistry.js +472 -0
- package/dist/tools.js +17 -0
- package/dist/tslib.es6.js +21 -0
- package/dist/workbenchThemeService.js +46 -0
- package/package.json +107 -24
package/dist/files.js
ADDED
|
@@ -0,0 +1,1325 @@
|
|
|
1
|
+
import { _ as __decorate, a as __param } from './tslib.es6.js';
|
|
2
|
+
import { n as format2, o as getServiceMachineId, E as Emitter, p as ResourceQueue, q as isReadableStream, s as peekStream, t as peekReadable, v as bufferToReadable, x as streamToBuffer, y as consumeStream, z as transform, A as isReadableBufferedStream, C as listenStream, D as bufferedStreamToBuffer, F as readableToBuffer, u as unsupported, G as newWriteableBufferStream, H as newWriteableStream } from './missing-services.js';
|
|
3
|
+
import { I as IFileService, j as IProductService, S as Services, z as FileChangesEvent, B as FileOperationError, D as hasOpenReadWriteCloseCapability, E as hasReadWriteCapability, G as hasFileReadStreamCapability, H as toFileSystemProviderErrorCode, q as FileSystemProviderErrorCode, J as ensureFileSystemProviderError, F as FileType, a as FilePermission, K as etag, L as FileOperationEvent, M as toFileOperationResult, O as ETAG_DISABLED, P as hasFileAtomicReadCapability, Q as NotModifiedSinceFileOperationError, R as hasFileFolderCopyCapability, T as hasFileCloneCapability, U as FileSystemProviderError, V as createFileSystemProviderError, C as CancellationTokenSource } from './services2.js';
|
|
4
|
+
import { VSBuffer } from 'monaco-editor/esm/vs/base/common/buffer.js';
|
|
5
|
+
import { canceled } from 'monaco-editor/esm/vs/base/common/errors.js';
|
|
6
|
+
import { localize } from 'monaco-editor/esm/vs/nls.js';
|
|
7
|
+
import { Disposable, toDisposable, dispose, DisposableStore } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
|
|
8
|
+
import { Promises } from 'monaco-editor/esm/vs/base/common/async.js';
|
|
9
|
+
import { Iterable } from 'monaco-editor/esm/vs/base/common/iterator.js';
|
|
10
|
+
import { isAbsolutePath, extUri, extUriIgnorePathCase, basename, dirname } from 'monaco-editor/esm/vs/base/common/resources.js';
|
|
11
|
+
import { TernarySearchTree } from 'monaco-editor/esm/vs/base/common/map.js';
|
|
12
|
+
import { coalesce } from 'monaco-editor/esm/vs/base/common/arrays.js';
|
|
13
|
+
import { hash } from 'monaco-editor/esm/vs/base/common/hash.js';
|
|
14
|
+
import { CancellationToken } from 'monaco-editor/esm/vs/base/common/cancellation.js';
|
|
15
|
+
import { Schemas, RemoteAuthorities } from 'monaco-editor/esm/vs/base/common/network.js';
|
|
16
|
+
import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
|
|
17
|
+
import { Event } from 'monaco-editor/esm/vs/base/common/event.js';
|
|
18
|
+
import { bh as supportsTelemetry, bi as getTelemetryLevel, bd as DEFAULT_EXTENSION, E as Disposable$1 } from './extHost.js';
|
|
19
|
+
import { createDecorator } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
|
|
20
|
+
import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
|
|
21
|
+
import { isWeb } from 'monaco-editor/esm/vs/base/common/platform.js';
|
|
22
|
+
import { registerSingleton } from 'monaco-editor/esm/vs/platform/instantiation/common/extensions.js';
|
|
23
|
+
import { SyncDescriptor } from 'monaco-editor/esm/vs/platform/instantiation/common/descriptors.js';
|
|
24
|
+
import { IStorageService } from 'monaco-editor/esm/vs/platform/storage/common/storage.js';
|
|
25
|
+
import { IEnvironmentService } from 'monaco-editor/esm/vs/platform/environment/common/environment.js';
|
|
26
|
+
import { IConfigurationService } from 'monaco-editor/esm/vs/platform/configuration/common/configuration.js';
|
|
27
|
+
function getRemoteAuthority(uri) {
|
|
28
|
+
return uri.scheme === Schemas.vscodeRemote ? uri.authority : undefined;
|
|
29
|
+
}
|
|
30
|
+
function getRemoteServerRootPath(product) {
|
|
31
|
+
return `/${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`;
|
|
32
|
+
}
|
|
33
|
+
async function readFileIntoStream(provider, resource, target, transformer, options, token) {
|
|
34
|
+
let error = undefined;
|
|
35
|
+
try {
|
|
36
|
+
await doReadFileIntoStream(provider, resource, target, transformer, options, token);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
error = err;
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
if (error && options.errorTransformer) {
|
|
43
|
+
error = options.errorTransformer(error);
|
|
44
|
+
}
|
|
45
|
+
if (typeof error !== 'undefined') {
|
|
46
|
+
target.error(error);
|
|
47
|
+
}
|
|
48
|
+
target.end();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function doReadFileIntoStream(provider, resource, target, transformer, options, token) {
|
|
52
|
+
throwIfCancelled(token);
|
|
53
|
+
const handle = await provider.open(resource, { create: false });
|
|
54
|
+
try {
|
|
55
|
+
throwIfCancelled(token);
|
|
56
|
+
let totalBytesRead = 0;
|
|
57
|
+
let bytesRead = 0;
|
|
58
|
+
let allowedRemainingBytes = (options && typeof options.length === 'number') ? options.length : undefined;
|
|
59
|
+
let buffer = VSBuffer.alloc(Math.min(options.bufferSize, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : options.bufferSize));
|
|
60
|
+
let posInFile = options && typeof options.position === 'number' ? options.position : 0;
|
|
61
|
+
let posInBuffer = 0;
|
|
62
|
+
do {
|
|
63
|
+
bytesRead = await provider.read(handle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer);
|
|
64
|
+
posInFile += bytesRead;
|
|
65
|
+
posInBuffer += bytesRead;
|
|
66
|
+
totalBytesRead += bytesRead;
|
|
67
|
+
if (typeof allowedRemainingBytes === 'number') {
|
|
68
|
+
allowedRemainingBytes -= bytesRead;
|
|
69
|
+
}
|
|
70
|
+
if (posInBuffer === buffer.byteLength) {
|
|
71
|
+
await target.write(transformer(buffer));
|
|
72
|
+
buffer = VSBuffer.alloc(Math.min(options.bufferSize, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : options.bufferSize));
|
|
73
|
+
posInBuffer = 0;
|
|
74
|
+
}
|
|
75
|
+
} while (bytesRead > 0 && (typeof allowedRemainingBytes !== 'number' || allowedRemainingBytes > 0) && throwIfCancelled(token) && throwIfTooLarge(totalBytesRead, options));
|
|
76
|
+
if (posInBuffer > 0) {
|
|
77
|
+
let lastChunkLength = posInBuffer;
|
|
78
|
+
if (typeof allowedRemainingBytes === 'number') {
|
|
79
|
+
lastChunkLength = Math.min(posInBuffer, allowedRemainingBytes);
|
|
80
|
+
}
|
|
81
|
+
target.write(transformer(buffer.slice(0, lastChunkLength)));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw ensureFileSystemProviderError(error);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await provider.close(handle);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function throwIfCancelled(token) {
|
|
92
|
+
if (token.isCancellationRequested) {
|
|
93
|
+
throw canceled();
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
function throwIfTooLarge(totalBytesRead, options) {
|
|
98
|
+
if (options?.limits) {
|
|
99
|
+
if (typeof options.limits.memory === 'number' && totalBytesRead > options.limits.memory) {
|
|
100
|
+
throw createFileSystemProviderError(localize('fileTooLargeForHeapError', "To open a file of this size, you need to restart and allow to use more memory"), FileSystemProviderErrorCode.FileExceedsMemoryLimit);
|
|
101
|
+
}
|
|
102
|
+
if (typeof options.limits.size === 'number' && totalBytesRead > options.limits.size) {
|
|
103
|
+
throw createFileSystemProviderError(localize('fileTooLargeError', "File is too large to open"), FileSystemProviderErrorCode.FileTooLarge);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
let FileService = class FileService extends Disposable {
|
|
109
|
+
constructor(logService) {
|
|
110
|
+
super();
|
|
111
|
+
this.logService = logService;
|
|
112
|
+
this.BUFFER_SIZE = 256 * 1024;
|
|
113
|
+
this._onDidChangeFileSystemProviderRegistrations = this._register(( (new Emitter())));
|
|
114
|
+
this.onDidChangeFileSystemProviderRegistrations = this._onDidChangeFileSystemProviderRegistrations.event;
|
|
115
|
+
this._onWillActivateFileSystemProvider = this._register(( (new Emitter())));
|
|
116
|
+
this.onWillActivateFileSystemProvider = this._onWillActivateFileSystemProvider.event;
|
|
117
|
+
this._onDidChangeFileSystemProviderCapabilities = this._register(( (new Emitter())));
|
|
118
|
+
this.onDidChangeFileSystemProviderCapabilities = this._onDidChangeFileSystemProviderCapabilities.event;
|
|
119
|
+
this.provider = ( (new Map()));
|
|
120
|
+
this._onDidRunOperation = this._register(( (new Emitter())));
|
|
121
|
+
this.onDidRunOperation = this._onDidRunOperation.event;
|
|
122
|
+
this._onDidFilesChange = this._register(( (new Emitter())));
|
|
123
|
+
this.onDidFilesChange = this._onDidFilesChange.event;
|
|
124
|
+
this._onDidWatchError = this._register(( (new Emitter())));
|
|
125
|
+
this.onDidWatchError = this._onDidWatchError.event;
|
|
126
|
+
this.activeWatchers = ( (new Map()));
|
|
127
|
+
this.writeQueue = this._register(( (new ResourceQueue())));
|
|
128
|
+
}
|
|
129
|
+
registerProvider(scheme, provider) {
|
|
130
|
+
if (this.provider.has(scheme)) {
|
|
131
|
+
throw new Error(`A filesystem provider for the scheme '${scheme}' is already registered.`);
|
|
132
|
+
}
|
|
133
|
+
const providerDisposables = ( (new DisposableStore()));
|
|
134
|
+
this.provider.set(scheme, provider);
|
|
135
|
+
this._onDidChangeFileSystemProviderRegistrations.fire({ added: true, scheme, provider });
|
|
136
|
+
providerDisposables.add(provider.onDidChangeFile(changes => this._onDidFilesChange.fire(( (new FileChangesEvent(changes, !this.isPathCaseSensitive(provider)))))));
|
|
137
|
+
if (typeof provider.onDidWatchError === 'function') {
|
|
138
|
+
providerDisposables.add(provider.onDidWatchError(error => this._onDidWatchError.fire(( (new Error(error))))));
|
|
139
|
+
}
|
|
140
|
+
providerDisposables.add(provider.onDidChangeCapabilities(() => this._onDidChangeFileSystemProviderCapabilities.fire({ provider, scheme })));
|
|
141
|
+
return toDisposable(() => {
|
|
142
|
+
this._onDidChangeFileSystemProviderRegistrations.fire({ added: false, scheme, provider });
|
|
143
|
+
this.provider.delete(scheme);
|
|
144
|
+
dispose(providerDisposables);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
getProvider(scheme) {
|
|
148
|
+
return this.provider.get(scheme);
|
|
149
|
+
}
|
|
150
|
+
async activateProvider(scheme) {
|
|
151
|
+
const joiners = [];
|
|
152
|
+
this._onWillActivateFileSystemProvider.fire({
|
|
153
|
+
scheme,
|
|
154
|
+
join(promise) {
|
|
155
|
+
joiners.push(promise);
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
if (this.provider.has(scheme)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
await Promises.settled(joiners);
|
|
162
|
+
}
|
|
163
|
+
async canHandleResource(resource) {
|
|
164
|
+
await this.activateProvider(resource.scheme);
|
|
165
|
+
return this.hasProvider(resource);
|
|
166
|
+
}
|
|
167
|
+
hasProvider(resource) {
|
|
168
|
+
return this.provider.has(resource.scheme);
|
|
169
|
+
}
|
|
170
|
+
hasCapability(resource, capability) {
|
|
171
|
+
const provider = this.provider.get(resource.scheme);
|
|
172
|
+
return !!(provider && (provider.capabilities & capability));
|
|
173
|
+
}
|
|
174
|
+
listCapabilities() {
|
|
175
|
+
return Iterable.map(this.provider, ([scheme, provider]) => ({ scheme, capabilities: provider.capabilities }));
|
|
176
|
+
}
|
|
177
|
+
async withProvider(resource) {
|
|
178
|
+
if (!isAbsolutePath(resource)) {
|
|
179
|
+
throw new FileOperationError(localize('invalidPath', "Unable to resolve filesystem provider with relative file path '{0}'", this.resourceForError(resource)), 8 );
|
|
180
|
+
}
|
|
181
|
+
await this.activateProvider(resource.scheme);
|
|
182
|
+
const provider = this.provider.get(resource.scheme);
|
|
183
|
+
if (!provider) {
|
|
184
|
+
const error = ( (new Error()));
|
|
185
|
+
error.name = 'ENOPRO';
|
|
186
|
+
error.message = ( (localize(
|
|
187
|
+
'noProviderFound',
|
|
188
|
+
"No file system provider found for resource '{0}'",
|
|
189
|
+
(resource.toString())
|
|
190
|
+
)));
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
return provider;
|
|
194
|
+
}
|
|
195
|
+
async withReadProvider(resource) {
|
|
196
|
+
const provider = await this.withProvider(resource);
|
|
197
|
+
if (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider) || hasFileReadStreamCapability(provider)) {
|
|
198
|
+
return provider;
|
|
199
|
+
}
|
|
200
|
+
throw new Error(`Filesystem provider for scheme '${resource.scheme}' neither has FileReadWrite, FileReadStream nor FileOpenReadWriteClose capability which is needed for the read operation.`);
|
|
201
|
+
}
|
|
202
|
+
async withWriteProvider(resource) {
|
|
203
|
+
const provider = await this.withProvider(resource);
|
|
204
|
+
if (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider)) {
|
|
205
|
+
return provider;
|
|
206
|
+
}
|
|
207
|
+
throw new Error(`Filesystem provider for scheme '${resource.scheme}' neither has FileReadWrite nor FileOpenReadWriteClose capability which is needed for the write operation.`);
|
|
208
|
+
}
|
|
209
|
+
async resolve(resource, options) {
|
|
210
|
+
try {
|
|
211
|
+
return await this.doResolveFile(resource, options);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
if (toFileSystemProviderErrorCode(error) === FileSystemProviderErrorCode.FileNotFound) {
|
|
215
|
+
throw new FileOperationError(localize('fileNotFoundError', "Unable to resolve nonexistent file '{0}'", this.resourceForError(resource)), 1 );
|
|
216
|
+
}
|
|
217
|
+
throw ensureFileSystemProviderError(error);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async doResolveFile(resource, options) {
|
|
221
|
+
const provider = await this.withProvider(resource);
|
|
222
|
+
const isPathCaseSensitive = this.isPathCaseSensitive(provider);
|
|
223
|
+
const resolveTo = options?.resolveTo;
|
|
224
|
+
const resolveSingleChildDescendants = options?.resolveSingleChildDescendants;
|
|
225
|
+
const resolveMetadata = options?.resolveMetadata;
|
|
226
|
+
const stat = await provider.stat(resource);
|
|
227
|
+
let trie;
|
|
228
|
+
return this.toFileStat(provider, resource, stat, undefined, !!resolveMetadata, (stat, siblings) => {
|
|
229
|
+
if (!trie) {
|
|
230
|
+
trie = TernarySearchTree.forUris(() => !isPathCaseSensitive);
|
|
231
|
+
trie.set(resource, true);
|
|
232
|
+
if (resolveTo) {
|
|
233
|
+
trie.fill(true, resolveTo);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (trie.get(stat.resource) || trie.findSuperstr(stat.resource.with({ query: null, fragment: null } ))) {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
if (stat.isDirectory && resolveSingleChildDescendants) {
|
|
240
|
+
return siblings === 1;
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
async toFileStat(provider, resource, stat, siblings, resolveMetadata, recurse) {
|
|
246
|
+
const { providerExtUri } = this.getExtUri(provider);
|
|
247
|
+
const fileStat = {
|
|
248
|
+
resource,
|
|
249
|
+
name: providerExtUri.basename(resource),
|
|
250
|
+
isFile: (stat.type & FileType.File) !== 0,
|
|
251
|
+
isDirectory: (stat.type & FileType.Directory) !== 0,
|
|
252
|
+
isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0,
|
|
253
|
+
mtime: stat.mtime,
|
|
254
|
+
ctime: stat.ctime,
|
|
255
|
+
size: stat.size,
|
|
256
|
+
readonly: Boolean((stat.permissions ?? 0) & FilePermission.Readonly) || Boolean(provider.capabilities & 2048 ),
|
|
257
|
+
etag: etag({ mtime: stat.mtime, size: stat.size }),
|
|
258
|
+
children: undefined
|
|
259
|
+
};
|
|
260
|
+
if (fileStat.isDirectory && recurse(fileStat, siblings)) {
|
|
261
|
+
try {
|
|
262
|
+
const entries = await provider.readdir(resource);
|
|
263
|
+
const resolvedEntries = await Promises.settled(entries.map(async ([name, type]) => {
|
|
264
|
+
try {
|
|
265
|
+
const childResource = providerExtUri.joinPath(resource, name);
|
|
266
|
+
const childStat = resolveMetadata ? await provider.stat(childResource) : { type };
|
|
267
|
+
return await this.toFileStat(provider, childResource, childStat, entries.length, resolveMetadata, recurse);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
this.logService.trace(error);
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
}));
|
|
274
|
+
fileStat.children = coalesce(resolvedEntries);
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
this.logService.trace(error);
|
|
278
|
+
fileStat.children = [];
|
|
279
|
+
}
|
|
280
|
+
return fileStat;
|
|
281
|
+
}
|
|
282
|
+
return fileStat;
|
|
283
|
+
}
|
|
284
|
+
async resolveAll(toResolve) {
|
|
285
|
+
return Promises.settled(toResolve.map(async (entry) => {
|
|
286
|
+
try {
|
|
287
|
+
return { stat: await this.doResolveFile(entry.resource, entry.options), success: true };
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
this.logService.trace(error);
|
|
291
|
+
return { stat: undefined, success: false };
|
|
292
|
+
}
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
295
|
+
async stat(resource) {
|
|
296
|
+
const provider = await this.withProvider(resource);
|
|
297
|
+
const stat = await provider.stat(resource);
|
|
298
|
+
return this.toFileStat(provider, resource, stat, undefined, true, () => false );
|
|
299
|
+
}
|
|
300
|
+
async exists(resource) {
|
|
301
|
+
const provider = await this.withProvider(resource);
|
|
302
|
+
try {
|
|
303
|
+
const stat = await provider.stat(resource);
|
|
304
|
+
return !!stat;
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async canCreateFile(resource, options) {
|
|
311
|
+
try {
|
|
312
|
+
await this.doValidateCreateFile(resource, options);
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
return error;
|
|
316
|
+
}
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
async doValidateCreateFile(resource, options) {
|
|
320
|
+
if (!options?.overwrite && (await this.exists(resource))) {
|
|
321
|
+
throw new FileOperationError(localize('fileExists', "Unable to create file '{0}' that already exists when overwrite flag is not set", this.resourceForError(resource)), 3 , options);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async createFile(resource, bufferOrReadableOrStream = VSBuffer.fromString(''), options) {
|
|
325
|
+
await this.doValidateCreateFile(resource, options);
|
|
326
|
+
const fileStat = await this.writeFile(resource, bufferOrReadableOrStream);
|
|
327
|
+
this._onDidRunOperation.fire(( (new FileOperationEvent(resource, 0 , fileStat))));
|
|
328
|
+
return fileStat;
|
|
329
|
+
}
|
|
330
|
+
async writeFile(resource, bufferOrReadableOrStream, options) {
|
|
331
|
+
const provider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(resource), resource);
|
|
332
|
+
const { providerExtUri } = this.getExtUri(provider);
|
|
333
|
+
try {
|
|
334
|
+
const stat = await this.validateWriteFile(provider, resource, options);
|
|
335
|
+
if (!stat) {
|
|
336
|
+
await this.mkdirp(provider, providerExtUri.dirname(resource));
|
|
337
|
+
}
|
|
338
|
+
let bufferOrReadableOrStreamOrBufferedStream;
|
|
339
|
+
if (hasReadWriteCapability(provider) && !(bufferOrReadableOrStream instanceof VSBuffer)) {
|
|
340
|
+
if (isReadableStream(bufferOrReadableOrStream)) {
|
|
341
|
+
const bufferedStream = await peekStream(bufferOrReadableOrStream, 3);
|
|
342
|
+
if (bufferedStream.ended) {
|
|
343
|
+
bufferOrReadableOrStreamOrBufferedStream = VSBuffer.concat(bufferedStream.buffer);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
bufferOrReadableOrStreamOrBufferedStream = bufferedStream;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
bufferOrReadableOrStreamOrBufferedStream = peekReadable(bufferOrReadableOrStream, data => VSBuffer.concat(data), 3);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
bufferOrReadableOrStreamOrBufferedStream = bufferOrReadableOrStream;
|
|
355
|
+
}
|
|
356
|
+
if (!hasOpenReadWriteCloseCapability(provider) || (hasReadWriteCapability(provider) && bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer)) {
|
|
357
|
+
await this.doWriteUnbuffered(provider, resource, options, bufferOrReadableOrStreamOrBufferedStream);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
await this.doWriteBuffered(provider, resource, options, bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer ? bufferToReadable(bufferOrReadableOrStreamOrBufferedStream) : bufferOrReadableOrStreamOrBufferedStream);
|
|
361
|
+
}
|
|
362
|
+
this._onDidRunOperation.fire(( (new FileOperationEvent(resource, 4 ))));
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
throw new FileOperationError(localize('err.write', "Unable to write file '{0}' ({1})", this.resourceForError(resource), ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options);
|
|
366
|
+
}
|
|
367
|
+
return this.resolve(resource, { resolveMetadata: true });
|
|
368
|
+
}
|
|
369
|
+
async validateWriteFile(provider, resource, options) {
|
|
370
|
+
const unlock = !!options?.unlock;
|
|
371
|
+
if (unlock && !((provider.capabilities & 8192) )) {
|
|
372
|
+
throw new Error(localize('writeFailedUnlockUnsupported', "Unable to unlock file '{0}' because provider does not support it.", this.resourceForError(resource)));
|
|
373
|
+
}
|
|
374
|
+
let stat = undefined;
|
|
375
|
+
try {
|
|
376
|
+
stat = await provider.stat(resource);
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
379
|
+
return undefined;
|
|
380
|
+
}
|
|
381
|
+
if ((stat.type & FileType.Directory) !== 0) {
|
|
382
|
+
throw new FileOperationError(localize('fileIsDirectoryWriteError', "Unable to write file '{0}' that is actually a directory", this.resourceForError(resource)), 0 , options);
|
|
383
|
+
}
|
|
384
|
+
this.throwIfFileIsReadonly(resource, stat);
|
|
385
|
+
if (typeof options?.mtime === 'number' && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED &&
|
|
386
|
+
typeof stat.mtime === 'number' && typeof stat.size === 'number' &&
|
|
387
|
+
options.mtime < stat.mtime && options.etag !== etag({ mtime: options.mtime , size: stat.size })) {
|
|
388
|
+
throw new FileOperationError(localize('fileModifiedError', "File Modified Since"), 3 , options);
|
|
389
|
+
}
|
|
390
|
+
return stat;
|
|
391
|
+
}
|
|
392
|
+
async readFile(resource, options, token) {
|
|
393
|
+
const provider = await this.withReadProvider(resource);
|
|
394
|
+
if (options?.atomic) {
|
|
395
|
+
return this.doReadFileAtomic(provider, resource, options, token);
|
|
396
|
+
}
|
|
397
|
+
return this.doReadFile(provider, resource, options, token);
|
|
398
|
+
}
|
|
399
|
+
async doReadFileAtomic(provider, resource, options, token) {
|
|
400
|
+
return (
|
|
401
|
+
(new Promise((resolve, reject) => {
|
|
402
|
+
this.writeQueue.queueFor(resource, this.getExtUri(provider).providerExtUri).queue(async () => {
|
|
403
|
+
try {
|
|
404
|
+
const content = await this.doReadFile(provider, resource, options, token);
|
|
405
|
+
resolve(content);
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
reject(error);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
}))
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
async doReadFile(provider, resource, options, token) {
|
|
415
|
+
const stream = await this.doReadFileStream(provider, resource, {
|
|
416
|
+
...options,
|
|
417
|
+
preferUnbuffered: true
|
|
418
|
+
}, token);
|
|
419
|
+
return {
|
|
420
|
+
...stream,
|
|
421
|
+
value: await streamToBuffer(stream.value)
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
async readFileStream(resource, options, token) {
|
|
425
|
+
const provider = await this.withReadProvider(resource);
|
|
426
|
+
return this.doReadFileStream(provider, resource, options, token);
|
|
427
|
+
}
|
|
428
|
+
async doReadFileStream(provider, resource, options, token) {
|
|
429
|
+
const cancellableSource = ( (new CancellationTokenSource(token)));
|
|
430
|
+
const statPromise = this.validateReadFile(resource, options).then(stat => stat, error => {
|
|
431
|
+
cancellableSource.cancel();
|
|
432
|
+
throw error;
|
|
433
|
+
});
|
|
434
|
+
let fileStream = undefined;
|
|
435
|
+
try {
|
|
436
|
+
if (typeof options?.etag === 'string' && options.etag !== ETAG_DISABLED) {
|
|
437
|
+
await statPromise;
|
|
438
|
+
}
|
|
439
|
+
if ((options?.atomic && hasFileAtomicReadCapability(provider)) ||
|
|
440
|
+
!(hasOpenReadWriteCloseCapability(provider) || hasFileReadStreamCapability(provider)) ||
|
|
441
|
+
(hasReadWriteCapability(provider) && options?.preferUnbuffered)
|
|
442
|
+
) {
|
|
443
|
+
fileStream = this.readFileUnbuffered(provider, resource, options);
|
|
444
|
+
}
|
|
445
|
+
else if (hasFileReadStreamCapability(provider)) {
|
|
446
|
+
fileStream = this.readFileStreamed(provider, resource, cancellableSource.token, options);
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
fileStream = this.readFileBuffered(provider, resource, cancellableSource.token, options);
|
|
450
|
+
}
|
|
451
|
+
const fileStat = await statPromise;
|
|
452
|
+
return {
|
|
453
|
+
...fileStat,
|
|
454
|
+
value: fileStream
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
catch (error) {
|
|
458
|
+
if (fileStream) {
|
|
459
|
+
await consumeStream(fileStream);
|
|
460
|
+
}
|
|
461
|
+
const message = ( (localize(
|
|
462
|
+
'err.read',
|
|
463
|
+
"Unable to read file '{0}' ({1})",
|
|
464
|
+
this.resourceForError(resource),
|
|
465
|
+
(ensureFileSystemProviderError(error).toString())
|
|
466
|
+
)));
|
|
467
|
+
if (error instanceof NotModifiedSinceFileOperationError) {
|
|
468
|
+
throw new NotModifiedSinceFileOperationError(message, error.stat, options);
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
throw new FileOperationError(message, toFileOperationResult(error), options);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
readFileStreamed(provider, resource, token, options = Object.create(null)) {
|
|
476
|
+
const fileStream = provider.readFileStream(resource, options, token);
|
|
477
|
+
return transform(fileStream, {
|
|
478
|
+
data: data => data instanceof VSBuffer ? data : VSBuffer.wrap(data),
|
|
479
|
+
error: error => ( (new FileOperationError( (localize(
|
|
480
|
+
'err.read',
|
|
481
|
+
"Unable to read file '{0}' ({1})",
|
|
482
|
+
this.resourceForError(resource),
|
|
483
|
+
(ensureFileSystemProviderError(error).toString())
|
|
484
|
+
)), toFileOperationResult(error), options)))
|
|
485
|
+
}, data => VSBuffer.concat(data));
|
|
486
|
+
}
|
|
487
|
+
readFileBuffered(provider, resource, token, options = Object.create(null)) {
|
|
488
|
+
const stream = newWriteableBufferStream();
|
|
489
|
+
readFileIntoStream(provider, resource, stream, data => data, {
|
|
490
|
+
...options,
|
|
491
|
+
bufferSize: this.BUFFER_SIZE,
|
|
492
|
+
errorTransformer: error => ( (new FileOperationError( (localize(
|
|
493
|
+
'err.read',
|
|
494
|
+
"Unable to read file '{0}' ({1})",
|
|
495
|
+
this.resourceForError(resource),
|
|
496
|
+
(ensureFileSystemProviderError(error).toString())
|
|
497
|
+
)), toFileOperationResult(error), options)))
|
|
498
|
+
}, token);
|
|
499
|
+
return stream;
|
|
500
|
+
}
|
|
501
|
+
readFileUnbuffered(provider, resource, options) {
|
|
502
|
+
const stream = newWriteableStream(data => VSBuffer.concat(data));
|
|
503
|
+
(async () => {
|
|
504
|
+
try {
|
|
505
|
+
let buffer;
|
|
506
|
+
if (options?.atomic && hasFileAtomicReadCapability(provider)) {
|
|
507
|
+
buffer = await provider.readFile(resource, { atomic: true });
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
buffer = await provider.readFile(resource);
|
|
511
|
+
}
|
|
512
|
+
if (typeof options?.position === 'number') {
|
|
513
|
+
buffer = buffer.slice(options.position);
|
|
514
|
+
}
|
|
515
|
+
if (typeof options?.length === 'number') {
|
|
516
|
+
buffer = buffer.slice(0, options.length);
|
|
517
|
+
}
|
|
518
|
+
this.validateReadFileLimits(resource, buffer.byteLength, options);
|
|
519
|
+
stream.end(VSBuffer.wrap(buffer));
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
stream.error(err);
|
|
523
|
+
stream.end();
|
|
524
|
+
}
|
|
525
|
+
})();
|
|
526
|
+
return stream;
|
|
527
|
+
}
|
|
528
|
+
async validateReadFile(resource, options) {
|
|
529
|
+
const stat = await this.resolve(resource, { resolveMetadata: true });
|
|
530
|
+
if (stat.isDirectory) {
|
|
531
|
+
throw new FileOperationError(localize('fileIsDirectoryReadError', "Unable to read file '{0}' that is actually a directory", this.resourceForError(resource)), 0 , options);
|
|
532
|
+
}
|
|
533
|
+
if (typeof options?.etag === 'string' && options.etag !== ETAG_DISABLED && options.etag === stat.etag) {
|
|
534
|
+
throw new NotModifiedSinceFileOperationError(localize('fileNotModifiedError', "File not modified since"), stat, options);
|
|
535
|
+
}
|
|
536
|
+
this.validateReadFileLimits(resource, stat.size, options);
|
|
537
|
+
return stat;
|
|
538
|
+
}
|
|
539
|
+
validateReadFileLimits(resource, size, options) {
|
|
540
|
+
if (options?.limits) {
|
|
541
|
+
let tooLargeErrorResult = undefined;
|
|
542
|
+
if (typeof options.limits.memory === 'number' && size > options.limits.memory) {
|
|
543
|
+
tooLargeErrorResult = 9 ;
|
|
544
|
+
}
|
|
545
|
+
if (typeof options.limits.size === 'number' && size > options.limits.size) {
|
|
546
|
+
tooLargeErrorResult = 7 ;
|
|
547
|
+
}
|
|
548
|
+
if (typeof tooLargeErrorResult === 'number') {
|
|
549
|
+
throw new FileOperationError(localize('fileTooLargeError', "Unable to read file '{0}' that is too large to open", this.resourceForError(resource)), tooLargeErrorResult);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
async canMove(source, target, overwrite) {
|
|
554
|
+
return this.doCanMoveCopy(source, target, 'move', overwrite);
|
|
555
|
+
}
|
|
556
|
+
async canCopy(source, target, overwrite) {
|
|
557
|
+
return this.doCanMoveCopy(source, target, 'copy', overwrite);
|
|
558
|
+
}
|
|
559
|
+
async doCanMoveCopy(source, target, mode, overwrite) {
|
|
560
|
+
if (( (source.toString())) !== ( (target.toString()))) {
|
|
561
|
+
try {
|
|
562
|
+
const sourceProvider = mode === 'move' ? this.throwIfFileSystemIsReadonly(await this.withWriteProvider(source), source) : await this.withReadProvider(source);
|
|
563
|
+
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);
|
|
564
|
+
await this.doValidateMoveCopy(sourceProvider, source, targetProvider, target, mode, overwrite);
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
return error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
async move(source, target, overwrite) {
|
|
573
|
+
const sourceProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(source), source);
|
|
574
|
+
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);
|
|
575
|
+
const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'move', !!overwrite);
|
|
576
|
+
const fileStat = await this.resolve(target, { resolveMetadata: true });
|
|
577
|
+
this._onDidRunOperation.fire(( (new FileOperationEvent(
|
|
578
|
+
source,
|
|
579
|
+
mode === 'move' ? 2 : 3 ,
|
|
580
|
+
fileStat
|
|
581
|
+
))));
|
|
582
|
+
return fileStat;
|
|
583
|
+
}
|
|
584
|
+
async copy(source, target, overwrite) {
|
|
585
|
+
const sourceProvider = await this.withReadProvider(source);
|
|
586
|
+
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);
|
|
587
|
+
const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', !!overwrite);
|
|
588
|
+
const fileStat = await this.resolve(target, { resolveMetadata: true });
|
|
589
|
+
this._onDidRunOperation.fire(( (new FileOperationEvent(
|
|
590
|
+
source,
|
|
591
|
+
mode === 'copy' ? 3 : 2 ,
|
|
592
|
+
fileStat
|
|
593
|
+
))));
|
|
594
|
+
return fileStat;
|
|
595
|
+
}
|
|
596
|
+
async doMoveCopy(sourceProvider, source, targetProvider, target, mode, overwrite) {
|
|
597
|
+
if (( (source.toString())) === ( (target.toString()))) {
|
|
598
|
+
return mode;
|
|
599
|
+
}
|
|
600
|
+
const { exists, isSameResourceWithDifferentPathCase } = await this.doValidateMoveCopy(sourceProvider, source, targetProvider, target, mode, overwrite);
|
|
601
|
+
if (exists && !isSameResourceWithDifferentPathCase && overwrite) {
|
|
602
|
+
await this.del(target, { recursive: true });
|
|
603
|
+
}
|
|
604
|
+
await this.mkdirp(targetProvider, this.getExtUri(targetProvider).providerExtUri.dirname(target));
|
|
605
|
+
if (mode === 'copy') {
|
|
606
|
+
if (sourceProvider === targetProvider && hasFileFolderCopyCapability(sourceProvider)) {
|
|
607
|
+
await sourceProvider.copy(source, target, { overwrite });
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
const sourceFile = await this.resolve(source);
|
|
611
|
+
if (sourceFile.isDirectory) {
|
|
612
|
+
await this.doCopyFolder(sourceProvider, sourceFile, targetProvider, target);
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
await this.doCopyFile(sourceProvider, source, targetProvider, target);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return mode;
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
if (sourceProvider === targetProvider) {
|
|
622
|
+
await sourceProvider.rename(source, target, { overwrite });
|
|
623
|
+
return mode;
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', overwrite);
|
|
627
|
+
await this.del(source, { recursive: true });
|
|
628
|
+
return 'copy';
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
async doCopyFile(sourceProvider, source, targetProvider, target) {
|
|
633
|
+
if (hasOpenReadWriteCloseCapability(sourceProvider) && hasOpenReadWriteCloseCapability(targetProvider)) {
|
|
634
|
+
return this.doPipeBuffered(sourceProvider, source, targetProvider, target);
|
|
635
|
+
}
|
|
636
|
+
if (hasOpenReadWriteCloseCapability(sourceProvider) && hasReadWriteCapability(targetProvider)) {
|
|
637
|
+
return this.doPipeBufferedToUnbuffered(sourceProvider, source, targetProvider, target);
|
|
638
|
+
}
|
|
639
|
+
if (hasReadWriteCapability(sourceProvider) && hasOpenReadWriteCloseCapability(targetProvider)) {
|
|
640
|
+
return this.doPipeUnbufferedToBuffered(sourceProvider, source, targetProvider, target);
|
|
641
|
+
}
|
|
642
|
+
if (hasReadWriteCapability(sourceProvider) && hasReadWriteCapability(targetProvider)) {
|
|
643
|
+
return this.doPipeUnbuffered(sourceProvider, source, targetProvider, target);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
async doCopyFolder(sourceProvider, sourceFolder, targetProvider, targetFolder) {
|
|
647
|
+
await targetProvider.mkdir(targetFolder);
|
|
648
|
+
if (Array.isArray(sourceFolder.children)) {
|
|
649
|
+
await Promises.settled(sourceFolder.children.map(async (sourceChild) => {
|
|
650
|
+
const targetChild = this.getExtUri(targetProvider).providerExtUri.joinPath(targetFolder, sourceChild.name);
|
|
651
|
+
if (sourceChild.isDirectory) {
|
|
652
|
+
return this.doCopyFolder(sourceProvider, await this.resolve(sourceChild.resource), targetProvider, targetChild);
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
return this.doCopyFile(sourceProvider, sourceChild.resource, targetProvider, targetChild);
|
|
656
|
+
}
|
|
657
|
+
}));
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
async doValidateMoveCopy(sourceProvider, source, targetProvider, target, mode, overwrite) {
|
|
661
|
+
let isSameResourceWithDifferentPathCase = false;
|
|
662
|
+
if (sourceProvider === targetProvider) {
|
|
663
|
+
const { providerExtUri, isPathCaseSensitive } = this.getExtUri(sourceProvider);
|
|
664
|
+
if (!isPathCaseSensitive) {
|
|
665
|
+
isSameResourceWithDifferentPathCase = providerExtUri.isEqual(source, target);
|
|
666
|
+
}
|
|
667
|
+
if (isSameResourceWithDifferentPathCase && mode === 'copy') {
|
|
668
|
+
throw new Error(localize('unableToMoveCopyError1', "Unable to copy when source '{0}' is same as target '{1}' with different path case on a case insensitive file system", this.resourceForError(source), this.resourceForError(target)));
|
|
669
|
+
}
|
|
670
|
+
if (!isSameResourceWithDifferentPathCase && providerExtUri.isEqualOrParent(target, source)) {
|
|
671
|
+
throw new Error(localize('unableToMoveCopyError2', "Unable to move/copy when source '{0}' is parent of target '{1}'.", this.resourceForError(source), this.resourceForError(target)));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
const exists = await this.exists(target);
|
|
675
|
+
if (exists && !isSameResourceWithDifferentPathCase) {
|
|
676
|
+
if (!overwrite) {
|
|
677
|
+
throw new FileOperationError(localize('unableToMoveCopyError3', "Unable to move/copy '{0}' because target '{1}' already exists at destination.", this.resourceForError(source), this.resourceForError(target)), 4 );
|
|
678
|
+
}
|
|
679
|
+
if (sourceProvider === targetProvider) {
|
|
680
|
+
const { providerExtUri } = this.getExtUri(sourceProvider);
|
|
681
|
+
if (providerExtUri.isEqualOrParent(source, target)) {
|
|
682
|
+
throw new Error(localize('unableToMoveCopyError4', "Unable to move/copy '{0}' into '{1}' since a file would replace the folder it is contained in.", this.resourceForError(source), this.resourceForError(target)));
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return { exists, isSameResourceWithDifferentPathCase };
|
|
687
|
+
}
|
|
688
|
+
getExtUri(provider) {
|
|
689
|
+
const isPathCaseSensitive = this.isPathCaseSensitive(provider);
|
|
690
|
+
return {
|
|
691
|
+
providerExtUri: isPathCaseSensitive ? extUri : extUriIgnorePathCase,
|
|
692
|
+
isPathCaseSensitive
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
isPathCaseSensitive(provider) {
|
|
696
|
+
return !!((provider.capabilities & 1024) );
|
|
697
|
+
}
|
|
698
|
+
async createFolder(resource) {
|
|
699
|
+
const provider = this.throwIfFileSystemIsReadonly(await this.withProvider(resource), resource);
|
|
700
|
+
await this.mkdirp(provider, resource);
|
|
701
|
+
const fileStat = await this.resolve(resource, { resolveMetadata: true });
|
|
702
|
+
this._onDidRunOperation.fire(( (new FileOperationEvent(resource, 0 , fileStat))));
|
|
703
|
+
return fileStat;
|
|
704
|
+
}
|
|
705
|
+
async mkdirp(provider, directory) {
|
|
706
|
+
const directoriesToCreate = [];
|
|
707
|
+
const { providerExtUri } = this.getExtUri(provider);
|
|
708
|
+
while (!providerExtUri.isEqual(directory, providerExtUri.dirname(directory))) {
|
|
709
|
+
try {
|
|
710
|
+
const stat = await provider.stat(directory);
|
|
711
|
+
if ((stat.type & FileType.Directory) === 0) {
|
|
712
|
+
throw new Error(localize('mkdirExistsError', "Unable to create folder '{0}' that already exists but is not a directory", this.resourceForError(directory)));
|
|
713
|
+
}
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
catch (error) {
|
|
717
|
+
if (toFileSystemProviderErrorCode(error) !== FileSystemProviderErrorCode.FileNotFound) {
|
|
718
|
+
throw error;
|
|
719
|
+
}
|
|
720
|
+
directoriesToCreate.push(providerExtUri.basename(directory));
|
|
721
|
+
directory = providerExtUri.dirname(directory);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
for (let i = directoriesToCreate.length - 1; i >= 0; i--) {
|
|
725
|
+
directory = providerExtUri.joinPath(directory, directoriesToCreate[i]);
|
|
726
|
+
try {
|
|
727
|
+
await provider.mkdir(directory);
|
|
728
|
+
}
|
|
729
|
+
catch (error) {
|
|
730
|
+
if (toFileSystemProviderErrorCode(error) !== FileSystemProviderErrorCode.FileExists) {
|
|
731
|
+
throw error;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async canDelete(resource, options) {
|
|
737
|
+
try {
|
|
738
|
+
await this.doValidateDelete(resource, options);
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
return error;
|
|
742
|
+
}
|
|
743
|
+
return true;
|
|
744
|
+
}
|
|
745
|
+
async doValidateDelete(resource, options) {
|
|
746
|
+
const provider = this.throwIfFileSystemIsReadonly(await this.withProvider(resource), resource);
|
|
747
|
+
const useTrash = !!options?.useTrash;
|
|
748
|
+
if (useTrash && !((provider.capabilities & 4096) )) {
|
|
749
|
+
throw new Error(localize('deleteFailedTrashUnsupported', "Unable to delete file '{0}' via trash because provider does not support it.", this.resourceForError(resource)));
|
|
750
|
+
}
|
|
751
|
+
let stat = undefined;
|
|
752
|
+
try {
|
|
753
|
+
stat = await provider.stat(resource);
|
|
754
|
+
}
|
|
755
|
+
catch (error) {
|
|
756
|
+
}
|
|
757
|
+
if (stat) {
|
|
758
|
+
this.throwIfFileIsReadonly(resource, stat);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
throw new FileOperationError(localize('deleteFailedNotFound', "Unable to delete nonexistent file '{0}'", this.resourceForError(resource)), 1 );
|
|
762
|
+
}
|
|
763
|
+
const recursive = !!options?.recursive;
|
|
764
|
+
if (!recursive) {
|
|
765
|
+
const stat = await this.resolve(resource);
|
|
766
|
+
if (stat.isDirectory && Array.isArray(stat.children) && stat.children.length > 0) {
|
|
767
|
+
throw new Error(localize('deleteFailedNonEmptyFolder', "Unable to delete non-empty folder '{0}'.", this.resourceForError(resource)));
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
return provider;
|
|
771
|
+
}
|
|
772
|
+
async del(resource, options) {
|
|
773
|
+
const provider = await this.doValidateDelete(resource, options);
|
|
774
|
+
const useTrash = !!options?.useTrash;
|
|
775
|
+
const recursive = !!options?.recursive;
|
|
776
|
+
await provider.delete(resource, { recursive, useTrash });
|
|
777
|
+
this._onDidRunOperation.fire(( (new FileOperationEvent(resource, 1 ))));
|
|
778
|
+
}
|
|
779
|
+
async cloneFile(source, target) {
|
|
780
|
+
const sourceProvider = await this.withProvider(source);
|
|
781
|
+
const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target), target);
|
|
782
|
+
if (sourceProvider === targetProvider && this.getExtUri(sourceProvider).providerExtUri.isEqual(source, target)) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
if (sourceProvider === targetProvider && hasFileCloneCapability(sourceProvider)) {
|
|
786
|
+
return sourceProvider.cloneFile(source, target);
|
|
787
|
+
}
|
|
788
|
+
await this.mkdirp(targetProvider, this.getExtUri(targetProvider).providerExtUri.dirname(target));
|
|
789
|
+
const sourceWriteQueue = this.writeQueue.queueFor(source, this.getExtUri(sourceProvider).providerExtUri);
|
|
790
|
+
if (sourceProvider === targetProvider && hasFileFolderCopyCapability(sourceProvider)) {
|
|
791
|
+
return sourceWriteQueue.queue(() => sourceProvider.copy(source, target, { overwrite: true }));
|
|
792
|
+
}
|
|
793
|
+
return sourceWriteQueue.queue(() => this.doCopyFile(sourceProvider, source, targetProvider, target));
|
|
794
|
+
}
|
|
795
|
+
watch(resource, options = { recursive: false, excludes: [] }) {
|
|
796
|
+
const disposables = ( (new DisposableStore()));
|
|
797
|
+
let watchDisposed = false;
|
|
798
|
+
let disposeWatch = () => { watchDisposed = true; };
|
|
799
|
+
disposables.add(toDisposable(() => disposeWatch()));
|
|
800
|
+
(async () => {
|
|
801
|
+
try {
|
|
802
|
+
const disposable = await this.doWatch(resource, options);
|
|
803
|
+
if (watchDisposed) {
|
|
804
|
+
dispose(disposable);
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
disposeWatch = () => dispose(disposable);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
catch (error) {
|
|
811
|
+
this.logService.error(error);
|
|
812
|
+
}
|
|
813
|
+
})();
|
|
814
|
+
return disposables;
|
|
815
|
+
}
|
|
816
|
+
async doWatch(resource, options) {
|
|
817
|
+
const provider = await this.withProvider(resource);
|
|
818
|
+
const watchHash = hash([this.getExtUri(provider).providerExtUri.getComparisonKey(resource), options]);
|
|
819
|
+
let watcher = this.activeWatchers.get(watchHash);
|
|
820
|
+
if (!watcher) {
|
|
821
|
+
watcher = {
|
|
822
|
+
count: 0,
|
|
823
|
+
disposable: provider.watch(resource, options)
|
|
824
|
+
};
|
|
825
|
+
this.activeWatchers.set(watchHash, watcher);
|
|
826
|
+
}
|
|
827
|
+
watcher.count += 1;
|
|
828
|
+
return toDisposable(() => {
|
|
829
|
+
if (watcher) {
|
|
830
|
+
watcher.count--;
|
|
831
|
+
if (watcher.count === 0) {
|
|
832
|
+
dispose(watcher.disposable);
|
|
833
|
+
this.activeWatchers.delete(watchHash);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
dispose() {
|
|
839
|
+
super.dispose();
|
|
840
|
+
for (const [, watcher] of this.activeWatchers) {
|
|
841
|
+
dispose(watcher.disposable);
|
|
842
|
+
}
|
|
843
|
+
this.activeWatchers.clear();
|
|
844
|
+
}
|
|
845
|
+
async doWriteBuffered(provider, resource, options, readableOrStreamOrBufferedStream) {
|
|
846
|
+
return this.writeQueue.queueFor(resource, this.getExtUri(provider).providerExtUri).queue(async () => {
|
|
847
|
+
const handle = await provider.open(resource, { create: true, unlock: options?.unlock ?? false });
|
|
848
|
+
try {
|
|
849
|
+
if (isReadableStream(readableOrStreamOrBufferedStream) || isReadableBufferedStream(readableOrStreamOrBufferedStream)) {
|
|
850
|
+
await this.doWriteStreamBufferedQueued(provider, handle, readableOrStreamOrBufferedStream);
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
await this.doWriteReadableBufferedQueued(provider, handle, readableOrStreamOrBufferedStream);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
catch (error) {
|
|
857
|
+
throw ensureFileSystemProviderError(error);
|
|
858
|
+
}
|
|
859
|
+
finally {
|
|
860
|
+
await provider.close(handle);
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
async doWriteStreamBufferedQueued(provider, handle, streamOrBufferedStream) {
|
|
865
|
+
let posInFile = 0;
|
|
866
|
+
let stream;
|
|
867
|
+
if (isReadableBufferedStream(streamOrBufferedStream)) {
|
|
868
|
+
if (streamOrBufferedStream.buffer.length > 0) {
|
|
869
|
+
const chunk = VSBuffer.concat(streamOrBufferedStream.buffer);
|
|
870
|
+
await this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0);
|
|
871
|
+
posInFile += chunk.byteLength;
|
|
872
|
+
}
|
|
873
|
+
if (streamOrBufferedStream.ended) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
stream = streamOrBufferedStream.stream;
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
stream = streamOrBufferedStream;
|
|
880
|
+
}
|
|
881
|
+
return (
|
|
882
|
+
(new Promise((resolve, reject) => {
|
|
883
|
+
listenStream(stream, {
|
|
884
|
+
onData: async (chunk) => {
|
|
885
|
+
stream.pause();
|
|
886
|
+
try {
|
|
887
|
+
await this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0);
|
|
888
|
+
}
|
|
889
|
+
catch (error) {
|
|
890
|
+
return reject(error);
|
|
891
|
+
}
|
|
892
|
+
posInFile += chunk.byteLength;
|
|
893
|
+
setTimeout(() => stream.resume());
|
|
894
|
+
},
|
|
895
|
+
onError: error => reject(error),
|
|
896
|
+
onEnd: () => resolve()
|
|
897
|
+
});
|
|
898
|
+
}))
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
async doWriteReadableBufferedQueued(provider, handle, readable) {
|
|
902
|
+
let posInFile = 0;
|
|
903
|
+
let chunk;
|
|
904
|
+
while ((chunk = readable.read()) !== null) {
|
|
905
|
+
await this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0);
|
|
906
|
+
posInFile += chunk.byteLength;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
async doWriteBuffer(provider, handle, buffer, length, posInFile, posInBuffer) {
|
|
910
|
+
let totalBytesWritten = 0;
|
|
911
|
+
while (totalBytesWritten < length) {
|
|
912
|
+
const bytesWritten = await provider.write(handle, posInFile + totalBytesWritten, buffer.buffer, posInBuffer + totalBytesWritten, length - totalBytesWritten);
|
|
913
|
+
totalBytesWritten += bytesWritten;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
async doWriteUnbuffered(provider, resource, options, bufferOrReadableOrStreamOrBufferedStream) {
|
|
917
|
+
return this.writeQueue.queueFor(resource, this.getExtUri(provider).providerExtUri).queue(() => this.doWriteUnbufferedQueued(provider, resource, options, bufferOrReadableOrStreamOrBufferedStream));
|
|
918
|
+
}
|
|
919
|
+
async doWriteUnbufferedQueued(provider, resource, options, bufferOrReadableOrStreamOrBufferedStream) {
|
|
920
|
+
let buffer;
|
|
921
|
+
if (bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer) {
|
|
922
|
+
buffer = bufferOrReadableOrStreamOrBufferedStream;
|
|
923
|
+
}
|
|
924
|
+
else if (isReadableStream(bufferOrReadableOrStreamOrBufferedStream)) {
|
|
925
|
+
buffer = await streamToBuffer(bufferOrReadableOrStreamOrBufferedStream);
|
|
926
|
+
}
|
|
927
|
+
else if (isReadableBufferedStream(bufferOrReadableOrStreamOrBufferedStream)) {
|
|
928
|
+
buffer = await bufferedStreamToBuffer(bufferOrReadableOrStreamOrBufferedStream);
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
buffer = readableToBuffer(bufferOrReadableOrStreamOrBufferedStream);
|
|
932
|
+
}
|
|
933
|
+
await provider.writeFile(resource, buffer.buffer, { create: true, overwrite: true, unlock: options?.unlock ?? false });
|
|
934
|
+
}
|
|
935
|
+
async doPipeBuffered(sourceProvider, source, targetProvider, target) {
|
|
936
|
+
return this.writeQueue.queueFor(target, this.getExtUri(targetProvider).providerExtUri).queue(() => this.doPipeBufferedQueued(sourceProvider, source, targetProvider, target));
|
|
937
|
+
}
|
|
938
|
+
async doPipeBufferedQueued(sourceProvider, source, targetProvider, target) {
|
|
939
|
+
let sourceHandle = undefined;
|
|
940
|
+
let targetHandle = undefined;
|
|
941
|
+
try {
|
|
942
|
+
sourceHandle = await sourceProvider.open(source, { create: false });
|
|
943
|
+
targetHandle = await targetProvider.open(target, { create: true, unlock: false });
|
|
944
|
+
const buffer = VSBuffer.alloc(this.BUFFER_SIZE);
|
|
945
|
+
let posInFile = 0;
|
|
946
|
+
let posInBuffer = 0;
|
|
947
|
+
let bytesRead = 0;
|
|
948
|
+
do {
|
|
949
|
+
bytesRead = await sourceProvider.read(sourceHandle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer);
|
|
950
|
+
await this.doWriteBuffer(targetProvider, targetHandle, buffer, bytesRead, posInFile, posInBuffer);
|
|
951
|
+
posInFile += bytesRead;
|
|
952
|
+
posInBuffer += bytesRead;
|
|
953
|
+
if (posInBuffer === buffer.byteLength) {
|
|
954
|
+
posInBuffer = 0;
|
|
955
|
+
}
|
|
956
|
+
} while (bytesRead > 0);
|
|
957
|
+
}
|
|
958
|
+
catch (error) {
|
|
959
|
+
throw ensureFileSystemProviderError(error);
|
|
960
|
+
}
|
|
961
|
+
finally {
|
|
962
|
+
await Promises.settled([
|
|
963
|
+
typeof sourceHandle === 'number' ? sourceProvider.close(sourceHandle) : Promise.resolve(),
|
|
964
|
+
typeof targetHandle === 'number' ? targetProvider.close(targetHandle) : Promise.resolve(),
|
|
965
|
+
]);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
async doPipeUnbuffered(sourceProvider, source, targetProvider, target) {
|
|
969
|
+
return this.writeQueue.queueFor(target, this.getExtUri(targetProvider).providerExtUri).queue(() => this.doPipeUnbufferedQueued(sourceProvider, source, targetProvider, target));
|
|
970
|
+
}
|
|
971
|
+
async doPipeUnbufferedQueued(sourceProvider, source, targetProvider, target) {
|
|
972
|
+
return targetProvider.writeFile(target, await sourceProvider.readFile(source), { create: true, overwrite: true, unlock: false });
|
|
973
|
+
}
|
|
974
|
+
async doPipeUnbufferedToBuffered(sourceProvider, source, targetProvider, target) {
|
|
975
|
+
return this.writeQueue.queueFor(target, this.getExtUri(targetProvider).providerExtUri).queue(() => this.doPipeUnbufferedToBufferedQueued(sourceProvider, source, targetProvider, target));
|
|
976
|
+
}
|
|
977
|
+
async doPipeUnbufferedToBufferedQueued(sourceProvider, source, targetProvider, target) {
|
|
978
|
+
const targetHandle = await targetProvider.open(target, { create: true, unlock: false });
|
|
979
|
+
try {
|
|
980
|
+
const buffer = await sourceProvider.readFile(source);
|
|
981
|
+
await this.doWriteBuffer(targetProvider, targetHandle, VSBuffer.wrap(buffer), buffer.byteLength, 0, 0);
|
|
982
|
+
}
|
|
983
|
+
catch (error) {
|
|
984
|
+
throw ensureFileSystemProviderError(error);
|
|
985
|
+
}
|
|
986
|
+
finally {
|
|
987
|
+
await targetProvider.close(targetHandle);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
async doPipeBufferedToUnbuffered(sourceProvider, source, targetProvider, target) {
|
|
991
|
+
const buffer = await streamToBuffer(this.readFileBuffered(sourceProvider, source, CancellationToken.None));
|
|
992
|
+
await this.doWriteUnbuffered(targetProvider, target, undefined, buffer);
|
|
993
|
+
}
|
|
994
|
+
throwIfFileSystemIsReadonly(provider, resource) {
|
|
995
|
+
if (provider.capabilities & 2048 ) {
|
|
996
|
+
throw new FileOperationError(localize('err.readonly', "Unable to modify readonly file '{0}'", this.resourceForError(resource)), 6 );
|
|
997
|
+
}
|
|
998
|
+
return provider;
|
|
999
|
+
}
|
|
1000
|
+
throwIfFileIsReadonly(resource, stat) {
|
|
1001
|
+
if ((stat.permissions ?? 0) & FilePermission.Readonly) {
|
|
1002
|
+
throw new FileOperationError(localize('err.readonly', "Unable to modify readonly file '{0}'", this.resourceForError(resource)), 6 );
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
resourceForError(resource) {
|
|
1006
|
+
if (resource.scheme === Schemas.file) {
|
|
1007
|
+
return resource.fsPath;
|
|
1008
|
+
}
|
|
1009
|
+
return (
|
|
1010
|
+
(resource.toString(true))
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
FileService = ( (__decorate([
|
|
1015
|
+
( (__param(0, ILogService)))
|
|
1016
|
+
], FileService)));
|
|
1017
|
+
class File$1 {
|
|
1018
|
+
constructor(name) {
|
|
1019
|
+
this.type = FileType.File;
|
|
1020
|
+
this.ctime = Date.now();
|
|
1021
|
+
this.mtime = Date.now();
|
|
1022
|
+
this.size = 0;
|
|
1023
|
+
this.name = name;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
class Directory {
|
|
1027
|
+
constructor(name) {
|
|
1028
|
+
this.type = FileType.Directory;
|
|
1029
|
+
this.ctime = Date.now();
|
|
1030
|
+
this.mtime = Date.now();
|
|
1031
|
+
this.size = 0;
|
|
1032
|
+
this.name = name;
|
|
1033
|
+
this.entries = ( (new Map()));
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
class InMemoryFileSystemProvider extends Disposable {
|
|
1037
|
+
constructor() {
|
|
1038
|
+
super(...arguments);
|
|
1039
|
+
this.capabilities = 2
|
|
1040
|
+
| 1024 ;
|
|
1041
|
+
this.onDidChangeCapabilities = Event.None;
|
|
1042
|
+
this.root = ( (new Directory('')));
|
|
1043
|
+
this._onDidChangeFile = this._register(( (new Emitter())));
|
|
1044
|
+
this.onDidChangeFile = this._onDidChangeFile.event;
|
|
1045
|
+
this._bufferedChanges = [];
|
|
1046
|
+
}
|
|
1047
|
+
async stat(resource) {
|
|
1048
|
+
return this._lookup(resource, false);
|
|
1049
|
+
}
|
|
1050
|
+
async readdir(resource) {
|
|
1051
|
+
const entry = this._lookupAsDirectory(resource, false);
|
|
1052
|
+
const result = [];
|
|
1053
|
+
entry.entries.forEach((child, name) => result.push([name, child.type]));
|
|
1054
|
+
return result;
|
|
1055
|
+
}
|
|
1056
|
+
async readFile(resource) {
|
|
1057
|
+
const data = this._lookupAsFile(resource, false).data;
|
|
1058
|
+
if (data) {
|
|
1059
|
+
return data;
|
|
1060
|
+
}
|
|
1061
|
+
throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);
|
|
1062
|
+
}
|
|
1063
|
+
async writeFile(resource, content, opts) {
|
|
1064
|
+
const basename$1 = basename(resource);
|
|
1065
|
+
const parent = this._lookupParentDirectory(resource);
|
|
1066
|
+
let entry = parent.entries.get(basename$1);
|
|
1067
|
+
if (entry instanceof Directory) {
|
|
1068
|
+
throw new FileSystemProviderError('file is directory', FileSystemProviderErrorCode.FileIsADirectory);
|
|
1069
|
+
}
|
|
1070
|
+
if (!entry && !opts.create) {
|
|
1071
|
+
throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);
|
|
1072
|
+
}
|
|
1073
|
+
if (entry && opts.create && !opts.overwrite) {
|
|
1074
|
+
throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);
|
|
1075
|
+
}
|
|
1076
|
+
if (!entry) {
|
|
1077
|
+
entry = ( (new File$1(basename$1)));
|
|
1078
|
+
parent.entries.set(basename$1, entry);
|
|
1079
|
+
this._fireSoon({ type: 1 , resource });
|
|
1080
|
+
}
|
|
1081
|
+
entry.mtime = Date.now();
|
|
1082
|
+
entry.size = content.byteLength;
|
|
1083
|
+
entry.data = content;
|
|
1084
|
+
this._fireSoon({ type: 0 , resource });
|
|
1085
|
+
}
|
|
1086
|
+
async rename(from, to, opts) {
|
|
1087
|
+
if (!opts.overwrite && this._lookup(to, true)) {
|
|
1088
|
+
throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);
|
|
1089
|
+
}
|
|
1090
|
+
const entry = this._lookup(from, false);
|
|
1091
|
+
const oldParent = this._lookupParentDirectory(from);
|
|
1092
|
+
const newParent = this._lookupParentDirectory(to);
|
|
1093
|
+
const newName = basename(to);
|
|
1094
|
+
oldParent.entries.delete(entry.name);
|
|
1095
|
+
entry.name = newName;
|
|
1096
|
+
newParent.entries.set(newName, entry);
|
|
1097
|
+
this._fireSoon({ type: 2 , resource: from }, { type: 1 , resource: to });
|
|
1098
|
+
}
|
|
1099
|
+
async delete(resource, opts) {
|
|
1100
|
+
const dirname$1 = dirname(resource);
|
|
1101
|
+
const basename$1 = basename(resource);
|
|
1102
|
+
const parent = this._lookupAsDirectory(dirname$1, false);
|
|
1103
|
+
if (parent.entries.has(basename$1)) {
|
|
1104
|
+
parent.entries.delete(basename$1);
|
|
1105
|
+
parent.mtime = Date.now();
|
|
1106
|
+
parent.size -= 1;
|
|
1107
|
+
this._fireSoon({ type: 0 , resource: dirname$1 }, { resource, type: 2 });
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
async mkdir(resource) {
|
|
1111
|
+
if (this._lookup(resource, true)) {
|
|
1112
|
+
throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);
|
|
1113
|
+
}
|
|
1114
|
+
const basename$1 = basename(resource);
|
|
1115
|
+
const dirname$1 = dirname(resource);
|
|
1116
|
+
const parent = this._lookupAsDirectory(dirname$1, false);
|
|
1117
|
+
const entry = ( (new Directory(basename$1)));
|
|
1118
|
+
parent.entries.set(entry.name, entry);
|
|
1119
|
+
parent.mtime = Date.now();
|
|
1120
|
+
parent.size += 1;
|
|
1121
|
+
this._fireSoon({ type: 0 , resource: dirname$1 }, { type: 1 , resource });
|
|
1122
|
+
}
|
|
1123
|
+
_lookup(uri, silent) {
|
|
1124
|
+
const parts = uri.path.split('/');
|
|
1125
|
+
let entry = this.root;
|
|
1126
|
+
for (const part of parts) {
|
|
1127
|
+
if (!part) {
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
let child;
|
|
1131
|
+
if (entry instanceof Directory) {
|
|
1132
|
+
child = entry.entries.get(part);
|
|
1133
|
+
}
|
|
1134
|
+
if (!child) {
|
|
1135
|
+
if (!silent) {
|
|
1136
|
+
throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);
|
|
1137
|
+
}
|
|
1138
|
+
else {
|
|
1139
|
+
return undefined;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
entry = child;
|
|
1143
|
+
}
|
|
1144
|
+
return entry;
|
|
1145
|
+
}
|
|
1146
|
+
_lookupAsDirectory(uri, silent) {
|
|
1147
|
+
const entry = this._lookup(uri, silent);
|
|
1148
|
+
if (entry instanceof Directory) {
|
|
1149
|
+
return entry;
|
|
1150
|
+
}
|
|
1151
|
+
throw new FileSystemProviderError('file not a directory', FileSystemProviderErrorCode.FileNotADirectory);
|
|
1152
|
+
}
|
|
1153
|
+
_lookupAsFile(uri, silent) {
|
|
1154
|
+
const entry = this._lookup(uri, silent);
|
|
1155
|
+
if (entry instanceof File$1) {
|
|
1156
|
+
return entry;
|
|
1157
|
+
}
|
|
1158
|
+
throw new FileSystemProviderError('file is a directory', FileSystemProviderErrorCode.FileIsADirectory);
|
|
1159
|
+
}
|
|
1160
|
+
_lookupParentDirectory(uri) {
|
|
1161
|
+
const dirname$1 = dirname(uri);
|
|
1162
|
+
return this._lookupAsDirectory(dirname$1, false);
|
|
1163
|
+
}
|
|
1164
|
+
watch(resource, opts) {
|
|
1165
|
+
return Disposable.None;
|
|
1166
|
+
}
|
|
1167
|
+
_fireSoon(...changes) {
|
|
1168
|
+
this._bufferedChanges.push(...changes);
|
|
1169
|
+
if (this._fireSoonHandle) {
|
|
1170
|
+
clearTimeout(this._fireSoonHandle);
|
|
1171
|
+
}
|
|
1172
|
+
this._fireSoonHandle = setTimeout(() => {
|
|
1173
|
+
this._onDidChangeFile.fire(this._bufferedChanges);
|
|
1174
|
+
this._bufferedChanges.length = 0;
|
|
1175
|
+
}, 5);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
const WEB_EXTENSION_RESOURCE_END_POINT = 'web-extension-resource';
|
|
1179
|
+
const IExtensionResourceLoaderService = ( (createDecorator('extensionResourceLoaderService')));
|
|
1180
|
+
class AbstractExtensionResourceLoaderService {
|
|
1181
|
+
constructor(_fileService, _storageService, _productService, _environmentService, _configurationService) {
|
|
1182
|
+
this._fileService = _fileService;
|
|
1183
|
+
this._storageService = _storageService;
|
|
1184
|
+
this._productService = _productService;
|
|
1185
|
+
this._environmentService = _environmentService;
|
|
1186
|
+
this._configurationService = _configurationService;
|
|
1187
|
+
this._webExtensionResourceEndPoint = `${getRemoteServerRootPath(_productService)}/${WEB_EXTENSION_RESOURCE_END_POINT}/`;
|
|
1188
|
+
if (_productService.extensionsGallery) {
|
|
1189
|
+
this._extensionGalleryResourceUrlTemplate = _productService.extensionsGallery.resourceUrlTemplate;
|
|
1190
|
+
this._extensionGalleryAuthority = this._extensionGalleryResourceUrlTemplate ? this._getExtensionGalleryAuthority(( (URI.parse(this._extensionGalleryResourceUrlTemplate)))) : undefined;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
get supportsExtensionGalleryResources() {
|
|
1194
|
+
return this._extensionGalleryResourceUrlTemplate !== undefined;
|
|
1195
|
+
}
|
|
1196
|
+
getExtensionGalleryResourceURL(galleryExtension, path) {
|
|
1197
|
+
if (this._extensionGalleryResourceUrlTemplate) {
|
|
1198
|
+
const uri = ( (URI.parse(
|
|
1199
|
+
format2(this._extensionGalleryResourceUrlTemplate, { publisher: galleryExtension.publisher, name: galleryExtension.name, version: galleryExtension.version, path: 'extension' })
|
|
1200
|
+
)));
|
|
1201
|
+
return this._isWebExtensionResourceEndPoint(uri) ? uri.with({ scheme: RemoteAuthorities.getPreferredWebSchema() }) : uri;
|
|
1202
|
+
}
|
|
1203
|
+
return undefined;
|
|
1204
|
+
}
|
|
1205
|
+
isExtensionGalleryResource(uri) {
|
|
1206
|
+
return this._extensionGalleryAuthority && this._extensionGalleryAuthority === this._getExtensionGalleryAuthority(uri);
|
|
1207
|
+
}
|
|
1208
|
+
async getExtensionGalleryRequestHeaders() {
|
|
1209
|
+
const headers = {
|
|
1210
|
+
'X-Client-Name': `${this._productService.applicationName}${isWeb ? '-web' : ''}`,
|
|
1211
|
+
'X-Client-Version': this._productService.version
|
|
1212
|
+
};
|
|
1213
|
+
if (supportsTelemetry(this._productService, this._environmentService) && getTelemetryLevel(this._configurationService) === 3 ) {
|
|
1214
|
+
headers['X-Machine-Id'] = await this._getServiceMachineId();
|
|
1215
|
+
}
|
|
1216
|
+
if (this._productService.commit) {
|
|
1217
|
+
headers['X-Client-Commit'] = this._productService.commit;
|
|
1218
|
+
}
|
|
1219
|
+
return headers;
|
|
1220
|
+
}
|
|
1221
|
+
_getServiceMachineId() {
|
|
1222
|
+
if (!this._serviceMachineIdPromise) {
|
|
1223
|
+
this._serviceMachineIdPromise = getServiceMachineId(this._environmentService, this._fileService, this._storageService);
|
|
1224
|
+
}
|
|
1225
|
+
return this._serviceMachineIdPromise;
|
|
1226
|
+
}
|
|
1227
|
+
_getExtensionGalleryAuthority(uri) {
|
|
1228
|
+
if (this._isWebExtensionResourceEndPoint(uri)) {
|
|
1229
|
+
return uri.authority;
|
|
1230
|
+
}
|
|
1231
|
+
const index = uri.authority.indexOf('.');
|
|
1232
|
+
return index !== -1 ? uri.authority.substring(index + 1) : undefined;
|
|
1233
|
+
}
|
|
1234
|
+
_isWebExtensionResourceEndPoint(uri) {
|
|
1235
|
+
return uri.path.startsWith(this._webExtensionResourceEndPoint);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
let SimpleExtensionResourceLoaderService = class SimpleExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService {
|
|
1239
|
+
constructor(fileService, storageService, productService, environmentService, configurationService) {
|
|
1240
|
+
super(fileService, storageService, productService, environmentService, configurationService);
|
|
1241
|
+
}
|
|
1242
|
+
async readExtensionResource(uri) {
|
|
1243
|
+
const result = await this._fileService.readFile(uri);
|
|
1244
|
+
return ( result.value.toString());
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
SimpleExtensionResourceLoaderService = ( __decorate([
|
|
1248
|
+
( __param(0, IFileService)),
|
|
1249
|
+
( __param(1, IStorageService)),
|
|
1250
|
+
( __param(2, IProductService)),
|
|
1251
|
+
( __param(3, IEnvironmentService)),
|
|
1252
|
+
( __param(4, IConfigurationService))
|
|
1253
|
+
], SimpleExtensionResourceLoaderService));
|
|
1254
|
+
registerSingleton(IExtensionResourceLoaderService, SimpleExtensionResourceLoaderService);
|
|
1255
|
+
class File {
|
|
1256
|
+
constructor(getContent) {
|
|
1257
|
+
this.getContent = getContent;
|
|
1258
|
+
this.ctime = Date.now();
|
|
1259
|
+
this.mtime = Date.now();
|
|
1260
|
+
this.size = 0;
|
|
1261
|
+
this.type = FileType.File;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
const encoder = new TextEncoder();
|
|
1265
|
+
class ExtensionFileSystemProviderWithFileReadWriteCapability {
|
|
1266
|
+
constructor() {
|
|
1267
|
+
this.capabilities = 2 | 1024 ;
|
|
1268
|
+
this.onDidChangeFile = Event.None;
|
|
1269
|
+
this.onDidChangeCapabilities = Event.None;
|
|
1270
|
+
this.onDidWatchError = Event.None;
|
|
1271
|
+
this.writeFile = unsupported;
|
|
1272
|
+
this.mkdir = unsupported;
|
|
1273
|
+
this.readdir = unsupported;
|
|
1274
|
+
this.delete = unsupported;
|
|
1275
|
+
this.rename = unsupported;
|
|
1276
|
+
this.files = new Map();
|
|
1277
|
+
}
|
|
1278
|
+
async stat(resource) {
|
|
1279
|
+
const file = this.files.get(( resource.toString()));
|
|
1280
|
+
if (file != null) {
|
|
1281
|
+
return file;
|
|
1282
|
+
}
|
|
1283
|
+
throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);
|
|
1284
|
+
}
|
|
1285
|
+
async readFile(resource) {
|
|
1286
|
+
const file = this.files.get(( resource.toString()));
|
|
1287
|
+
if (file != null) {
|
|
1288
|
+
return encoder.encode(await file.getContent());
|
|
1289
|
+
}
|
|
1290
|
+
throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);
|
|
1291
|
+
}
|
|
1292
|
+
watch() {
|
|
1293
|
+
return {
|
|
1294
|
+
dispose() { }
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
registerFile(resource, getContent) {
|
|
1298
|
+
this.files.set(( resource.toString()), new File(getContent));
|
|
1299
|
+
return new Disposable$1(() => {
|
|
1300
|
+
this.files.delete(( resource.toString()));
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
const extensionFileSystemProvider = new ExtensionFileSystemProviderWithFileReadWriteCapability();
|
|
1305
|
+
let MemoryFileService = class MemoryFileService extends FileService {
|
|
1306
|
+
constructor(logService) {
|
|
1307
|
+
super(logService);
|
|
1308
|
+
this.registerProvider(Schemas.file, new InMemoryFileSystemProvider());
|
|
1309
|
+
const extension = Services.get().extension ?? DEFAULT_EXTENSION;
|
|
1310
|
+
this.registerProvider(extension.extensionLocation.scheme, extensionFileSystemProvider);
|
|
1311
|
+
}
|
|
1312
|
+
};
|
|
1313
|
+
MemoryFileService = ( __decorate([
|
|
1314
|
+
( __param(0, ILogService))
|
|
1315
|
+
], MemoryFileService));
|
|
1316
|
+
function registerExtensionFile(resource, getContent) {
|
|
1317
|
+
return extensionFileSystemProvider.registerFile(resource, getContent);
|
|
1318
|
+
}
|
|
1319
|
+
function getServiceOverride() {
|
|
1320
|
+
return {
|
|
1321
|
+
[( IFileService.toString())]: new SyncDescriptor(MemoryFileService),
|
|
1322
|
+
[( IExtensionResourceLoaderService.toString())]: new SyncDescriptor(SimpleExtensionResourceLoaderService)
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
export { IExtensionResourceLoaderService as I, getRemoteAuthority as a, getServiceOverride as g, registerExtensionFile as r };
|