Skip to content

Commit

Permalink
Merge pull request #53536 from Microsoft/joao/search-progress-events
Browse files Browse the repository at this point in the history
Use events instead of PPromise for search IPC
  • Loading branch information
joaomoreno authored Jul 9, 2018
2 parents 61e0cf0 + 1030cf9 commit 8bc931b
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 202 deletions.
5 changes: 3 additions & 2 deletions src/vs/workbench/services/search/node/fileSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { IProgress, IUncachedSearchStats } from 'vs/platform/search/common/searc

import * as extfs from 'vs/base/node/extfs';
import * as flow from 'vs/base/node/flow';
import { IRawFileMatch, ISerializedSearchComplete, IRawSearch, ISearchEngine, IFolderSearch } from './search';
import { IRawFileMatch, IRawSearch, ISearchEngine, IFolderSearch, ISerializedSearchSuccess } from './search';
import { spawnRipgrepCmd } from './ripgrepFileSearch';
import { rgErrorMsgForDisplay } from './ripgrepTextSearch';

Expand Down Expand Up @@ -721,9 +721,10 @@ export class Engine implements ISearchEngine<IRawFileMatch> {
this.walker = new FileWalker(config);
}

public search(onResult: (result: IRawFileMatch) => void, onProgress: (progress: IProgress) => void, done: (error: Error, complete: ISerializedSearchComplete) => void): void {
public search(onResult: (result: IRawFileMatch) => void, onProgress: (progress: IProgress) => void, done: (error: Error, complete: ISerializedSearchSuccess) => void): void {
this.walker.walk(this.folderQueries, this.extraFiles, onResult, onProgress, (err: Error, isLimitHit: boolean) => {
done(err, {
type: 'success',
limitHit: isLimitHit,
stats: this.walker.getStats()
});
Expand Down
229 changes: 132 additions & 97 deletions src/vs/workbench/services/search/node/rawSearchService.ts

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions src/vs/workbench/services/search/node/ripgrepTextSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as encoding from 'vs/base/node/encoding';
import * as extfs from 'vs/base/node/extfs';
import { IProgress } from 'vs/platform/search/common/search';
import { rgPath } from 'vscode-ripgrep';
import { FileMatch, IFolderSearch, IRawSearch, ISerializedFileMatch, ISerializedSearchComplete, LineMatch } from './search';
import { FileMatch, IFolderSearch, IRawSearch, ISerializedFileMatch, LineMatch, ISerializedSearchSuccess } from './search';

// If vscode-ripgrep is in an .asar file, then the binary is unpacked.
const rgDiskPath = rgPath.replace(/\bnode_modules\.asar\b/, 'node_modules.asar.unpacked');
Expand All @@ -44,10 +44,11 @@ export class RipgrepEngine {
}

// TODO@Rob - make promise-based once the old search is gone, and I don't need them to have matching interfaces anymore
search(onResult: (match: ISerializedFileMatch) => void, onMessage: (message: IProgress) => void, done: (error: Error, complete: ISerializedSearchComplete) => void): void {
search(onResult: (match: ISerializedFileMatch) => void, onMessage: (message: IProgress) => void, done: (error: Error, complete: ISerializedSearchSuccess) => void): void {
if (!this.config.folderQueries.length && !this.config.extraFiles.length) {
process.removeListener('exit', this.killRgProcFn);
done(null, {
type: 'success',
limitHit: false,
stats: null
});
Expand Down Expand Up @@ -94,6 +95,7 @@ export class RipgrepEngine {
this.cancel();
process.removeListener('exit', this.killRgProcFn);
done(null, {
type: 'success',
limitHit: true,
stats: null
});
Expand Down Expand Up @@ -124,11 +126,13 @@ export class RipgrepEngine {
process.removeListener('exit', this.killRgProcFn);
if (stderr && !gotData && (displayMsg = rgErrorMsgForDisplay(stderr))) {
done(new Error(displayMsg), {
type: 'success',
limitHit: false,
stats: null
});
} else {
done(null, {
type: 'success',
limitHit: false,
stats: null
});
Expand Down
35 changes: 29 additions & 6 deletions src/vs/workbench/services/search/node/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

'use strict';

import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import { TPromise } from 'vs/base/common/winjs.base';
import { IExpression } from 'vs/base/common/glob';
import { IProgress, ILineMatch, IPatternInfo, ISearchStats } from 'vs/platform/search/common/search';
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { Event } from 'vs/base/common/event';

export interface IFolderSearch {
folder: string;
Expand Down Expand Up @@ -41,10 +42,10 @@ export interface ITelemetryEvent {
}

export interface IRawSearchService {
fileSearch(search: IRawSearch): PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem>;
textSearch(search: IRawSearch): PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem>;
fileSearch(search: IRawSearch): Event<ISerializedSearchProgressItem | ISerializedSearchComplete>;
textSearch(search: IRawSearch): Event<ISerializedSearchProgressItem | ISerializedSearchComplete>;
clearCache(cacheKey: string): TPromise<void>;
fetchTelemetry(): PPromise<void, ITelemetryEvent>;
readonly onTelemetry: Event<ITelemetryEvent>;
}

export interface IRawFileMatch {
Expand All @@ -55,15 +56,37 @@ export interface IRawFileMatch {
}

export interface ISearchEngine<T> {
search: (onResult: (matches: T) => void, onProgress: (progress: IProgress) => void, done: (error: Error, complete: ISerializedSearchComplete) => void) => void;
search: (onResult: (matches: T) => void, onProgress: (progress: IProgress) => void, done: (error: Error, complete: ISerializedSearchSuccess) => void) => void;
cancel: () => void;
}

export interface ISerializedSearchComplete {
export interface ISerializedSearchSuccess {
type: 'success';
limitHit: boolean;
stats: ISearchStats;
}

export interface ISerializedSearchError {
type: 'error';
error: any;
}

export type ISerializedSearchComplete = ISerializedSearchSuccess | ISerializedSearchError;

export function isSerializedSearchComplete(arg: ISerializedSearchProgressItem | ISerializedSearchComplete): arg is ISerializedSearchComplete {
if ((arg as any).type === 'error') {
return true;
} else if ((arg as any).type === 'success') {
return true;
} else {
return false;
}
}

export function isSerializedSearchSuccess(arg: ISerializedSearchComplete): arg is ISerializedSearchSuccess {
return arg.type === 'success';
}

export interface ISerializedFileMatch {
path: string;
lineMatches?: ILineMatch[];
Expand Down
36 changes: 18 additions & 18 deletions src/vs/workbench/services/search/node/searchIpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,55 @@

'use strict';

import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import { TPromise } from 'vs/base/common/winjs.base';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IRawSearchService, IRawSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ITelemetryEvent } from './search';
import { Event } from 'vs/base/common/event';

export interface ISearchChannel extends IChannel {
call(command: 'fileSearch', search: IRawSearch): PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem>;
call(command: 'textSearch', search: IRawSearch): PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem>;
listen(event: 'telemetry'): Event<ITelemetryEvent>;
listen(event: 'fileSearch', search: IRawSearch): Event<ISerializedSearchProgressItem | ISerializedSearchComplete>;
listen(event: 'textSearch', search: IRawSearch): Event<ISerializedSearchProgressItem | ISerializedSearchComplete>;
call(command: 'clearCache', cacheKey: string): TPromise<void>;
call(command: 'fetchTelemetry'): PPromise<void, ITelemetryEvent>;
call(command: string, arg: any): TPromise<any>;
}

export class SearchChannel implements ISearchChannel {

constructor(private service: IRawSearchService) { }

listen<T>(event: string, arg?: any): Event<T> {
throw new Error('No events');
listen<T>(event: string, arg?: any): Event<any> {
switch (event) {
case 'telemetry': return this.service.onTelemetry;
case 'fileSearch': return this.service.fileSearch(arg);
case 'textSearch': return this.service.textSearch(arg);
}
throw new Error('Event not found');
}

call(command: string, arg?: any): TPromise<any> {
switch (command) {
case 'fileSearch': return this.service.fileSearch(arg);
case 'textSearch': return this.service.textSearch(arg);
case 'clearCache': return this.service.clearCache(arg);
case 'fetchTelemetry': return this.service.fetchTelemetry();
}
return undefined;
throw new Error('Call not found');
}
}

export class SearchChannelClient implements IRawSearchService {

get onTelemetry(): Event<ITelemetryEvent> { return this.channel.listen('telemetry'); }

constructor(private channel: ISearchChannel) { }

fileSearch(search: IRawSearch): PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem> {
return this.channel.call('fileSearch', search);
fileSearch(search: IRawSearch): Event<ISerializedSearchProgressItem | ISerializedSearchComplete> {
return this.channel.listen('fileSearch', search);
}

textSearch(search: IRawSearch): PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem> {
return this.channel.call('textSearch', search);
textSearch(search: IRawSearch): Event<ISerializedSearchProgressItem | ISerializedSearchComplete> {
return this.channel.listen('textSearch', search);
}

clearCache(cacheKey: string): TPromise<void> {
return this.channel.call('clearCache', cacheKey);
}

fetchTelemetry(): PPromise<void, ITelemetryEvent> {
return this.channel.call('fetchTelemetry');
}
}
38 changes: 31 additions & 7 deletions src/vs/workbench/services/search/node/searchService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { IProgress, LineMatch, FileMatch, ISearchComplete, ISearchProgressItem,
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IRawSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedFileMatch, IRawSearchService, ITelemetryEvent } from './search';
import { IRawSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedFileMatch, IRawSearchService, ITelemetryEvent, isSerializedSearchComplete, isSerializedSearchSuccess, ISerializedSearchSuccess } from './search';
import { ISearchChannel, SearchChannelClient } from './searchIpc';
import { IEnvironmentService, IDebugParams } from 'vs/platform/environment/common/environment';
import { ResourceMap } from 'vs/base/common/map';
Expand All @@ -26,6 +26,7 @@ import { Schemas } from 'vs/base/common/network';
import * as pfs from 'vs/base/node/pfs';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Event } from 'vs/base/common/event';

export class SearchService implements ISearchService {
public _serviceBrand: any;
Expand Down Expand Up @@ -320,14 +321,14 @@ export class DiskSearch implements ISearchResultProvider {
const existingFolders = folderQueries.filter((q, index) => exists[index]);
const rawSearch = this.rawSearchQuery(query, existingFolders);

let request: PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem>;
let event: Event<ISerializedSearchProgressItem | ISerializedSearchComplete>;
if (query.type === QueryType.File) {
request = this.raw.fileSearch(rawSearch);
event = this.raw.fileSearch(rawSearch);
} else {
request = this.raw.textSearch(rawSearch);
event = this.raw.textSearch(rawSearch);
}

return DiskSearch.collectResults(request);
return DiskSearch.collectResultsFromEvent(event);
});
}

Expand Down Expand Up @@ -372,7 +373,28 @@ export class DiskSearch implements ISearchResultProvider {
return rawSearch;
}

public static collectResults(request: PPromise<ISerializedSearchComplete, ISerializedSearchProgressItem>): PPromise<ISearchComplete, ISearchProgressItem> {
public static collectResultsFromEvent(event: Event<ISerializedSearchProgressItem | ISerializedSearchComplete>): PPromise<ISearchComplete, ISearchProgressItem> {
const promise = new PPromise<ISerializedSearchSuccess, ISerializedSearchProgressItem>((c, e, p) => {
setTimeout(() => {
const listener = event(ev => {
if (isSerializedSearchComplete(ev)) {
if (isSerializedSearchSuccess(ev)) {
c(ev);
} else {
e(ev.error);
}
listener.dispose();
} else {
p(ev);
}
});
}, 0);
});

return DiskSearch.collectResults(promise);
}

public static collectResults(request: PPromise<ISerializedSearchSuccess, ISerializedSearchProgressItem>): PPromise<ISearchComplete, ISearchProgressItem> {
let result: IFileMatch[] = [];
return new PPromise<ISearchComplete, ISearchProgressItem>((c, e, p) => {
request.done((complete) => {
Expand Down Expand Up @@ -420,6 +442,8 @@ export class DiskSearch implements ISearchResultProvider {
}

public fetchTelemetry(): PPromise<void, ITelemetryEvent> {
return this.raw.fetchTelemetry();
return new PPromise<void, ITelemetryEvent>((c, e, p) => {
this.raw.onTelemetry(p);
});
}
}
5 changes: 3 additions & 2 deletions src/vs/workbench/services/search/node/textSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { IProgress } from 'vs/platform/search/common/search';
import { FileWalker } from 'vs/workbench/services/search/node/fileSearch';

import { ISerializedFileMatch, ISerializedSearchComplete, IRawSearch, ISearchEngine } from './search';
import { ISerializedFileMatch, IRawSearch, ISearchEngine, ISerializedSearchSuccess } from './search';
import { ISearchWorker } from './worker/searchWorkerIpc';
import { ITextSearchWorkerProvider } from './textSearchWorkerProvider';

Expand Down Expand Up @@ -60,7 +60,7 @@ export class Engine implements ISearchEngine<ISerializedFileMatch[]> {
});
}

search(onResult: (match: ISerializedFileMatch[]) => void, onProgress: (progress: IProgress) => void, done: (error: Error, complete: ISerializedSearchComplete) => void): void {
search(onResult: (match: ISerializedFileMatch[]) => void, onProgress: (progress: IProgress) => void, done: (error: Error, complete: ISerializedSearchSuccess) => void): void {
this.workers = this.workerProvider.getWorkers();
this.initializeWorkers();

Expand All @@ -86,6 +86,7 @@ export class Engine implements ISearchEngine<ISerializedFileMatch[]> {
if (!this.isDone && this.processedBytes === this.totalBytes && this.walkerIsDone) {
this.isDone = true;
done(this.walkerError, {
type: 'success',
limitHit: this.limitReached,
stats: this.walker.getStats()
});
Expand Down
Loading

0 comments on commit 8bc931b

Please sign in to comment.