diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 469fe9552c63a1b4726be2da36bee1045e8a8afc..efd44a680a5f9517921b982578b5c6979dd551e7 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -166,7 +166,7 @@ export enum FileType { Symlink = 2 } export interface IStat { - resource: URI; + id: number | string; mtime: number; size: number; type: FileType; @@ -185,7 +185,7 @@ export interface IFileSystemProvider { unlink(resource: URI): TPromise; rename(resource: URI, target: URI): TPromise; mkdir(resource: URI): TPromise; - readdir(resource: URI): TPromise; + readdir(resource: URI): TPromise<[URI, IStat][]>; rmdir(resource: URI): TPromise; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 37f76762ed7a1ff02e2d1af15c775b197659d7de..4b63d9f20dc77d911538210d22339ec347e7be88 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -120,6 +120,58 @@ declare module 'vscode' { ignoreFocusOut?: boolean; } + + // export enum FileErrorCodes { + // /** + // * Not owner. + // */ + // EPERM = 1, + // /** + // * No such file or directory. + // */ + // ENOENT = 2, + // /** + // * I/O error. + // */ + // EIO = 5, + // /** + // * Permission denied. + // */ + // EACCES = 13, + // /** + // * File exists. + // */ + // EEXIST = 17, + // /** + // * Not a directory. + // */ + // ENOTDIR = 20, + // /** + // * Is a directory. + // */ + // EISDIR = 21, + // /** + // * File too large. + // */ + // EFBIG = 27, + // /** + // * No space left on device. + // */ + // ENOSPC = 28, + // /** + // * Directory is not empty. + // */ + // ENOTEMPTY = 66, + // /** + // * Invalid file handle. + // */ + // ESTALE = 70, + // /** + // * Illegal NFS file handle. + // */ + // EBADHANDLE = 10001, + // } + export enum FileChangeType { Updated = 0, Added = 1, @@ -138,7 +190,7 @@ declare module 'vscode' { } export interface FileStat { - resource: Uri; + id: number | string; mtime: number; size: number; type: FileType; @@ -155,13 +207,40 @@ declare module 'vscode' { // utimes(resource: Uri, mtime: number): Thenable; stat(resource: Uri): Thenable; + + // todo@remote + // offset - byte offset to start + // count - number of bytes to read + // Thenable - number of bytes actually red read(resource: Uri, progress: Progress): Thenable; + + // todo@remote + // offset - byte offset to start + // count - number of bytes to write + // Thenable - number of bytes actually written write(resource: Uri, content: Uint8Array): Thenable; - unlink(resource: Uri): Thenable; + + // todo@remote + // Thenable rename(resource: Uri, target: Uri): Thenable; + + // todo@remote + // Thenable mkdir(resource: Uri): Thenable; - readdir(resource: Uri): Thenable; + readdir(resource: Uri): Thenable<[Uri, FileStat][]>; + + // todo@remote + // ? merge both + // ? recursive del rmdir(resource: Uri): Thenable; + unlink(resource: Uri): Thenable; + + // todo@remote + // create(resource: Uri): Thenable; + + // todo@remote + // helps with performance bigly + // copy(from: Uri, to: Uri): Thenable; } export namespace workspace { diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 51decb5ec71af1fa1643275d73484dc42a6bb5ea..106e79e772c7e09806a1dbf68386bf289902ef02 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -109,7 +109,7 @@ class RemoteFileSystemProvider implements IFileSystemProvider { mkdir(resource: URI): TPromise { return this._proxy.$mkdir(this._handle, resource); } - readdir(resource: URI): TPromise { + readdir(resource: URI): TPromise<[URI, IStat][], any> { return this._proxy.$readdir(this._handle, resource); } rmdir(resource: URI): TPromise { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 8c89933b9bb1f8541002cfaa3bd61f519756655b..89b49dd82924cb5499c1b1e98da15484115ded86 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -486,7 +486,7 @@ export interface ExtHostFileSystemShape { $unlink(handle: number, resource: URI): TPromise; $rename(handle: number, resource: URI, target: URI): TPromise; $mkdir(handle: number, resource: URI): TPromise; - $readdir(handle: number, resource: URI): TPromise; + $readdir(handle: number, resource: URI): TPromise<[URI, IStat][]>; $rmdir(handle: number, resource: URI): TPromise; } diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index d46e8ac3f3a50b3e5566abcfcfaa9e8ff36d0589..55fb5012fef190f6b471d99d26329c6020c30baa 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -66,7 +66,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { $mkdir(handle: number, resource: URI): TPromise { return TPromise.as(this._provider.get(handle).mkdir(resource)); } - $readdir(handle: number, resource: URI): TPromise { + $readdir(handle: number, resource: URI): TPromise<[URI, IStat][], any> { return TPromise.as(this._provider.get(handle).readdir(resource)); } $rmdir(handle: number, resource: URI): TPromise { diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index d34a4e9db698c87b7dfcacb3ad7ef88ab2f51091..7944090af4e4ee72fa02ed28e4d5c81a63705d3e 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -25,12 +25,13 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat: IStat) => boolean): TPromise { - const ret: IFileStat = { +function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse?: (tuple: [URI, IStat]) => boolean): TPromise { + const [resource, stat] = tuple; + const fileStat: IFileStat = { isDirectory: false, hasChildren: false, - resource: stat.resource, - name: basename(stat.resource.path), + resource: resource, + name: basename(resource.path), mtime: stat.mtime, size: stat.size, etag: stat.mtime.toString(29) + stat.size.toString(31), @@ -38,38 +39,38 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat if (stat.type === FileType.File) { // done - return TPromise.as(ret); + return TPromise.as(fileStat); } else { // dir -> resolve - return provider.readdir(stat.resource).then(items => { - ret.isDirectory = true; - ret.hasChildren = items.length > 0; + return provider.readdir(resource).then(entries => { + fileStat.isDirectory = true; + fileStat.hasChildren = entries.length > 0; - if (recurse && recurse(stat)) { + if (recurse && recurse([resource, stat])) { // resolve children if requested - return TPromise.join(items.map(stat => toIFileStat(provider, stat, recurse))).then(children => { - ret.children = children; - return ret; + return TPromise.join(entries.map(stat => toIFileStat(provider, stat, recurse))).then(children => { + fileStat.children = children; + return fileStat; }); } else { - return ret; + return fileStat; } }); } } -export function toDeepIFileStat(provider: IFileSystemProvider, stat: IStat, to: URI[]): TPromise { +export function toDeepIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], to: URI[]): TPromise { const trie = new StringTrieMap(); - trie.insert(stat.resource.toString(), true); + trie.insert(tuple[0].toString(), true); if (!isFalsyOrEmpty(to)) { to.forEach(uri => trie.insert(uri.toString(), true)); } - return toIFileStat(provider, stat, candidate => { - const sub = trie.findSuperstr(candidate.resource.toString()); + return toIFileStat(provider, tuple, candidate => { + const sub = trie.findSuperstr(candidate[0].toString()); return !!sub; }); } @@ -193,7 +194,7 @@ export class RemoteFileService extends FileService { let promises: TPromise[] = []; for (const item of toResolve) { promises.push(provider.stat(item.resource) - .then(stat => toDeepIFileStat(provider, stat, item.options && item.options.resolveTo)) + .then(stat => toDeepIFileStat(provider, [item.resource, stat], item.options && item.options.resolveTo)) .then(stat => result.push({ stat, success: true }))); } return TPromise.join(promises).then(() => result); @@ -221,7 +222,7 @@ export class RemoteFileService extends FileService { private async _doResolveContent(provider: IFileSystemProvider, resource: URI): TPromise { - const stat = await toIFileStat(provider, await provider.stat(resource)); + const stat = await toIFileStat(provider, [resource, await provider.stat(resource)]); const encoding = this.getEncoding(resource); const stream = decodeStream(encoding); @@ -267,7 +268,7 @@ export class RemoteFileService extends FileService { const encoding = this.getEncoding(resource, options.encoding); await provider.write(resource, encode(content, encoding)); const stat = await provider.stat(resource); - const fileStat = await toIFileStat(provider, stat); + const fileStat = await toIFileStat(provider, [resource, stat]); return fileStat; } @@ -306,7 +307,7 @@ export class RemoteFileService extends FileService { } else { const provider = await this._withProvider(resource); await provider.mkdir(resource); - const stat = await toIFileStat(provider, await provider.stat(resource)); + const stat = await toIFileStat(provider, [resource, await provider.stat(resource)]); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); return stat; } @@ -414,7 +415,7 @@ export class RemoteFileService extends FileService { await provider.write(resource, new Uint8Array(0)); stat = await provider.stat(resource); } - return toIFileStat(provider, stat); + return toIFileStat(provider, [resource, stat]); } // TODO@Joh - file watching on demand!