move proposed search api logic into its own world, #47058

This commit is contained in:
Johannes Rieken
2018-04-17 18:38:17 +02:00
parent e09c8a7086
commit c8b4f0d05d
7 changed files with 231 additions and 173 deletions

View File

@@ -4,28 +4,23 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise, PPromise } from 'vs/base/common/winjs.base';
import { ExtHostContext, MainContext, IExtHostContext, MainThreadFileSystemShape, ExtHostFileSystemShape, IFileChangeDto } from '../node/extHost.protocol';
import { IFileService, IStat, IFileChange, ISimpleReadWriteProvider, IFileSystemProviderBase, FileOpenFlags } from 'vs/platform/files/common/files';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { FileOpenFlags, IFileChange, IFileService, IFileSystemProviderBase, ISimpleReadWriteProvider, IStat } from 'vs/platform/files/common/files';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ISearchResultProvider, ISearchQuery, ISearchComplete, ISearchProgressItem, QueryType, IFileMatch, ISearchService, ILineMatch } from 'vs/platform/search/common/search';
import { values } from 'vs/base/common/map';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../node/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
export class MainThreadFileSystem implements MainThreadFileSystemShape {
private readonly _proxy: ExtHostFileSystemShape;
private readonly _fileProvider = new Map<number, RemoteFileSystemProvider>();
private readonly _searchProvider = new Map<number, RemoteSearchProvider>();
constructor(
extHostContext: IExtHostContext,
@IFileService private readonly _fileService: IFileService,
@ISearchService private readonly _searchService: ISearchService
@IFileService private readonly _fileService: IFileService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystem);
}
@@ -38,27 +33,14 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
$registerFileSystemProvider(handle: number, scheme: string): void {
this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, handle, this._proxy));
}
$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._fileProvider.get(handle).$onFileSystemChange(changes);
}
// --- search
$handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
}
}
class RemoteFileSystemProvider implements ISimpleReadWriteProvider, IFileSystemProviderBase {
@@ -121,105 +103,3 @@ class RemoteFileSystemProvider implements ISimpleReadWriteProvider, IFileSystemP
return this._proxy.$readdir(this._handle, resource);
}
}
class SearchOperation {
private static _idPool = 0;
constructor(
readonly progress: (match: IFileMatch) => any,
readonly id: number = ++SearchOperation._idPool,
readonly matches = new Map<string, IFileMatch>()
) {
//
}
addMatch(resource: URI, match: ILineMatch): void {
if (!this.matches.has(resource.toString())) {
this.matches.set(resource.toString(), { resource, lineMatches: [] });
}
if (match) {
this.matches.get(resource.toString()).lineMatches.push(match);
}
this.progress(this.matches.get(resource.toString()));
}
}
class RemoteSearchProvider implements ISearchResultProvider {
private readonly _registrations: IDisposable[];
private readonly _searches = new Map<number, SearchOperation>();
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<ISearchComplete, ISearchProgressItem> {
if (isFalsyOrEmpty(query.folderQueries)) {
return PPromise.as(undefined);
}
let includes = { ...query.includePattern };
let excludes = { ...query.excludePattern };
for (const folderQuery of query.folderQueries) {
if (folderQuery.folder.scheme === this._scheme) {
includes = { ...includes, ...folderQuery.includePattern };
excludes = { ...excludes, ...folderQuery.excludePattern };
}
}
let outer: TPromise;
return new PPromise((resolve, reject, report) => {
const search = new SearchOperation(report);
this._searches.set(search.id, search);
outer = query.type === QueryType.File
? this._proxy.$provideFileSearchResults(this._handle, search.id, query.filePattern)
: this._proxy.$provideTextSearchResults(this._handle, search.id, query.contentPattern, { excludes: Object.keys(excludes), includes: Object.keys(includes) });
outer.then(() => {
this._searches.delete(search.id);
resolve(({ results: values(search.matches), stats: undefined }));
}, err => {
this._searches.delete(search.id);
reject(err);
});
}, () => {
if (outer) {
outer.cancel();
}
});
}
handleFindMatch(session: number, dataOrUri: UriComponents | [UriComponents, ILineMatch]): void {
if (!this._searches.has(session)) {
// ignore...
return;
}
let resource: URI;
let match: ILineMatch;
if (Array.isArray(dataOrUri)) {
resource = URI.revive(dataOrUri[0]);
match = dataOrUri[1];
} else {
resource = URI.revive(dataOrUri);
}
this._searches.get(session).addMatch(resource, match);
}
}