sussudio
Version:
An unofficial VS Code Internal API
109 lines (108 loc) • 4.91 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from "../../../base/common/event.mjs";
import { Disposable, toDisposable } from "../../../base/common/lifecycle.mjs";
import { hasFileFolderCopyCapability } from "../../files/common/files.mjs";
import { newWriteableStream } from "../../../base/common/stream.mjs";
import { TernarySearchTree } from "../../../base/common/ternarySearchTree.mjs";
import { VSBuffer } from "../../../base/common/buffer.mjs";
/**
* This is a wrapper on top of the local filesystem provider which will
* - Convert the user data resources to file system scheme and vice-versa
* - Enforces atomic reads for user data
*/
export class FileUserDataProvider extends Disposable {
fileSystemScheme;
fileSystemProvider;
userDataScheme;
logService;
get capabilities() { return this.fileSystemProvider.capabilities & ~4 /* FileSystemProviderCapabilities.FileOpenReadWriteClose */; }
onDidChangeCapabilities = this.fileSystemProvider.onDidChangeCapabilities;
_onDidChangeFile = this._register(new Emitter());
onDidChangeFile = this._onDidChangeFile.event;
watchResources = TernarySearchTree.forUris(() => !(this.capabilities & 1024 /* FileSystemProviderCapabilities.PathCaseSensitive */));
constructor(fileSystemScheme, fileSystemProvider, userDataScheme, logService) {
super();
this.fileSystemScheme = fileSystemScheme;
this.fileSystemProvider = fileSystemProvider;
this.userDataScheme = userDataScheme;
this.logService = logService;
this._register(this.fileSystemProvider.onDidChangeFile(e => this.handleFileChanges(e)));
}
watch(resource, opts) {
this.watchResources.set(resource, resource);
const disposable = this.fileSystemProvider.watch(this.toFileSystemResource(resource), opts);
return toDisposable(() => {
this.watchResources.delete(resource);
disposable.dispose();
});
}
stat(resource) {
return this.fileSystemProvider.stat(this.toFileSystemResource(resource));
}
mkdir(resource) {
return this.fileSystemProvider.mkdir(this.toFileSystemResource(resource));
}
rename(from, to, opts) {
return this.fileSystemProvider.rename(this.toFileSystemResource(from), this.toFileSystemResource(to), opts);
}
readFile(resource) {
return this.fileSystemProvider.readFile(this.toFileSystemResource(resource), { atomic: true });
}
readFileStream(resource, opts, token) {
const stream = newWriteableStream(data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer);
(async () => {
try {
const contents = await this.readFile(resource);
stream.end(contents);
}
catch (error) {
stream.error(error);
stream.end();
}
})();
return stream;
}
readdir(resource) {
return this.fileSystemProvider.readdir(this.toFileSystemResource(resource));
}
writeFile(resource, content, opts) {
return this.fileSystemProvider.writeFile(this.toFileSystemResource(resource), content, opts);
}
delete(resource, opts) {
return this.fileSystemProvider.delete(this.toFileSystemResource(resource), opts);
}
copy(from, to, opts) {
if (hasFileFolderCopyCapability(this.fileSystemProvider)) {
return this.fileSystemProvider.copy(this.toFileSystemResource(from), this.toFileSystemResource(to), opts);
}
throw new Error('copy not supported');
}
handleFileChanges(changes) {
const userDataChanges = [];
for (const change of changes) {
if (change.resource.scheme !== this.fileSystemScheme) {
continue; // only interested in file schemes
}
const userDataResource = this.toUserDataResource(change.resource);
if (this.watchResources.findSubstr(userDataResource)) {
userDataChanges.push({
resource: userDataResource,
type: change.type
});
}
}
if (userDataChanges.length) {
this.logService.debug('User data changed');
this._onDidChangeFile.fire(userDataChanges);
}
}
toFileSystemResource(userDataResource) {
return userDataResource.with({ scheme: this.fileSystemScheme });
}
toUserDataResource(fileSystemResource) {
return fileSystemResource.with({ scheme: this.userDataScheme });
}
}