提交 e0e9c3d4 编写于 作者: R Rob Lourens

Search provider - some clean up

上级 995ef296
......@@ -5,9 +5,9 @@
import * as path from 'path';
import * as vscode from 'vscode';
import * as arrays from './arrays';
import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from './fileSearchScorer';
import * as strings from './strings';
import * as arrays from './common/arrays';
import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from './common/fileSearchScorer';
import * as strings from './common/strings';
interface IProviderArgs {
query: vscode.FileSearchQuery;
......@@ -119,7 +119,7 @@ export class CachedSearchProvider {
const preparedQuery = prepareQuery(args.query.pattern);
const compare = (matchA: IInternalFileMatch, matchB: IInternalFileMatch) => compareItemsByScore(matchA, matchB, preparedQuery, true, FileMatchItemAccessor, scorerCache);
return arrays.topAsync(results, compare, args.options.maxResults, 10000);
return arrays.topAsync(results, compare, args.options.maxResults || 10000, 10000);
}
private getResultsFromCache(cache: Cache, searchValue: string, onResult: (results: IInternalFileMatch) => void): Promise<[IInternalFileMatch[], CacheStats]> {
......@@ -199,7 +199,7 @@ export class CachedSearchProvider {
}
};
provider.provideFileSearchResults(args.query, args.options, { report: onProviderResult }, args.token).then(() => {
provider.provideFileSearchResults(args.query, args.options, { report: onProviderResult }, args.token).then(() => {
if (batch.length) {
onResult(batch);
}
......
......@@ -72,4 +72,4 @@ export function findFirstInSorted<T>(array: T[], p: (x: T) => boolean): number {
}
}
return low;
}
\ No newline at end of file
}
......@@ -9,6 +9,13 @@ import * as strings from './strings';
let intlFileNameCollator: Intl.Collator;
let intlFileNameCollatorIsNumeric: boolean;
setFileNameComparer(new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }));
export function setFileNameComparer(collator: Intl.Collator): void {
intlFileNameCollator = collator;
intlFileNameCollatorIsNumeric = collator.resolvedOptions().numeric;
}
export function compareFileNames(one: string, other: string, caseSensitive = false): number {
if (intlFileNameCollator) {
const a = one || '';
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
* 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 { stripWildcards, equalsIgnoreCase } from './strings';
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
......
......@@ -17,7 +17,10 @@ export function activate(): void {
}
class RipgrepSearchProvider implements vscode.SearchProvider {
private cachedProvider: CachedSearchProvider;
constructor(private outputChannel: vscode.OutputChannel) {
this.cachedProvider = new CachedSearchProvider(this.outputChannel);
}
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
......@@ -26,8 +29,7 @@ class RipgrepSearchProvider implements vscode.SearchProvider {
}
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.SearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
const cachedProvider = new CachedSearchProvider(this.outputChannel);
const engine = new RipgrepFileSearch(this.outputChannel);
return cachedProvider.provideFileSearchResults(engine, query, options, progress, token);
return this.cachedProvider.provideFileSearchResults(engine, query, options, progress, token);
}
}
\ No newline at end of file
......@@ -7,7 +7,7 @@ import * as cp from 'child_process';
import { Readable } from 'stream';
import { NodeStringDecoder, StringDecoder } from 'string_decoder';
import * as vscode from 'vscode';
import { normalizeNFC, normalizeNFD } from './normalization';
import { normalizeNFC, normalizeNFD } from './common/normalization';
import { rgPath } from './ripgrep';
import { anchorGlob } from './ripgrepHelpers';
import { rgErrorMsgForDisplay } from './ripgrepTextSearch';
......
......@@ -28,7 +28,7 @@ declare module 'vscode' {
excludes: string[];
useIgnoreFiles?: boolean;
followSymlinks?: boolean;
maxResults: number;
maxResults?: number;
}
export interface TextSearchOptions extends SearchOptions {
......
......@@ -42,7 +42,11 @@ export class MainThreadSearch implements MainThreadSearchShape {
this._searchProvider.delete(handle);
}
$handleFindMatch(handle: number, session, data: UriComponents | IRawFileMatch2[]): void {
$handleFileMatch(handle: number, session, data: UriComponents[]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
}
$handleTextMatch(handle: number, session, data: IRawFileMatch2[]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
}
......@@ -134,22 +138,24 @@ class RemoteSearchProvider implements ISearchResultProvider {
});
}
handleFindMatch(session: number, dataOrUri: UriComponents | IRawFileMatch2[]): void {
handleFindMatch(session: number, dataOrUri: (UriComponents | IRawFileMatch2)[]): void {
if (!this._searches.has(session)) {
// ignore...
return;
}
const searchOp = this._searches.get(session);
if (Array.isArray(dataOrUri)) {
dataOrUri.forEach(m => {
dataOrUri.forEach(result => {
if ((<IRawFileMatch2>result).lineMatches) {
searchOp.addMatch({
resource: URI.revive(m.resource),
lineMatches: m.lineMatches
resource: URI.revive((<IRawFileMatch2>result).resource),
lineMatches: (<IRawFileMatch2>result).lineMatches
});
});
} else {
searchOp.addMatch({ resource: URI.revive(dataOrUri) });
}
} else {
searchOp.addMatch({
resource: URI.revive(result)
});
}
});
}
}
......@@ -483,7 +483,8 @@ export interface MainThreadFileSystemShape extends IDisposable {
export interface MainThreadSearchShape extends IDisposable {
$registerSearchProvider(handle: number, scheme: string): void;
$unregisterProvider(handle: number): void;
$handleFindMatch(handle: number, session: number, data: UriComponents | IRawFileMatch2[]): void;
$handleFileMatch(handle: number, session: number, data: UriComponents | UriComponents[]): void;
$handleTextMatch(handle: number, session: number, data: IRawFileMatch2[]): void;
$handleTelemetry(eventName: string, data: any): void;
}
......
......@@ -18,8 +18,6 @@ import { IFileMatch, IFolderQuery, IPatternInfo, IRawFileMatch2, IRawSearchQuery
import * as vscode from 'vscode';
import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from './extHost.protocol';
type OneOrMore<T> = T | T[];
export interface ISchemeTransformer {
transformOutgoing(scheme: string): string;
}
......@@ -67,13 +65,7 @@ export class ExtHostSearch implements ExtHostSearchShape {
null,
null,
progress => {
if (Array.isArray(progress)) {
progress.forEach(p => {
this._proxy.$handleFindMatch(handle, session, p.resource);
});
} else {
this._proxy.$handleFindMatch(handle, session, progress.resource);
}
this._proxy.$handleFileMatch(handle, session, progress.map(p => p.resource));
});
}
......@@ -89,7 +81,7 @@ export class ExtHostSearch implements ExtHostSearchShape {
null,
null,
progress => {
this._proxy.$handleFindMatch(handle, session, progress);
this._proxy.$handleTextMatch(handle, session, progress);
});
}
}
......@@ -512,16 +504,12 @@ class FileSearchEngine {
private includePattern: glob.ParsedExpression;
private maxResults: number;
private exists: boolean;
// private maxFilesize: number;
private isLimitHit: boolean;
private resultCount: number;
private isCanceled: boolean;
private activeCancellationTokens: Set<CancellationTokenSource>;
// private filesWalked: number;
// private directoriesWalked: number;
private globalExcludePattern: glob.ParsedExpression;
constructor(private config: ISearchQuery, private provider: vscode.SearchProvider, private _pfs: typeof pfs) {
......@@ -529,14 +517,10 @@ class FileSearchEngine {
this.includePattern = config.includePattern && glob.parse(config.includePattern);
this.maxResults = config.maxResults || null;
this.exists = config.exists;
// this.maxFilesize = config.maxFileSize || null;
this.resultCount = 0;
this.isLimitHit = false;
this.activeCancellationTokens = new Set<CancellationTokenSource>();
// this.filesWalked = 0;
// this.directoriesWalked = 0;
if (this.filePattern) {
this.normalizedFilePatternLowercase = strings.stripWildcards(this.filePattern).toLowerCase();
}
......@@ -644,7 +628,7 @@ class FileSearchEngine {
.then(() => {
this.activeCancellationTokens.add(cancellation);
return this.provider.provideFileSearchResults(
{ cacheKey: this.config.cacheKey, pattern: this.config.filePattern },
{ cacheKey: this.config.cacheKey, pattern: this.config.filePattern || '' },
options,
{ report: onProviderResult },
cancellation.token);
......@@ -736,7 +720,6 @@ class FileSearchEngine {
const self = this;
const filePattern = this.filePattern;
function matchDirectory(entries: IDirectoryEntry[]) {
// self.directoriesWalked++;
for (let i = 0, n = entries.length; i < n; i++) {
const entry = entries[i];
const { relativePath, basename } = entry;
......@@ -753,7 +736,6 @@ class FileSearchEngine {
if (sub) {
matchDirectory(sub);
} else {
// self.filesWalked++;
if (relativePath === filePattern) {
continue; // ignore file if its path matches with the file pattern because that is already matched above
}
......@@ -769,25 +751,9 @@ class FileSearchEngine {
matchDirectory(rootEntries);
}
public getStats(): any {
return null;
// return {
// fromCache: false,
// traversal: Traversal[this.traversal],
// errors: this.errors,
// fileWalkStartTime: this.fileWalkStartTime,
// fileWalkResultTime: Date.now(),
// directoriesWalked: this.directoriesWalked,
// filesWalked: this.filesWalked,
// resultCount: this.resultCount,
// cmdForkResultTime: this.cmdForkResultTime,
// cmdResultCount: this.cmdResultCount
// };
}
/**
* Return whether the file pattern is an absolute path to a file that exists.
* TODO@roblou should use FS provider?
* TODO@roblou delete to match fileSearch.ts
*/
private checkFilePatternAbsoluteMatch(): TPromise<{ exists: boolean, size?: number }> {
if (!this.filePattern || !path.isAbsolute(this.filePattern)) {
......@@ -859,16 +825,12 @@ class FileSearchManager {
constructor(private _pfs: typeof pfs) { }
public fileSearch(config: ISearchQuery, provider: vscode.SearchProvider): PPromise<ISearchCompleteStats, OneOrMore<IFileMatch>> {
public fileSearch(config: ISearchQuery, provider: vscode.SearchProvider): PPromise<ISearchCompleteStats, IFileMatch[]> {
let searchP: PPromise;
return new PPromise<ISearchCompleteStats, OneOrMore<IFileMatch>>((c, e, p) => {
return new PPromise<ISearchCompleteStats, IFileMatch[]>((c, e, p) => {
const engine = new FileSearchEngine(config, provider, this._pfs);
searchP = this.doSearch(engine, provider, FileSearchManager.BATCH_SIZE).then(c, e, progress => {
if (Array.isArray(progress)) {
p(progress.map(m => this.rawMatchToSearchItem(m)));
} else if ((<IInternalFileMatch>progress).relativePath) {
p(this.rawMatchToSearchItem(<IInternalFileMatch>progress));
}
p(progress.map(m => this.rawMatchToSearchItem(m)));
});
}, () => {
if (searchP) {
......@@ -883,8 +845,8 @@ class FileSearchManager {
};
}
private doSearch(engine: FileSearchEngine, provider: vscode.SearchProvider, batchSize?: number): PPromise<ISearchCompleteStats, OneOrMore<IInternalFileMatch>> {
return new PPromise<ISearchCompleteStats, OneOrMore<IInternalFileMatch>>((c, e, p) => {
private doSearch(engine: FileSearchEngine, provider: vscode.SearchProvider, batchSize: number): PPromise<ISearchCompleteStats, IInternalFileMatch[]> {
return new PPromise<ISearchCompleteStats, IInternalFileMatch[]>((c, e, p) => {
let batch: IInternalFileMatch[] = [];
engine.search().then(result => {
if (batch.length) {
......@@ -892,8 +854,7 @@ class FileSearchManager {
}
c({
limitHit: result.isLimitHit,
stats: engine.getStats() // TODO@roblou
limitHit: result.isLimitHit
});
}, error => {
if (batch.length) {
......@@ -903,14 +864,10 @@ class FileSearchManager {
e(error);
}, match => {
if (match) {
if (batchSize) {
batch.push(match);
if (batchSize > 0 && batch.length >= batchSize) {
p(batch);
batch = [];
}
} else {
p(match);
batch.push(match);
if (batchSize > 0 && batch.length >= batchSize) {
p(batch);
batch = [];
}
}
});
......
......@@ -155,7 +155,7 @@ suite('ExtHostSearch', () => {
test('no results', async () => {
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
return TPromise.wrap(null);
}
});
......@@ -173,7 +173,7 @@ suite('ExtHostSearch', () => {
];
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(path.basename(r.fsPath)));
return TPromise.wrap(null);
}
......@@ -188,7 +188,7 @@ suite('ExtHostSearch', () => {
test('Search canceled', async () => {
let cancelRequested = false;
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
return new TPromise((resolve, reject) => {
token.onCancellationRequested(() => {
cancelRequested = true;
......@@ -213,7 +213,7 @@ suite('ExtHostSearch', () => {
];
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(r));
throw new Error('I broke');
}
......@@ -229,7 +229,7 @@ suite('ExtHostSearch', () => {
test('provider returns null', async () => {
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
return null;
}
});
......@@ -244,7 +244,7 @@ suite('ExtHostSearch', () => {
test('all provider calls get global include/excludes', async () => {
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
assert(options.excludes.length === 2 && options.includes.length === 2, 'Missing global include/excludes');
return TPromise.wrap(null);
}
......@@ -273,7 +273,7 @@ suite('ExtHostSearch', () => {
test('global/local include/excludes combined', async () => {
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
if (options.folder.toString() === rootFolderA.toString()) {
assert.deepEqual(options.includes.sort(), ['*.ts', 'foo']);
assert.deepEqual(options.excludes.sort(), ['*.js', 'bar']);
......@@ -315,7 +315,7 @@ suite('ExtHostSearch', () => {
test('include/excludes resolved correctly', async () => {
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
assert.deepEqual(options.includes.sort(), ['*.jsx', '*.ts']);
assert.deepEqual(options.excludes.sort(), []);
......@@ -358,7 +358,7 @@ suite('ExtHostSearch', () => {
];
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
}
......@@ -389,7 +389,7 @@ suite('ExtHostSearch', () => {
test('multiroot sibling exclude clause', async () => {
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
let reportedResults;
if (options.folder.fsPath === rootFolderA.fsPath) {
reportedResults = [
......@@ -460,7 +460,7 @@ suite('ExtHostSearch', () => {
let wasCanceled = false;
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(path.basename(r.fsPath)));
token.onCancellationRequested(() => wasCanceled = true);
......@@ -497,7 +497,7 @@ suite('ExtHostSearch', () => {
let wasCanceled = false;
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(path.basename(r.fsPath)));
token.onCancellationRequested(() => wasCanceled = true);
......@@ -533,7 +533,7 @@ suite('ExtHostSearch', () => {
let wasCanceled = false;
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(path.basename(r.fsPath)));
token.onCancellationRequested(() => wasCanceled = true);
......@@ -564,7 +564,7 @@ suite('ExtHostSearch', () => {
test('multiroot max results', async () => {
let cancels = 0;
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
token.onCancellationRequested(() => cancels++);
// Provice results async so it has a chance to invoke every provider
......@@ -610,7 +610,7 @@ suite('ExtHostSearch', () => {
];
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(path.basename(r.fsPath)));
return TPromise.wrap(null);
}
......@@ -642,7 +642,7 @@ suite('ExtHostSearch', () => {
];
await registerTestSearchProvider({
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
reportedResults.forEach(r => progress.report(path.basename(r.fsPath)));
return TPromise.wrap(null);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册