diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 699ea00d5e5b4..b5a350b5c8a06 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -203,24 +203,6 @@ declare module 'vscode' { type: FileType; } - export interface TextSearchQuery { - pattern: string; - isRegex?: boolean; - isCaseSensitive?: boolean; - isWordMatch?: boolean; - } - - export interface TextSearchOptions { - includes: GlobPattern[]; - excludes: GlobPattern[]; - } - - export interface TextSearchResult { - uri: Uri; - range: Range; - preview: { leading: string, matching: string, trailing: string }; - } - // todo@joh discover files etc // todo@joh CancellationToken everywhere // todo@joh add open/close calls? @@ -265,15 +247,41 @@ declare module 'vscode' { // todo@remote // create(resource: Uri): Thenable; + } + + export namespace workspace { + export function registerFileSystemProvider(scheme: string, provider: FileSystemProvider): Disposable; + } - // find files by names - // todo@joh, move into its own provider - findFiles?(query: string, progress: Progress, token: CancellationToken): Thenable; + //#endregion + + //#region Joh: remote, search provider + + export interface TextSearchQuery { + pattern: string; + isRegex?: boolean; + isCaseSensitive?: boolean; + isWordMatch?: boolean; + } + + export interface TextSearchOptions { + includes: GlobPattern[]; + excludes: GlobPattern[]; + } + + export interface TextSearchResult { + uri: Uri; + range: Range; + preview: { leading: string, matching: string, trailing: string }; + } + + export interface SearchProvider { + provideFileSearchResults?(query: string, progress: Progress, token: CancellationToken): Thenable; provideTextSearchResults?(query: TextSearchQuery, options: TextSearchOptions, progress: Progress, token: CancellationToken): Thenable; } export namespace workspace { - export function registerFileSystemProvider(scheme: string, provider: FileSystemProvider): Disposable; + export function registerSearchProvider(scheme: string, provider: SearchProvider): Disposable; } //#endregion diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index e5bb035c46784..7e36cdb14488e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -20,7 +20,8 @@ import { isFalsyOrEmpty } from 'vs/base/common/arrays'; export class MainThreadFileSystem implements MainThreadFileSystemShape { private readonly _proxy: ExtHostFileSystemShape; - private readonly _provider = new Map(); + private readonly _fileProvider = new Map(); + private readonly _searchProvider = new Map(); constructor( extHostContext: IExtHostContext, @@ -31,31 +32,38 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } dispose(): void { - this._provider.forEach(value => dispose()); - this._provider.clear(); + this._fileProvider.forEach(value => dispose()); + this._fileProvider.clear(); } $registerFileSystemProvider(handle: number, scheme: string): void { - this._provider.set(handle, new RemoteFileSystemProvider(this._fileService, this._searchService, scheme, handle, this._proxy)); + this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, handle, this._proxy)); } - $unregisterFileSystemProvider(handle: number): void { - dispose(this._provider.get(handle)); - this._provider.delete(handle); + $registerSearchProvider(handle: number, scheme: string): void { + this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, scheme, handle, this._proxy)); + } + + $unregisterProvider(handle: number): void { + dispose(this._fileProvider.get(handle)); + this._fileProvider.delete(handle); + + dispose(this._searchProvider.get(handle)); + this._searchProvider.delete(handle); } $onFileSystemChange(handle: number, changes: IFileChangeDto[]): void { - this._provider.get(handle).$onFileSystemChange(changes); + this._fileProvider.get(handle).$onFileSystemChange(changes); } $reportFileChunk(handle: number, session: number, chunk: number[]): void { - this._provider.get(handle).reportFileChunk(session, chunk); + this._fileProvider.get(handle).reportFileChunk(session, chunk); } // --- search $handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void { - this._provider.get(handle).handleFindMatch(session, data); + this._searchProvider.get(handle).handleFindMatch(session, data); } } @@ -71,40 +79,22 @@ class FileReadOperation { } } -class SearchOperation { - - private static _idPool = 0; - - constructor( - readonly progress: (match: IFileMatch) => any, - readonly id: number = ++SearchOperation._idPool, - readonly matches = new Map() - ) { - // - } -} - -class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProvider { +class RemoteFileSystemProvider implements IFileSystemProvider { private readonly _onDidChange = new Emitter(); private readonly _registrations: IDisposable[]; private readonly _reads = new Map(); - private readonly _searches = new Map(); readonly onDidChange: Event = this._onDidChange.event; constructor( fileService: IFileService, - searchService: ISearchService, - private readonly _scheme: string, + scheme: string, private readonly _handle: number, private readonly _proxy: ExtHostFileSystemShape ) { - this._registrations = [ - fileService.registerProvider(_scheme, this), - searchService.registerSearchResultProvider(this), - ]; + this._registrations = [fileService.registerProvider(scheme, this)]; } dispose(): void { @@ -159,8 +149,39 @@ class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProv rmdir(resource: URI): TPromise { return this._proxy.$rmdir(this._handle, resource); } +} - // --- search +class SearchOperation { + + private static _idPool = 0; + + constructor( + readonly progress: (match: IFileMatch) => any, + readonly id: number = ++SearchOperation._idPool, + readonly matches = new Map() + ) { + // + } +} + +class RemoteSearchProvider implements ISearchResultProvider { + + private readonly _registrations: IDisposable[]; + private readonly _searches = new Map(); + + + constructor( + searchService: ISearchService, + private readonly _scheme: string, + private readonly _handle: number, + private readonly _proxy: ExtHostFileSystemShape + ) { + this._registrations = [searchService.registerSearchResultProvider(this)]; + } + + dispose(): void { + dispose(this._registrations); + } search(query: ISearchQuery): PPromise { diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 17491fd9c2687..7cbe907c2d7ac 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -517,8 +517,11 @@ export function createApiFactory( registerTaskProvider: (type: string, provider: vscode.TaskProvider) => { return extHostTask.registerTaskProvider(extension, provider); }, - registerFileSystemProvider: proposedApiFunction(extension, (authority, provider) => { - return extHostFileSystem.registerFileSystemProvider(authority, provider); + registerFileSystemProvider: proposedApiFunction(extension, (scheme, provider) => { + return extHostFileSystem.registerFileSystemProvider(scheme, provider); + }), + registerSearchProvider: proposedApiFunction(extension, (scheme, provider) => { + return extHostFileSystem.registerSearchProvider(scheme, provider); }) }; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 095ea5ce4f1dd..d864ba9693a3f 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -380,7 +380,8 @@ export interface IFileChangeDto { export interface MainThreadFileSystemShape extends IDisposable { $registerFileSystemProvider(handle: number, scheme: string): void; - $unregisterFileSystemProvider(handle: number): void; + $registerSearchProvider(handle: number, scheme: string): void; + $unregisterProvider(handle: number): void; $onFileSystemChange(handle: number, resource: IFileChangeDto[]): void; $reportFileChunk(handle: number, session: number, chunk: number[] | null): void; diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index 8b40b6ac61e8a..10685208822bd 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -58,7 +58,8 @@ class FsLinkProvider implements vscode.DocumentLinkProvider { export class ExtHostFileSystem implements ExtHostFileSystemShape { private readonly _proxy: MainThreadFileSystemShape; - private readonly _provider = new Map(); + private readonly _fsProvider = new Map(); + private readonly _searchProvider = new Map(); private readonly _linkProvider = new FsLinkProvider(); private _handlePool: number = 0; @@ -71,7 +72,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider) { const handle = this._handlePool++; this._linkProvider.add(scheme); - this._provider.set(handle, provider); + this._fsProvider.set(handle, provider); this._proxy.$registerFileSystemProvider(handle, scheme); let reg: IDisposable; if (provider.onDidChange) { @@ -83,17 +84,29 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { reg.dispose(); } this._linkProvider.delete(scheme); - this._provider.delete(handle); - this._proxy.$unregisterFileSystemProvider(handle); + this._fsProvider.delete(handle); + this._proxy.$unregisterProvider(handle); + } + }; + } + + registerSearchProvider(scheme: string, provider: vscode.SearchProvider) { + const handle = this._handlePool++; + this._searchProvider.set(handle, provider); + this._proxy.$registerSearchProvider(handle, scheme); + return { + dispose: () => { + this._searchProvider.delete(handle); + this._proxy.$unregisterProvider(handle); } }; } $utimes(handle: number, resource: UriComponents, mtime: number, atime: number): TPromise { - return asWinJsPromise(token => this._provider.get(handle).utimes(URI.revive(resource), mtime, atime)); + return asWinJsPromise(token => this._fsProvider.get(handle).utimes(URI.revive(resource), mtime, atime)); } $stat(handle: number, resource: UriComponents): TPromise { - return asWinJsPromise(token => this._provider.get(handle).stat(URI.revive(resource))); + return asWinJsPromise(token => this._fsProvider.get(handle).stat(URI.revive(resource))); } $read(handle: number, session: number, offset: number, count: number, resource: UriComponents): TPromise { const progress = { @@ -101,29 +114,29 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { this._proxy.$reportFileChunk(handle, session, [].slice.call(chunk)); } }; - return asWinJsPromise(token => this._provider.get(handle).read(URI.revive(resource), offset, count, progress)); + return asWinJsPromise(token => this._fsProvider.get(handle).read(URI.revive(resource), offset, count, progress)); } $write(handle: number, resource: UriComponents, content: number[]): TPromise { - return asWinJsPromise(token => this._provider.get(handle).write(URI.revive(resource), Buffer.from(content))); + return asWinJsPromise(token => this._fsProvider.get(handle).write(URI.revive(resource), Buffer.from(content))); } $unlink(handle: number, resource: UriComponents): TPromise { - return asWinJsPromise(token => this._provider.get(handle).unlink(URI.revive(resource))); + return asWinJsPromise(token => this._fsProvider.get(handle).unlink(URI.revive(resource))); } $move(handle: number, resource: UriComponents, target: UriComponents): TPromise { - return asWinJsPromise(token => this._provider.get(handle).move(URI.revive(resource), URI.revive(target))); + return asWinJsPromise(token => this._fsProvider.get(handle).move(URI.revive(resource), URI.revive(target))); } $mkdir(handle: number, resource: UriComponents): TPromise { - return asWinJsPromise(token => this._provider.get(handle).mkdir(URI.revive(resource))); + return asWinJsPromise(token => this._fsProvider.get(handle).mkdir(URI.revive(resource))); } $readdir(handle: number, resource: UriComponents): TPromise<[UriComponents, IStat][], any> { - return asWinJsPromise(token => this._provider.get(handle).readdir(URI.revive(resource))); + return asWinJsPromise(token => this._fsProvider.get(handle).readdir(URI.revive(resource))); } $rmdir(handle: number, resource: UriComponents): TPromise { - return asWinJsPromise(token => this._provider.get(handle).rmdir(URI.revive(resource))); + return asWinJsPromise(token => this._fsProvider.get(handle).rmdir(URI.revive(resource))); } $findFiles(handle: number, session: number, query: string): TPromise { - const provider = this._provider.get(handle); - if (!provider.findFiles) { + const provider = this._searchProvider.get(handle); + if (!provider.provideFileSearchResults) { return TPromise.as(undefined); } const progress = { @@ -131,10 +144,10 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { this._proxy.$handleFindMatch(handle, session, uri); } }; - return asWinJsPromise(token => provider.findFiles(query, progress, token)); + return asWinJsPromise(token => provider.provideFileSearchResults(query, progress, token)); } $provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise { - const provider = this._provider.get(handle); + const provider = this._searchProvider.get(handle); if (!provider.provideTextSearchResults) { return TPromise.as(undefined); }