From 9bbd4493b1b76b8f74c032edf1c3b03fd3aef4ac Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 24 Jul 2017 20:26:43 -0700 Subject: [PATCH] Implement search include/exclude precedence per #27226 --- .../services/search/node/ripgrepTextSearch.ts | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts index 6c8ea877d778b..437c1ab2f004a 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts @@ -11,6 +11,7 @@ import { StringDecoder, NodeStringDecoder } from 'string_decoder'; import * as cp from 'child_process'; import { rgPath } from 'vscode-ripgrep'; +import arrays = require('vs/base/common/arrays'); import objects = require('vs/base/common/objects'); import platform = require('vs/base/common/platform'); import * as strings from 'vs/base/common/strings'; @@ -382,15 +383,27 @@ export class LineMatch implements ILineMatch { interface IRgGlobResult { globArgs: string[]; - siblingClauses: glob.IExpression; + siblingClauses?: glob.IExpression; } -function foldersToRgExcludeGlobs(folderQueries: IFolderSearch[], globalExclude: glob.IExpression): IRgGlobResult { +function foldersToRgExcludeGlobs(folderQueries: IFolderSearch[]): IRgGlobResult { + return foldersToRgGlobs(folderQueries, fq => fq.excludePattern); +} + +function foldersToRgIncludeGlobs(folderQueries: IFolderSearch[], globalInclude: glob.IExpression): IRgGlobResult { + return foldersToRgGlobs(folderQueries, fq => objects.assign({}, fq.includePattern || {}, globalInclude || {})); +} + +function foldersToRgGlobalExcludeGlobs(folderQueries: IFolderSearch[], globalExclude: glob.IExpression): IRgGlobResult { + return foldersToRgGlobs(folderQueries, () => globalExclude); +} + +function foldersToRgGlobs(folderQueries: IFolderSearch[], patternProvider: (fs: IFolderSearch) => glob.IExpression): IRgGlobResult { const globArgs: string[] = []; let siblingClauses: glob.IExpression = {}; folderQueries.forEach(folderQuery => { - const totalExcludePattern = objects.assign({}, globalExclude || {}, folderQuery.excludePattern || {}); - const result = globExprsToRgGlobs(totalExcludePattern, folderQuery.folder); + const pattern = patternProvider(folderQuery); + const result = globExprsToRgGlobs(pattern, folderQuery.folder); globArgs.push(...result.globArgs); if (result.siblingClauses) { siblingClauses = objects.assign(siblingClauses, result.siblingClauses); @@ -400,17 +413,6 @@ function foldersToRgExcludeGlobs(folderQueries: IFolderSearch[], globalExclude: return { globArgs, siblingClauses }; } -function foldersToIncludeGlobs(folderQueries: IFolderSearch[], globalInclude: glob.IExpression): string[] { - const globArgs = []; - folderQueries.forEach(folderQuery => { - const totalIncludePattern = objects.assign({}, globalInclude || {}, folderQuery.includePattern || {}); - const result = globExprsToRgGlobs(totalIncludePattern, folderQuery.folder); - globArgs.push(...result.globArgs); - }); - - return globArgs; -} - function globExprsToRgGlobs(patterns: glob.IExpression, folder: string): IRgGlobResult { const globArgs: string[] = []; let siblingClauses: glob.IExpression = null; @@ -454,16 +456,22 @@ function getRgArgs(config: IRawSearch): IRgGlobResult { const args = ['--hidden', '--heading', '--line-number', '--color', 'ansi', '--colors', 'path:none', '--colors', 'line:none', '--colors', 'match:fg:red', '--colors', 'match:style:nobold']; args.push(config.contentPattern.isCaseSensitive ? '--case-sensitive' : '--ignore-case'); - // includePattern can't have siblingClauses - foldersToIncludeGlobs(config.folderQueries, config.includePattern).forEach(globArg => { - args.push('-g', globArg); - }); + const globsToGlobArgs = (globArgs: string[]) => arrays.flatten(globArgs.map(arg => ['-g', arg])); + const globToNotGlob = (glob: string) => '!' + glob; - let siblingClauses: glob.IExpression; - const rgGlobs = foldersToRgExcludeGlobs(config.folderQueries, config.excludePattern); - rgGlobs.globArgs - .forEach(rgGlob => args.push('-g', `!${rgGlob}`)); - siblingClauses = rgGlobs.siblingClauses; + // Include/exclude precedence: + // settings exclude < global include < global exclude + const excludeResult = foldersToRgExcludeGlobs(config.folderQueries); + args.push(...globsToGlobArgs(excludeResult.globArgs.map(globToNotGlob))); + + const includeResult = foldersToRgIncludeGlobs(config.folderQueries, config.includePattern); + args.push(...globsToGlobArgs(includeResult.globArgs)); + + const globalExcludeResult = foldersToRgGlobalExcludeGlobs(config.folderQueries, config.excludePattern); + args.push(...globsToGlobArgs(globalExcludeResult.globArgs.map(globToNotGlob))); + + // includePattern can't have siblingClauses + const siblingClauses = excludeResult.siblingClauses; if (config.maxFilesize) { args.push('--max-filesize', config.maxFilesize + '');