mainThreadFileSystem.ts 7.7 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import { Emitter, Event } from 'vs/base/common/event';
7
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
8 9
import { URI, UriComponents } from 'vs/base/common/uri';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat } from 'vs/platform/files/common/files';
10
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
11
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
12
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
13
import { VSBuffer } from 'vs/base/common/buffer';
14 15 16 17 18

@extHostNamedCustomer(MainContext.MainThreadFileSystem)
export class MainThreadFileSystem implements MainThreadFileSystemShape {

	private readonly _proxy: ExtHostFileSystemShape;
19
	private readonly _fileProvider = new Map<number, RemoteFileSystemProvider>();
20
	private readonly _resourceLabelFormatters = new Map<number, IDisposable>();
21 22 23

	constructor(
		extHostContext: IExtHostContext,
A
Tweaks  
Alex Dima 已提交
24
		@IFileService private readonly _fileService: IFileService,
I
isidor 已提交
25
		@ILabelService private readonly _labelService: ILabelService
26
	) {
27
		this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystem);
28 29 30
	}

	dispose(): void {
J
Johannes Rieken 已提交
31
		this._fileProvider.forEach(value => value.dispose());
32
		this._fileProvider.clear();
33 34
	}

35 36
	$registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities): void {
		this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, capabilities, handle, this._proxy));
37
	}
38

39 40 41
	$unregisterProvider(handle: number): void {
		dispose(this._fileProvider.get(handle));
		this._fileProvider.delete(handle);
42 43
	}

44 45 46 47 48 49 50 51 52 53
	$registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void {
		// Dynamicily registered formatters should have priority over those contributed via package.json
		formatter.priority = true;
		const disposable = this._labelService.registerFormatter(formatter);
		this._resourceLabelFormatters.set(handle, disposable);
	}

	$unregisterResourceLabelFormatter(handle: number): void {
		dispose(this._resourceLabelFormatters.get(handle));
		this._resourceLabelFormatters.delete(handle);
A
Tweaks  
Alex Dima 已提交
54 55
	}

J
Johannes Rieken 已提交
56
	$onFileSystemChange(handle: number, changes: IFileChangeDto[]): void {
57 58 59 60 61
		const fileProvider = this._fileProvider.get(handle);
		if (!fileProvider) {
			throw new Error('Unknown file provider');
		}
		fileProvider.$onFileSystemChange(changes);
62
	}
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112


	// ---

	async $stat(uri: UriComponents): Promise<IStat> {
		const stat = await this._fileService.resolve(URI.revive(uri), { resolveMetadata: true });
		return {
			ctime: 0,
			mtime: stat.mtime,
			size: stat.size,
			type: MainThreadFileSystem._getFileType(stat)
		};
	}

	async $readdir(uri: UriComponents): Promise<[string, FileType][]> {
		const stat = await this._fileService.resolve(URI.revive(uri), { resolveMetadata: false });
		if (!stat.children) {
			throw new Error('not a folder');
		}
		return stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)]);
	}

	private static _getFileType(stat: IFileStat): FileType {
		return (stat.isDirectory ? FileType.Directory : FileType.File) + (stat.isSymbolicLink ? FileType.SymbolicLink : 0);
	}

	async $readFile(resource: UriComponents): Promise<VSBuffer> {
		return (await this._fileService.readFile(URI.revive(resource))).value;
	}

	async $writeFile(resource: UriComponents, content: VSBuffer, opts: FileWriteOptions): Promise<void> {
		//todo@joh honor opts
		await this._fileService.writeFile(URI.revive(resource), content, {});
	}

	async $rename(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
		this._fileService.move(URI.revive(resource), URI.revive(target), opts.overwrite);
	}

	async $copy(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
		this._fileService.copy(URI.revive(resource), URI.revive(target), opts.overwrite);
	}

	async $mkdir(resource: UriComponents): Promise<void> {
		this._fileService.createFolder(URI.revive(resource));
	}

	async $delete(resource: UriComponents, opts: FileDeleteOptions): Promise<void> {
		this._fileService.del(URI.revive(resource), opts);
	}
113 114
}

