diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 108a6515e425f47dba88203ebd90fc1f4280cf6d..893c80ca37fd56df37d33deb8d0204720492bf08 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2207,4 +2207,26 @@ declare module 'vscode' { }): Disposable; } //#endregion + + //#region + + export interface FileSystem { + /** + * Check if a given file system supports writing files. + * + * Keep in mind that just because a file system supports writing, that does + * not mean that writes will always succeed. There may be permissions issues + * or other errors that prevent writing a file. + * + * @param scheme The scheme of the filesystem, for example `file` or `git`. + * + * @return `true` if the file system supports writing, `false` if it does not + * support writing (i.e. it is readonly), and `undefined` if VS Code does not + * know about the filesystem. + */ + isWritableFileSystem(scheme: string): boolean | undefined; + } + + + //#endregion } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 46a0b734f5be1810fa70723d7cf5dff3c5ba93f0..f4d07676ed2ee505c4f5f9a29d93dd0904830913 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -135,7 +135,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment)); const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService)); const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation)); - const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures)); + const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures, extHostConsumerFileSystem)); const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors)); const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands)); const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService)); diff --git a/src/vs/workbench/api/common/extHostFileSystem.ts b/src/vs/workbench/api/common/extHostFileSystem.ts index 34d7d3862edb54a1dbc2d600432457002872ab5c..c6330dd6e8b2cb4d5fe675b469086ca6d272ce08 100644 --- a/src/vs/workbench/api/common/extHostFileSystem.ts +++ b/src/vs/workbench/api/common/extHostFileSystem.ts @@ -16,6 +16,7 @@ import { State, StateMachine, LinkComputer, Edge } from 'vs/editor/common/modes/ import { commonPrefixLength } from 'vs/base/common/strings'; import { CharCode } from 'vs/base/common/charCode'; import { VSBuffer } from 'vs/base/common/buffer'; +import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer'; class FsLinkProvider { @@ -119,7 +120,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { private _linkProviderRegistration?: IDisposable; private _handlePool: number = 0; - constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures) { + constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures, private readonly _fileSystemConsumer: IExtHostConsumerFileSystem) { this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem); // register used schemes @@ -142,6 +143,8 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { throw new Error(`a provider for the scheme '${scheme}' is already registered`); } + const schemeRegistration = this._fileSystemConsumer._registerScheme(scheme, options); + // this._registerLinkProviderIfNotYetRegistered(); @@ -197,6 +200,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { return toDisposable(() => { subscription.dispose(); + schemeRegistration.dispose(); this._linkProvider.delete(scheme); this._usedSchemes.delete(scheme); this._fsProvider.delete(handle); diff --git a/src/vs/workbench/api/common/extHostFileSystemConsumer.ts b/src/vs/workbench/api/common/extHostFileSystemConsumer.ts index 67c8bb77d5e40fc66b885a93b41cb6deafbe065e..cf3d309dbfbcec8ad11ef010ca1782cb45938086 100644 --- a/src/vs/workbench/api/common/extHostFileSystemConsumer.ts +++ b/src/vs/workbench/api/common/extHostFileSystemConsumer.ts @@ -10,6 +10,7 @@ import { FileSystemError } from 'vs/workbench/api/common/extHostTypes'; import { VSBuffer } from 'vs/base/common/buffer'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; export class ExtHostConsumerFileSystem implements vscode.FileSystem { @@ -17,6 +18,8 @@ export class ExtHostConsumerFileSystem implements vscode.FileSystem { private readonly _proxy: MainThreadFileSystemShape; + private readonly _schemes = new Map(); + constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadFileSystem); } @@ -45,6 +48,14 @@ export class ExtHostConsumerFileSystem implements vscode.FileSystem { copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean; }): Promise { return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError); } + isWritableFileSystem(scheme: string): boolean | undefined { + const entry = this._schemes.get(scheme); + if (entry) { + return !entry.isReadonly; + } + return undefined; + } + private static _handleError(err: any): never { // generic error if (!(err instanceof Error)) { @@ -68,6 +79,14 @@ export class ExtHostConsumerFileSystem implements vscode.FileSystem { default: throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode); } } + + /* internal */ _registerScheme(scheme: string, options: { readonly isReadonly?: boolean }): IDisposable { + this._schemes.set(scheme, options); + + return toDisposable(() => { + return this._schemes.delete(scheme); + }); + } } export interface IExtHostConsumerFileSystem extends ExtHostConsumerFileSystem { }