Fix exclude settings to be resolved against their root folder, not the searchPath, mainly for './' search scenarios

This commit is contained in:
Rob Lourens
2017-07-29 12:25:23 -07:00
parent 413f58826e
commit d618f0da4a
6 changed files with 58 additions and 11 deletions
+4
View File
@@ -15,6 +15,10 @@ export interface IExpression {
[pattern: string]: boolean | SiblingClause | any;
}
export function getEmptyExpression(): IExpression {
return Object.create(null);
}
export interface SiblingClause {
when: string;
}
@@ -6,7 +6,7 @@
import { isPromiseCanceledError } from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import { ISearchService, QueryType } from 'vs/platform/search/common/search';
import { ISearchService, QueryType, ISearchQuery } from 'vs/platform/search/common/search';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
@@ -56,13 +56,16 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape {
return undefined;
}
const search = this._searchService.search({
const query: ISearchQuery = {
folderQueries: workspace.roots.map(root => ({ folder: root })),
type: QueryType.File,
maxResults,
includePattern: { [include]: true },
excludePattern: { [exclude]: true },
}).then(result => {
};
this._searchService.extendQuery(query);
const search = this._searchService.search(query).then(result => {
return result.results.map(m => m.resource);
}, err => {
if (!isPromiseCanceledError(err)) {
@@ -45,9 +45,6 @@ export class QueryBuilder {
let { searchPaths, includePattern } = this.parseSearchPaths(options.includePattern);
let excludePattern = patternListToIExpression(splitGlobPattern(options.excludePattern));
// if we have searchPaths, then turn them into folderQueries, and get all the excludes for the workspaces, and add them to excludePattern.
// If we don't, then turn the folderResources into folderQueries, with their excludes on each one
// Build folderQueries from searchPaths, if given, otherwise folderResources
let folderQueries = folderResources && folderResources.map(uri => this.getFolderQueryForRoot(uri, options));
if (searchPaths && searchPaths.length) {
@@ -92,8 +92,6 @@ suite('QueryBuilder', () => {
});
test('simple include', () => {
mockConfigService.setUserConfiguration('search', { useRipgrep: true });
assertEqualQueries(
queryBuilder.text(
PATTERN_INFO,
@@ -142,7 +140,6 @@ suite('QueryBuilder', () => {
const ROOT_3_URI = getUri(ROOT_3);
mockWorkspace.roots = [ROOT_1_URI, ROOT_2_URI, ROOT_3_URI];
mockConfigService.setUserConfiguration('search', { useRipgrep: true });
mockConfigService.setUserConfiguration('search', {
useRipgrep: true,
exclude: { 'foo/**/*.js': true }
@@ -12,6 +12,7 @@ import fs = require('fs');
import path = require('path');
import { isEqualOrParent } from 'vs/base/common/paths';
import { Readable } from 'stream';
import { TPromise } from 'vs/base/common/winjs.base';
import scorer = require('vs/base/common/scorer');
import objects = require('vs/base/common/objects');
@@ -103,10 +104,34 @@ export class FileWalker {
}
});
this.folderExcludePatterns.set(folderQuery.folder, glob.parse(folderExcludeExpression, { trimForExclusions: true }));
this.folderExcludePatterns.set(folderQuery.folder, this.parseAbsoluteAndRelativeGlobs(folderExcludeExpression, folderQuery.folder));
});
}
private parseAbsoluteAndRelativeGlobs(expr: glob.IExpression, root: string): glob.ParsedExpression {
let absoluteGlobExpr: glob.IExpression;
let relativeGlobExpr: glob.IExpression;
Object.keys(expr).forEach(key => {
if (path.isAbsolute(key)) {
absoluteGlobExpr = absoluteGlobExpr || glob.getEmptyExpression();
absoluteGlobExpr[key] = true;
} else {
relativeGlobExpr = relativeGlobExpr || glob.getEmptyExpression();
relativeGlobExpr[key] = true;
}
});
const absoluteParsedExpr = absoluteGlobExpr && glob.parse(absoluteGlobExpr, { trimForExclusions: true });
const relativeParsedExpr = relativeGlobExpr && glob.parse(relativeGlobExpr, { trimForExclusions: true });
// The absolute and relative expressions don't "have" to be kept separate, but this keeps us from having to path.join every single
// file searched, it's only used for a text search with a searchPath
return (_path: string, basename?: string, siblingsFn?: () => string[] | TPromise<string[]>): string | TPromise<string> => {
return (relativeParsedExpr && relativeParsedExpr(_path, basename, siblingsFn)) ||
(absoluteParsedExpr && absoluteParsedExpr(path.join(root, _path), basename, siblingsFn));
};
}
public cancel(): void {
this.isCanceled = true;
}
@@ -88,7 +88,8 @@ function doRipgrepSearchTest(config: IRawSearch, expectedResultCount: number): T
}
function doSearchTest(config: IRawSearch, expectedResultCount: number, done) {
return doRipgrepSearchTest(config, expectedResultCount)
return doLegacySearchTest(config, expectedResultCount)
.then(() => doRipgrepSearchTest(config, expectedResultCount))
.then(done, done);
}
@@ -187,6 +188,26 @@ suite('Search-integration', function () {
doSearchTest(config, 382, done);
});
test('Text: e (with absolute path excludes)', function (done: () => void) {
const config: any = {
folderQueries: ROOT_FOLDER_QUERY,
contentPattern: { pattern: 'e' },
excludePattern: makeExpression(path.join(TEST_FIXTURES, '**/examples'))
};
doSearchTest(config, 394, done);
});
test('Text: e (with mixed absolute/relative path excludes)', function (done: () => void) {
const config: any = {
folderQueries: ROOT_FOLDER_QUERY,
contentPattern: { pattern: 'e' },
excludePattern: makeExpression(path.join(TEST_FIXTURES, '**/examples'), '*.css')
};
doSearchTest(config, 310, done);
});
test('Text: sibling exclude', function (done: () => void) {
const config: any = {
folderQueries: ROOT_FOLDER_QUERY,