115
class RemoteFileSystemProvider implements IFileSystemProvider {
116 117

	private readonly _onDidChange = new Emitter<IFileChange[]>();
J
Johannes Rieken 已提交
118
	private readonly _registration: IDisposable;
119

120
	readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChange.event;
A
Alex Dima 已提交
121

122
	readonly capabilities: FileSystemProviderCapabilities;
A
Alex Dima 已提交
123
	readonly onDidChangeCapabilities: Event<void> = Event.None;
124 125

	constructor(
J
Johannes Rieken 已提交
126
		fileService: IFileService,
127
		scheme: string,
128
		capabilities: FileSystemProviderCapabilities,
129 130 131
		private readonly _handle: number,
		private readonly _proxy: ExtHostFileSystemShape
	) {
132
		this.capabilities = capabilities;
J
Johannes Rieken 已提交
133
		this._registration = fileService.registerProvider(scheme, this);
134 135 136
	}

	dispose(): void {
J
Johannes Rieken 已提交
137
		this._registration.dispose();
138 139 140
		this._onDidChange.dispose();
	}

141 142 143
	watch(resource: URI, opts: IWatchOptions) {
		const session = Math.random();
		this._proxy.$watch(this._handle, session, resource, opts);
144 145 146
		return toDisposable(() => {
			this._proxy.$unwatch(this._handle, session);
		});
147 148
	}

J
Johannes Rieken 已提交
149 150 151 152 153 154
	$onFileSystemChange(changes: IFileChangeDto[]): void {
		this._onDidChange.fire(changes.map(RemoteFileSystemProvider._createFileChange));
	}

	private static _createFileChange(dto: IFileChangeDto): IFileChange {
		return { resource: URI.revive(dto.resource), type: dto.type };
155 156 157 158
	}

	// --- forwarding calls

J
Johannes Rieken 已提交
159
	stat(resource: URI): Promise<IStat> {
160 161 162
		return this._proxy.$stat(this._handle, resource).then(undefined, err => {
			throw err;
		});
163
	}
164

J
Johannes Rieken 已提交
165
	readFile(resource: URI): Promise<Uint8Array> {
166
		return this._proxy.$readFile(this._handle, resource).then(buffer => buffer.buffer);
167
	}
168

J
Johannes Rieken 已提交
169
	writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> {
170
		return this._proxy.$writeFile(this._handle, resource, VSBuffer.wrap(content), opts);
171
	}
172

J
Johannes Rieken 已提交
173
	delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
174
		return this._proxy.$delete(this._handle, resource, opts);
175
	}
176

J
Johannes Rieken 已提交
177
	mkdir(resource: URI): Promise<void> {
178 179
		return this._proxy.$mkdir(this._handle, resource);
	}
180

J
Johannes Rieken 已提交
181
	readdir(resource: URI): Promise<[string, FileType][]> {
182
		return this._proxy.$readdir(this._handle, resource);
183
	}
184

J
Johannes Rieken 已提交
185
	rename(resource: URI, target: URI, opts: FileOverwriteOptions): Promise<void> {
186
		return this._proxy.$rename(this._handle, resource, target, opts);
187
	}
188

J
Johannes Rieken 已提交
189
	copy(resource: URI, target: URI, opts: FileOverwriteOptions): Promise<void> {
190
		return this._proxy.$copy(this._handle, resource, target, opts);
191
	}
192

J
Johannes Rieken 已提交
193 194
	open(resource: URI, opts: FileOpenOptions): Promise<number> {
		return this._proxy.$open(this._handle, resource, opts);
195 196
	}

J
Johannes Rieken 已提交
197
	close(fd: number): Promise<void> {
198 199 200
		return this._proxy.$close(this._handle, fd);
	}

J
Johannes Rieken 已提交
201
	read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
202
		return this._proxy.$read(this._handle, fd, pos, length).then(readData => {
203
			data.set(readData.buffer, offset);
204 205
			return readData.byteLength;
		});
206 207
	}

J
Johannes Rieken 已提交
208
	write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
209
		return this._proxy.$write(this._handle, fd, pos, VSBuffer.wrap(data).slice(offset, offset + length));
210
	}
211
}