diff --git a/extensions/search-rg/src/extension.ts b/extensions/search-rg/src/extension.ts index be58769c6f692..ea531fbf0827d 100644 --- a/extensions/search-rg/src/extension.ts +++ b/extensions/search-rg/src/extension.ts @@ -7,7 +7,9 @@ import * as vscode from 'vscode'; import { RipgrepTextSearchEngine } from './ripgrepTextSearch'; export function activate(): void { - vscode.workspace.registerSearchProvider('vscode-remote', new RipgrepSearchProvider()); + const provider = new RipgrepSearchProvider(); + vscode.workspace.registerSearchProvider('vscode-remote', provider); + vscode.workspace.registerSearchProvider('file', provider); } class RipgrepSearchProvider implements vscode.SearchProvider { diff --git a/extensions/search-rg/src/ripgrepTextSearch.ts b/extensions/search-rg/src/ripgrepTextSearch.ts index 1e61c291e7f3f..496ec0210f0a6 100644 --- a/extensions/search-rg/src/ripgrepTextSearch.ts +++ b/extensions/search-rg/src/ripgrepTextSearch.ts @@ -32,7 +32,6 @@ export class RipgrepTextSearchEngine { } cancel(): void { - this.isDone = true; this.ripgrepParser.cancel(); this.rgProc.kill(); } @@ -50,6 +49,10 @@ export class RipgrepTextSearchEngine { // let rgCmd = `rg ${escapedArgs}\n - cwd: ${cwd}`; this.rgProc = cp.spawn(rgDiskPath, rgArgs, { cwd }); + this.rgProc.on('error', e => { + console.log(e); + reject(e); + }); this.ripgrepParser = new RipgrepParser(cwd); this.ripgrepParser.on('result', (match: vscode.TextSearchResult) => { @@ -71,17 +74,14 @@ export class RipgrepTextSearchEngine { }); this.rgProc.on('close', code => { - // Trigger last result, then wait on async result handling + // Trigger last result this.ripgrepParser.flush(); this.rgProc = null; - if (!this.isDone) { - this.isDone = true; - let displayMsg: string; - if (stderr && !gotData && (displayMsg = rgErrorMsgForDisplay(stderr))) { - reject(new Error(displayMsg)); - } else { - resolve(); - } + let displayMsg: string; + if (stderr && !gotData && (displayMsg = rgErrorMsgForDisplay(stderr))) { + reject(new Error(displayMsg)); + } else { + resolve(); } }); }); diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index 69a89dbcdef2e..c6bed9fa62c0e 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -5,7 +5,7 @@ 'use strict'; import { PPromise, TPromise } from 'vs/base/common/winjs.base'; -import uri from 'vs/base/common/uri'; +import uri, { UriComponents } from 'vs/base/common/uri'; import * as objects from 'vs/base/common/objects'; import * as paths from 'vs/base/common/paths'; import * as glob from 'vs/base/common/glob'; @@ -33,16 +33,16 @@ export interface ISearchResultProvider { search(query: ISearchQuery): PPromise; } -export interface IFolderQuery { - folder: uri; +export interface IFolderQuery { + folder: U; excludePattern?: glob.IExpression; includePattern?: glob.IExpression; fileEncoding?: string; disregardIgnoreFiles?: boolean; } -export interface ICommonQueryOptions { - extraFileResources?: uri[]; +export interface ICommonQueryOptions { + extraFileResources?: U[]; filePattern?: string; // file search only fileEncoding?: string; maxResults?: number; @@ -60,21 +60,24 @@ export interface ICommonQueryOptions { ignoreSymlinks?: boolean; } -export interface IQueryOptions extends ICommonQueryOptions { +export interface IQueryOptions extends ICommonQueryOptions { excludePattern?: string; includePattern?: string; } -export interface ISearchQuery extends ICommonQueryOptions { +export interface ISearchQueryProps extends ICommonQueryOptions { type: QueryType; excludePattern?: glob.IExpression; includePattern?: glob.IExpression; contentPattern?: IPatternInfo; - folderQueries?: IFolderQuery[]; + folderQueries?: IFolderQuery[]; usingSearchPaths?: boolean; } +export type ISearchQuery = ISearchQueryProps; +export type IRawSearchQuery = ISearchQueryProps; + export enum QueryType { File = 1, Text = 2 diff --git a/src/vs/workbench/api/electron-browser/mainThreadSearch.ts b/src/vs/workbench/api/electron-browser/mainThreadSearch.ts index 7cb5254028ff0..eb9ada8b63811 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSearch.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSearch.ts @@ -73,7 +73,6 @@ class RemoteSearchProvider implements ISearchResultProvider { private readonly _registrations: IDisposable[]; private readonly _searches = new Map(); - constructor( searchService: ISearchService, private readonly _scheme: string, @@ -93,15 +92,12 @@ class RemoteSearchProvider implements ISearchResultProvider { return PPromise.as(undefined); } - let includes = { ...query.includePattern }; - let excludes = { ...query.excludePattern }; + const folderQueriesForScheme = query.folderQueries.filter(fq => fq.folder.scheme === this._scheme); - for (const folderQuery of query.folderQueries) { - if (folderQuery.folder.scheme === this._scheme) { - includes = { ...includes, ...folderQuery.includePattern }; - excludes = { ...excludes, ...folderQuery.excludePattern }; - } - } + query = { + ...query, + folderQueries: folderQueriesForScheme + }; let outer: TPromise; @@ -112,7 +108,7 @@ class RemoteSearchProvider implements ISearchResultProvider { outer = query.type === QueryType.File ? this._proxy.$provideFileSearchResults(this._handle, search.id, query.filePattern) - : this._proxy.$provideTextSearchResults(this._handle, search.id, query.contentPattern, query, { excludes: Object.keys(excludes), includes: Object.keys(includes) }); + : this._proxy.$provideTextSearchResults(this._handle, search.id, query.contentPattern, query); outer.then(() => { this._searches.delete(search.id); @@ -146,3 +142,20 @@ class RemoteSearchProvider implements ISearchResultProvider { this._searches.get(session).addMatch(resource, match); } } + +// function createRawSearchQuery(query: ISearchQuery): IRawSearchQuery { +// return { +// contentPattern: query.contentPattern, +// disregardExcludeSettings: query.disregardExcludeSettings, +// disregardIgnoreFiles: query.disregardIgnoreFiles, +// excludePattern: query.excludePattern, +// extraFileResources: query.extraFileResources, +// fileEncoding: query.fileEncoding, +// folderQueries: query.folderQueries.map(fq => { +// const rawFq: IFolderQuery = { ...fq }; +// rawFq.folder = fq.folder.toJSON(); +// return rawFq; +// }), +// type: query.type +// } +// } \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 564922457e28b..f08e3609affd6 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -46,7 +46,7 @@ import { IStat, FileChangeType, FileOpenFlags, IWatchOptions, FileSystemProvider import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { CommentRule, CharacterPair, EnterAction } from 'vs/editor/common/modes/languageConfiguration'; import { ISingleEditOperation } from 'vs/editor/common/model'; -import { ILineMatch, IPatternInfo, ISearchQuery } from 'vs/platform/search/common/search'; +import { ILineMatch, IPatternInfo, IRawSearchQuery } from 'vs/platform/search/common/search'; import { LogLevel } from 'vs/platform/log/common/log'; import { TaskExecutionDTO, TaskDTO, TaskHandleDTO } from 'vs/workbench/api/shared/tasks'; @@ -592,7 +592,7 @@ export interface ExtHostFileSystemShape { export interface ExtHostSearchShape { $provideFileSearchResults(handle: number, session: number, query: string): TPromise; - $provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, query: ISearchQuery, options: { includes: string[], excludes: string[] }): TPromise; + $provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, query: IRawSearchQuery): TPromise; } export interface ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index 10e8d57599315..34e919bfa5e40 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -6,9 +6,10 @@ import { asWinJsPromise } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IPatternInfo, ISearchQuery } from 'vs/platform/search/common/search'; +import { IPatternInfo, IFolderQuery, IRawSearchQuery } from 'vs/platform/search/common/search'; import * as vscode from 'vscode'; import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from './extHost.protocol'; +import URI, { UriComponents } from 'vs/base/common/uri'; export class ExtHostSearch implements ExtHostSearchShape { @@ -45,16 +46,36 @@ export class ExtHostSearch implements ExtHostSearchShape { return asWinJsPromise(token => provider.provideFileSearchResults(query, progress, token)); } - $provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, query: ISearchQuery, options: { includes: string[], excludes: string[] }): TPromise { + $provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, query: IRawSearchQuery): TPromise { + return TPromise.join( + query.folderQueries.map(fq => this.provideTextSearchResultsForFolder(handle, session, pattern, query, fq)) + ).then( + () => { }, + (err: Error[]) => { + return TPromise.wrapError(err[0]); + }); + } + + private provideTextSearchResultsForFolder(handle: number, session: number, pattern: IPatternInfo, query: IRawSearchQuery, folderQuery: IFolderQuery): TPromise { const provider = this._searchProvider.get(handle); if (!provider.provideTextSearchResults) { return TPromise.as(undefined); } + const includes: string[] = query.includePattern ? Object.keys(query.includePattern) : []; + if (folderQuery.includePattern) { + includes.push(...Object.keys(folderQuery.includePattern)); + } + + const excludes: string[] = query.excludePattern ? Object.keys(query.excludePattern) : []; + if (folderQuery.excludePattern) { + excludes.push(...Object.keys(folderQuery.excludePattern)); + } + const searchOptions: vscode.TextSearchOptions = { - folder: query.folderQueries[0].folder, - excludes: options.excludes, - includes: options.includes, + folder: URI.from(folderQuery.folder), + excludes, + includes, disregardIgnoreFiles: query.disregardIgnoreFiles, ignoreSymlinks: query.ignoreSymlinks, encoding: query.fileEncoding diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 7f8387e9d2980..38ba1302a8f3a 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -40,7 +40,7 @@ export class SearchService implements IRawSearchService { public textSearch(config: IRawSearch): PPromise { return config.useRipgrep ? - this.ripgrepTextSearch(config) : + PPromise.wrap({ limitHit: false, stats: null }) : this.legacyTextSearch(config); }