diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 25d4550d7fa..57e66accfa5 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -156,24 +156,6 @@ export enum FileType2 { SymbolicLink = 4, } -export class FileError extends Error { - - static readonly EntryExists = new FileError('EEXIST'); - static readonly EntryNotFound = new FileError('ENOENT'); - static readonly EntryNotADirectory = new FileError('ENOTDIR'); - static readonly EntryIsADirectory = new FileError('EISDIR'); - - constructor(readonly code: string, message?: string) { - super(message || code); - } - is(err: any): err is FileError { - if (!err || typeof err !== 'object') { - return false; - } - return err.code === this.code; - } -} - export enum FileOpenFlags { Read = 0b0001, Write = 0b0010, diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7a55ba9b0e2..a78f6101190 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -84,32 +84,18 @@ declare module 'vscode' { // create(resource: Uri): Thenable; } - // export class FileError extends Error { + /** + * + */ + export class FileError extends Error { - // /** - // * Entry already exists, e.g. when creating a file or folder. - // */ - // static readonly EntryExists: FileError; + static EntryExists(message?: string): FileError; + static EntryNotFound(message?: string): FileError; + static EntryNotADirectory(message?: string): FileError; + static EntryIsADirectory(message?: string): FileError; - // /** - // * Entry does not exist. - // */ - // static readonly EntryNotFound: FileError; - - // /** - // * Entry is not a directory. - // */ - // static readonly EntryNotADirectory: FileError; - - // /** - // * Entry is a directory. - // */ - // static readonly EntryIsADirectory: FileError; - - // readonly code: string; - - // constructor(code: string, message?: string); - // } + constructor(message?: string); + } export enum FileChangeType2 { Changed = 1, diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index b3aedaab4a2..e2c1accca14 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import { FileOpenFlags, IFileChange, IFileService, IStat, IWatchOptions, FileError, FileSystemProviderCapabilities, IFileSystemProvider } from 'vs/platform/files/common/files'; +import { FileOpenFlags, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions } from 'vs/platform/files/common/files'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../node/extHost.protocol'; @@ -88,7 +88,7 @@ class RemoteFileSystemProvider implements IFileSystemProvider { // --- forwarding calls - stat(resource: URI): TPromise { + stat(resource: URI): TPromise { return this._proxy.$stat(this._handle, resource).then(undefined, err => { throw err; }); diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 3de53551971..a69e5e34be1 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -713,7 +713,7 @@ export function createApiFactory( FileChangeType2: extHostTypes.FileChangeType2, FileType2: extHostTypes.FileType2, FileOpenFlags: files.FileOpenFlags, - FileError: files.FileError, + FileError: extHostTypes.FileError, FoldingRange: extHostTypes.FoldingRange, FoldingRangeKind: extHostTypes.FoldingRangeKind }; diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index f877921b5d5..ae88f3ded82 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1838,6 +1838,32 @@ export enum FileType2 { SymbolicLink = 4, } +export class FileError extends Error { + + static EntryExists(message?: string): FileError { + return new FileError(message, 'EntryExists', FileError.EntryExists); + } + static EntryNotFound(message?: string): FileError { + return new FileError(message, 'EntryNotFound', FileError.EntryNotFound); + } + static EntryNotADirectory(message?: string): FileError { + return new FileError(message, 'EntryNotADirectory', FileError.EntryNotADirectory); + } + static EntryIsADirectory(message?: string): FileError { + return new FileError(message, 'EntryIsADirectory', FileError.EntryIsADirectory); + } + + constructor(message?: string, code?: string, hide?: Function) { + super(message); + this.name = code ? `FileError/${code}` : `FileError`; + + if (typeof Error.captureStackTrace === 'function' && typeof hide === 'function') { + // nice stack traces + Error.captureStackTrace(this, hide); + } + } +} + //#endregion //#region folding api diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 3d6d056a71b..254c3c9d18f 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -16,7 +16,7 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { FileChangesEvent, FileError, FileOpenFlags, FileOperation, FileOperationError, FileOperationEvent, FileOperationResult, FileType2, IContent, ICreateFileOptions, IFileStat, IFileSystemProvider, IFilesConfiguration, IResolveContentOptions, IResolveFileOptions, IResolveFileResult, IStat, IStreamContent, ITextSnapshot, IUpdateContentOptions, StringSnapshot, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; +import { FileChangesEvent, FileOpenFlags, FileOperation, FileOperationError, FileOperationEvent, FileOperationResult, FileType2, IContent, ICreateFileOptions, IFileStat, IFileSystemProvider, IFilesConfiguration, IResolveContentOptions, IResolveFileOptions, IResolveFileResult, IStat, IStreamContent, ITextSnapshot, IUpdateContentOptions, StringSnapshot, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -200,6 +200,32 @@ export class RemoteFileService extends FileService { || this._supportedSchemes.indexOf(resource.scheme) >= 0; } + private _tryParseFileOperationResult(err: any): FileOperationResult { + if (!(err instanceof Error)) { + return undefined; + } + let match = /FileError\/(.+)$/.exec(err.name); + if (!match) { + return undefined; + } + let res: FileOperationResult; + switch (match[1]) { + case 'EntryNotFound': + res = FileOperationResult.FILE_NOT_FOUND; + break; + case 'EntryIsADirectory': + res = FileOperationResult.FILE_IS_DIRECTORY; + break; + case 'EntryExists': + case 'EntryNotADirectory': + default: + // todo + res = undefined; + break; + } + return res; + } + // --- stat private _withProvider(resource: URI): TPromise { @@ -229,7 +255,10 @@ export class RemoteFileService extends FileService { } else { return this._doResolveFiles([{ resource, options }]).then(data => { if (data.length !== 1 || !data[0].success) { - throw new Error(`ENOENT, ${resource}`); + throw new FileOperationError( + localize('fileNotFoundError', "File not found ({0})", resource.toString(true)), + FileOperationResult.FILE_NOT_FOUND + ); } else { return data[0].stat; } @@ -369,10 +398,9 @@ export class RemoteFileService extends FileService { this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat)); return fileStat; }, err => { - if (FileError.EntryExists.is(err)) { - return TPromise.wrapError(new FileOperationError(err.code, FileOperationResult.FILE_MODIFIED_SINCE, options)); - } - throw err; + const message = localize('err.create', "Failed to create file {0}", resource.toString(false)); + const result = this._tryParseFileOperationResult(err); + throw new FileOperationError(message, result, options); }); } }