提交 06960b0c 编写于 作者: R Rob Lourens

Support excluding ./ and / paths in search viewlet - fixes #31492

上级 e5d86bce
......@@ -23,7 +23,7 @@ export interface ISearchPathPattern {
export interface ISearchPathsResult {
searchPaths?: ISearchPathPattern[];
includePattern?: glob.IExpression;
pattern?: glob.IExpression;
}
export class QueryBuilder {
......@@ -42,8 +42,8 @@ export class QueryBuilder {
}
private query(type: QueryType, contentPattern: IPatternInfo, folderResources?: uri[], options: IQueryOptions = {}): ISearchQuery {
let { searchPaths, includePattern } = this.parseSearchPaths(options.includePattern);
let excludePattern = patternListToIExpression(splitGlobPattern(options.excludePattern));
let { searchPaths, pattern: includePattern } = this.parseSearchPaths(options.includePattern);
let excludePattern = this.parseExcludePattern(options.excludePattern);
// Build folderQueries from searchPaths, if given, otherwise folderResources
let folderQueries = folderResources && folderResources.map(uri => this.getFolderQueryForRoot(uri, options));
......@@ -111,12 +111,37 @@ export class QueryBuilder {
const includePattern = patternListToIExpression(exprSegments);
if (includePattern) {
result.includePattern = includePattern;
result.pattern = includePattern;
}
return result;
}
/**
* Takes the input from the excludePattern as seen in the searchViewlet. Runs the same algorithm as parseSearchPaths,
* but the result is a single IExpression that encapsulates all the exclude patterns.
*/
public parseExcludePattern(pattern: string): glob.IExpression | undefined {
const result = this.parseSearchPaths(pattern);
let excludeExpression = glob.getEmptyExpression();
if (result.pattern) {
excludeExpression = objects.mixin(excludeExpression, result.pattern);
}
if (result.searchPaths) {
result.searchPaths.forEach(searchPath => {
const excludeFsPath = searchPath.searchPath.fsPath;
const excludePath = searchPath.pattern ?
paths.join(excludeFsPath, searchPath.pattern) :
excludeFsPath;
excludeExpression[excludePath] = true;
});
}
return Object.keys(excludeExpression).length ? excludeExpression : undefined;
}
private mergeExcludesFromFolderQueries(folderQueries: IFolderQuery[]): glob.IExpression | undefined {
const mergedExcludes = folderQueries.reduce((merged: glob.IExpression, fq: IFolderQuery) => {
if (fq.excludePattern) {
......@@ -181,11 +206,11 @@ export class QueryBuilder {
}
const workspace = this.workspaceContextService.getWorkspace();
if (searchPath === './') {
return [];
} else if (workspace.roots.length === 1) {
if (workspace.roots.length === 1) {
return [paths.normalize(
paths.join(workspace.roots[0].fsPath, searchPath))];
} else if (searchPath === './') {
return []; // ./ or ./**/foo makes sense for single-root but not multiroot
} else {
const relativeSearchPathMatch = searchPath.match(/\.\/([^\/]+)(\/.+)?/);
if (relativeSearchPathMatch) {
......
......@@ -187,13 +187,65 @@ suite('QueryBuilder', () => {
);
});
test('simple exclude input pattern', () => {
assertEqualQueries(
queryBuilder.text(
PATTERN_INFO,
[ROOT_1_URI],
{ excludePattern: 'foo' }
),
<ISearchQuery>{
contentPattern: PATTERN_INFO,
folderQueries: [{
folder: ROOT_1_URI
}],
type: QueryType.Text,
excludePattern: patternsToIExpression(globalGlob('foo')),
useRipgrep: true
});
});
test('exclude ./ syntax', () => {
assertEqualQueries(
queryBuilder.text(
PATTERN_INFO,
[ROOT_1_URI],
{ excludePattern: './bar' }
),
<ISearchQuery>{
contentPattern: PATTERN_INFO,
folderQueries: [{
folder: ROOT_1_URI
}],
excludePattern: patternsToIExpression(paths.join(ROOT_1, 'bar')),
type: QueryType.Text,
useRipgrep: true
});
assertEqualQueries(
queryBuilder.text(
PATTERN_INFO,
[ROOT_1_URI],
{ excludePattern: './bar/**/*.ts' }
),
<ISearchQuery>{
contentPattern: PATTERN_INFO,
folderQueries: [{
folder: ROOT_1_URI
}],
excludePattern: patternsToIExpression(paths.join(ROOT_1, 'bar/**/*.ts')),
type: QueryType.Text,
useRipgrep: true
});
});
suite('parseSearchPaths', () => {
test('simple includes', () => {
function testSimpleIncludes(includePattern: string, expectedPatterns: string[]): void {
assert.deepEqual(
queryBuilder.parseSearchPaths(includePattern),
<ISearchPathsResult>{
includePattern: patternsToIExpression(...expectedPatterns.map(globalGlob))
pattern: patternsToIExpression(...expectedPatterns.map(globalGlob))
},
includePattern);
}
......@@ -231,7 +283,7 @@ suite('QueryBuilder', () => {
fixPath('/foo/bar') + ',' + 'a',
<ISearchPathsResult>{
searchPaths: [{ searchPath: getUri('/foo/bar') }],
includePattern: patternsToIExpression(globalGlob('a'))
pattern: patternsToIExpression(globalGlob('a'))
}
],
[
......@@ -464,7 +516,7 @@ function assertEqualQueries(actual: ISearchQuery, expected: ISearchQuery): void
function assertEqualSearchPathResults(actual: ISearchPathsResult, expected: ISearchPathsResult, message?: string): void {
cleanUndefinedQueryValues(actual);
assert.deepEqual(actual.includePattern, expected.includePattern, message);
assert.deepEqual(actual.pattern, expected.pattern, message);
assert.equal(actual.searchPaths && actual.searchPaths.length, expected.searchPaths && expected.searchPaths.length);
if (actual.searchPaths) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册