From 7683cb4bf438c46fa93491e232d7934fd23f5bf4 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 18 Apr 2018 21:43:37 -0700 Subject: [PATCH] Transition combined include/exclude patterns back to split include/exclude boxes For #46315 --- .../parts/search/browser/searchView.ts | 37 +++++++++++++-- .../parts/search/common/queryBuilder.ts | 22 +++++++++ .../search/test/common/queryBuilder.test.ts | 45 +++++++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/search/browser/searchView.ts b/src/vs/workbench/parts/search/browser/searchView.ts index 1a1e0f46fd3..dccdd36adcd 100644 --- a/src/vs/workbench/parts/search/browser/searchView.ts +++ b/src/vs/workbench/parts/search/browser/searchView.ts @@ -183,14 +183,43 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { this.createSearchWidget(this.searchWidgetsContainer); const filePatterns = this.viewletSettings['query.filePatterns'] || ''; - const patternExclusions = this.viewletSettings['query.folderExclusions'] || ''; - const patternExclusionsHistory = this.viewletSettings['query.folderExclusionsHistory'] || []; - const patternIncludes = this.viewletSettings['query.folderIncludes'] || ''; - const patternIncludesHistory = this.viewletSettings['query.folderIncludesHistory'] || []; + let patternExclusions = this.viewletSettings['query.folderExclusions'] || ''; + const patternExclusionsHistory: string[] = this.viewletSettings['query.folderExclusionsHistory'] || []; + let patternIncludes = this.viewletSettings['query.folderIncludes'] || ''; + let patternIncludesHistory: string[] = this.viewletSettings['query.folderIncludesHistory'] || []; const queryDetailsExpanded = this.viewletSettings['query.queryDetailsExpanded'] || ''; const useExcludesAndIgnoreFiles = typeof this.viewletSettings['query.useExcludesAndIgnoreFiles'] === 'boolean' ? this.viewletSettings['query.useExcludesAndIgnoreFiles'] : true; + // Transition history from 1.22 combined include+exclude, to split include/exclude histories + const patternIncludesHistoryWithoutExcludes: string[] = []; + const patternExcludesHistoryFromIncludes: string[] = []; + patternIncludesHistory.forEach(historyEntry => { + const includeExclude = this.queryBuilder.parseIncludeExcludePattern(historyEntry); + if (includeExclude.includePattern) { + patternIncludesHistoryWithoutExcludes.push(includeExclude.includePattern); + } + + if (includeExclude.excludePattern) { + patternExcludesHistoryFromIncludes.push(includeExclude.excludePattern); + } + }); + + patternIncludesHistory = patternIncludesHistoryWithoutExcludes; + patternExclusionsHistory.push(...patternExcludesHistoryFromIncludes); + + // Split combined include/exclude to split include/exclude boxes + const includeExclude = this.queryBuilder.parseIncludeExcludePattern(patternIncludes); + patternIncludes = includeExclude.includePattern || ''; + + if (includeExclude.excludePattern) { + if (patternExclusions) { + patternExclusions += ', ' + includeExclude.excludePattern; + } else { + patternExclusions = includeExclude.excludePattern; + } + } + this.queryDetails = this.searchWidgetsContainer.div({ 'class': ['query-details'] }, (builder) => { builder.div({ 'class': 'more', 'tabindex': 0, 'role': 'button', 'title': nls.localize('moreSearch', "Toggle Search Details") }) .on(dom.EventType.CLICK, (e) => { diff --git a/src/vs/workbench/parts/search/common/queryBuilder.ts b/src/vs/workbench/parts/search/common/queryBuilder.ts index 417c6bdac24..d0a998f9117 100644 --- a/src/vs/workbench/parts/search/common/queryBuilder.ts +++ b/src/vs/workbench/parts/search/common/queryBuilder.ts @@ -182,6 +182,28 @@ export class QueryBuilder { return Object.keys(excludeExpression).length ? excludeExpression : undefined; } + /** + * A helper that splits positive and negative patterns from a string that combines both. + */ + public parseIncludeExcludePattern(pattern: string): { includePattern?: string, excludePattern?: string } { + const grouped = collections.groupBy( + splitGlobPattern(pattern), + s => strings.startsWith(s, '!') ? 'excludePattern' : 'includePattern'); + + const result = {}; + if (grouped.includePattern) { + result['includePattern'] = grouped.includePattern.join(', '); + } + + if (grouped.excludePattern) { + result['excludePattern'] = grouped.excludePattern + .map(s => strings.ltrim(s, '!')) + .join(', '); + } + + return result; + } + private mergeExcludesFromFolderQueries(folderQueries: IFolderQuery[]): glob.IExpression | undefined { const mergedExcludes = folderQueries.reduce((merged: glob.IExpression, fq: IFolderQuery) => { if (fq.excludePattern) { diff --git a/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts b/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts index bb9e17f68f0..4ae1b1a4faf 100644 --- a/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts +++ b/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts @@ -697,6 +697,51 @@ suite('QueryBuilder', () => { assert(query.sortByScore); }); }); + + suite('parseIncludeExcludePattern', () => { + test('nothing', () => { + assert.deepEqual( + queryBuilder.parseIncludeExcludePattern(''), + {}); + }); + + test('includes', () => { + assert.deepEqual( + queryBuilder.parseIncludeExcludePattern('src'), + { + includePattern: 'src' + }); + + assert.deepEqual( + queryBuilder.parseIncludeExcludePattern('src, test'), + { + includePattern: 'src, test' + }); + }); + + test('excludes', () => { + assert.deepEqual( + queryBuilder.parseIncludeExcludePattern('!src'), + { + excludePattern: 'src' + }); + + assert.deepEqual( + queryBuilder.parseIncludeExcludePattern('!src, !test'), + { + excludePattern: 'src, test' + }); + }); + + test('includes and excludes', () => { + assert.deepEqual( + queryBuilder.parseIncludeExcludePattern('!src, test, !foo, bar'), + { + includePattern: 'test, bar', + excludePattern: 'src, foo' + }); + }); + }); }); function assertEqualQueries(actual: ISearchQuery, expected: ISearchQuery): void { -- GitLab