Skip to content

Commit

Permalink
move proposed search api logic into its own world, #47058
Browse files Browse the repository at this point in the history
  • Loading branch information
jrieken committed Apr 17, 2018
1 parent e09c8a7 commit c8b4f0d
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import './mainThreadOutputService';
import './mainThreadProgress';
import './mainThreadQuickOpen';
import './mainThreadSCM';
import './mainThreadSearch';
import './mainThreadSaveParticipant';
import './mainThreadStatusBar';
import './mainThreadStorage';
Expand Down
132 changes: 6 additions & 126 deletions src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
}
}
148 changes: 148 additions & 0 deletions src/vs/workbench/api/electron-browser/mainThreadSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';

import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import URI, { UriComponents } from 'vs/base/common/uri';
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import { IFileMatch, ILineMatch, ISearchComplete, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, QueryType } from 'vs/platform/search/common/search';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../node/extHost.protocol';

@extHostNamedCustomer(MainContext.MainThreadSearch)
export class MainThreadSearch implements MainThreadSearchShape {

private readonly _proxy: ExtHostSearchShape;
private readonly _searchProvider = new Map<number, RemoteSearchProvider>();

constructor(
extHostContext: IExtHostContext,
@ISearchService private readonly _searchService: ISearchService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSearch);
}

dispose(): void {
this._searchProvider.forEach(value => dispose());
this._searchProvider.clear();
}

$registerSearchProvider(handle: number, scheme: string): void {
this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, scheme, handle, this._proxy));
}

$unregisterProvider(handle: number): void {
dispose(this._searchProvider.get(handle));
this._searchProvider.delete(handle);
}

$handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
}
}

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: ExtHostSearchShape
) {
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);
}
}
4 changes: 3 additions & 1 deletion src/vs/workbench/api/node/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview';
import * as files from 'vs/platform/files/common/files';
import { ExtHostSearch } from './extHostSearch';

export interface IExtensionApiFactory {
(extension: IExtensionDescription): typeof vscode;
Expand Down Expand Up @@ -116,6 +117,7 @@ export function createApiFactory(
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol));
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace));
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
Expand Down Expand Up @@ -568,7 +570,7 @@ export function createApiFactory(
return extHostFileSystem.registerFileSystemProvider(scheme, provider, newProvider);
}),
registerSearchProvider: proposedApiFunction(extension, (scheme, provider) => {
return extHostFileSystem.registerSearchProvider(scheme, provider);
return extHostSearch.registerSearchProvider(scheme, provider);
})
};

Expand Down
10 changes: 8 additions & 2 deletions src/vs/workbench/api/node/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,11 +383,13 @@ export interface IFileChangeDto {

export interface MainThreadFileSystemShape extends IDisposable {
$registerFileSystemProvider(handle: number, scheme: string): void;
$registerSearchProvider(handle: number, scheme: string): void;
$unregisterProvider(handle: number): void;

$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
}

export interface MainThreadSearchShape extends IDisposable {
$registerSearchProvider(handle: number, scheme: string): void;
$unregisterProvider(handle: number): void;
$handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void;
}

Expand Down Expand Up @@ -576,7 +578,9 @@ export interface ExtHostFileSystemShape {
$readdir(handle: number, resource: UriComponents): TPromise<[string, IStat][]>;

$delete(handle: number, resource: UriComponents): TPromise<void>;
}

export interface ExtHostSearchShape {
$provideFileSearchResults(handle: number, session: number, query: string): TPromise<void>;
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise<void>;
}
Expand Down Expand Up @@ -857,6 +861,7 @@ export const MainContext = {
MainThreadFileSystem: createMainId<MainThreadFileSystemShape>('MainThreadFileSystem'),
MainThreadExtensionService: createMainId<MainThreadExtensionServiceShape>('MainThreadExtensionService'),
MainThreadSCM: createMainId<MainThreadSCMShape>('MainThreadSCM'),
MainThreadSearch: createMainId<MainThreadSearchShape>('MainThreadSearch'),
MainThreadTask: createMainId<MainThreadTaskShape>('MainThreadTask'),
MainThreadWindow: createMainId<MainThreadWindowShape>('MainThreadWindow'),
};
Expand All @@ -882,6 +887,7 @@ export const ExtHostContext = {
ExtHostLogService: createExtId<ExtHostLogServiceShape>('ExtHostLogService'),
ExtHostTerminalService: createExtId<ExtHostTerminalServiceShape>('ExtHostTerminalService'),
ExtHostSCM: createExtId<ExtHostSCMShape>('ExtHostSCM'),
ExtHostSearch: createExtId<ExtHostSearchShape>('ExtHostSearch'),
ExtHostTask: createExtId<ExtHostTaskShape>('ExtHostTask'),
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
Expand Down
Loading

0 comments on commit c8b4f0d

Please sign in to comment.