diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index 3bdd68f2fbed02ef321caa7b3a73a9b0571ad35e..6b9887e0330edd36b1da915bd13a21dade359a3a 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -37,6 +37,7 @@ export interface IQueryOptions { fileEncoding?: string; useRipgrep?: boolean; useIgnoreFiles?: boolean; + useExcludeSettings?: boolean; } export interface ISearchQuery extends IQueryOptions { diff --git a/src/vs/workbench/parts/search/browser/media/searchviewlet.css b/src/vs/workbench/parts/search/browser/media/searchviewlet.css index 5288f56d87bbdaf7462cafd6e38135168d7705b6..bf46f7ca54884310b0115fc667bfb39567090297 100644 --- a/src/vs/workbench/parts/search/browser/media/searchviewlet.css +++ b/src/vs/workbench/parts/search/browser/media/searchviewlet.css @@ -310,6 +310,15 @@ background-size: 18px 18px; } +.vs .monaco-workbench .search-viewlet .query-details .file-types .controls>.custom-checkbox.useExcludeSettings { + background: url('configure.svg') center center no-repeat; +} + +.vs-dark .monaco-workbench .search-viewlet .query-details .file-types .controls>.custom-checkbox.useExcludeSettings, +.hc-black .monaco-workbench .search-viewlet .query-details .file-types .controls>.custom-checkbox.useExcludeSettings { + background: url('configure-inverse.svg') center center no-repeat; +} + .search-viewlet .findInFileMatch, .monaco-editor .findInFileMatch { background-color: rgba(234, 92, 0, 0.3); diff --git a/src/vs/workbench/parts/search/browser/patternInputWidget.ts b/src/vs/workbench/parts/search/browser/patternInputWidget.ts index cf33558d23c2d63921d6c8bc19e70d3794757dac..83a0ca76b6017ec66cbedab0cf581a39a049b647 100644 --- a/src/vs/workbench/parts/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/parts/search/browser/patternInputWidget.ts @@ -31,22 +31,21 @@ export class PatternInputWidget extends Widget { public inputFocusTracker: dom.IFocusTracker; - private onOptionChange: (event: Event) => void; + protected onOptionChange: (event: Event) => void; private width: number; private placeholder: string; private ariaLabel: string; private pattern: Checkbox; - private useIgnoreFilesBox: Checkbox; private domNode: HTMLElement; private inputNode: HTMLInputElement; - private inputBox: InputBox; + protected inputBox: InputBox; private _onSubmit = this._register(new Emitter()); public onSubmit: CommonEvent = this._onSubmit.event; - constructor(parent: HTMLElement, private contextViewProvider: IContextViewProvider, private themeService: IThemeService, options: IOptions = Object.create(null), private showUseIgnoreFiles = false) { + constructor(parent: HTMLElement, private contextViewProvider: IContextViewProvider, private themeService: IThemeService, options: IOptions = Object.create(null)) { super(); this.onOptionChange = null; this.width = options.width || 100; @@ -54,7 +53,6 @@ export class PatternInputWidget extends Widget { this.ariaLabel = options.ariaLabel || nls.localize('defaultLabel', "input"); this.pattern = null; - this.useIgnoreFilesBox = null; this.domNode = null; this.inputNode = null; this.inputBox = null; @@ -67,7 +65,6 @@ export class PatternInputWidget extends Widget { public dispose(): void { super.dispose(); this.pattern.dispose(); - this.useIgnoreFilesBox.dispose(); if (this.inputFocusTracker) { this.inputFocusTracker.dispose(); } @@ -141,27 +138,20 @@ export class PatternInputWidget extends Widget { return this.inputBox.hasFocus(); } - public useIgnoreFiles(): boolean { - return this.useIgnoreFilesBox.checked; - } - - public setUseIgnoreFiles(value: boolean): void { - this.useIgnoreFilesBox.checked = value; - this.setInputWidth(); - } - public isGlobPattern(): boolean { return this.pattern.checked; } public setIsGlobPattern(value: boolean): void { this.pattern.checked = value; - this.setInputWidth(); } private setInputWidth(): void { - let w = this.width - this.pattern.width() - this.useIgnoreFilesBox.width(); - this.inputBox.width = w; + this.inputBox.width = this.width - this.getSubcontrolsWidth(); + } + + protected getSubcontrolsWidth(): number { + return this.pattern.width(); } private render(): void { @@ -190,7 +180,6 @@ export class PatternInputWidget extends Widget { if (!viaKeyboard) { this.inputBox.focus(); } - this.setInputWidth(); if (this.isGlobPattern()) { this.showGlobHelp(); @@ -200,19 +189,6 @@ export class PatternInputWidget extends Widget { } }); - this.useIgnoreFilesBox = new Checkbox({ - actionClassName: 'useIgnoreFiles', - title: nls.localize('useIgnoreFilesDescription', "Use Ignore Files"), - isChecked: false, - onChange: (viaKeyboard) => { - this.onOptionChange(null); - if (!viaKeyboard) { - this.inputBox.focus(); - } - this.setInputWidth(); - } - }); - $(this.pattern.domNode).on('mouseover', () => { if (this.isGlobPattern()) { this.showGlobHelp(); @@ -223,17 +199,16 @@ export class PatternInputWidget extends Widget { this.inputBox.hideMessage(); }); - this.setInputWidth(); - let controls = document.createElement('div'); controls.className = 'controls'; - if (this.showUseIgnoreFiles) { - controls.appendChild(this.useIgnoreFilesBox.domNode); - } - - controls.appendChild(this.pattern.domNode); + this.renderSubcontrols(controls); this.domNode.appendChild(controls); + this.setInputWidth(); + } + + protected renderSubcontrols(controlsDiv: HTMLDivElement): void { + controlsDiv.appendChild(this.pattern.domNode); } private showGlobHelp(): void { @@ -255,4 +230,66 @@ export class PatternInputWidget extends Widget { return; } } +} + +export class ExcludePatternInputWidget extends PatternInputWidget { + + private useIgnoreFilesBox: Checkbox; + private useExcludeSettingsBox: Checkbox; + + public dispose(): void { + super.dispose(); + this.useIgnoreFilesBox.dispose(); + this.useExcludeSettingsBox.dispose(); + } + + public useExcludeSettings(): boolean { + return this.useExcludeSettingsBox.checked; + } + + public setUseExcludeSettings(value: boolean) { + this.useExcludeSettingsBox.checked = value; + } + + public useIgnoreFiles(): boolean { + return this.useIgnoreFilesBox.checked; + } + + public setUseIgnoreFiles(value: boolean): void { + this.useIgnoreFilesBox.checked = value; + } + + protected getSubcontrolsWidth(): number { + return super.getSubcontrolsWidth() + this.useIgnoreFilesBox.width() + this.useExcludeSettingsBox.width(); + } + + protected renderSubcontrols(controlsDiv: HTMLDivElement): void { + this.useIgnoreFilesBox = new Checkbox({ + actionClassName: 'useIgnoreFiles', + title: nls.localize('useIgnoreFilesDescription', "Use Ignore Files"), + isChecked: false, + onChange: (viaKeyboard) => { + this.onOptionChange(null); + if (!viaKeyboard) { + this.inputBox.focus(); + } + } + }); + + this.useExcludeSettingsBox = new Checkbox({ + actionClassName: 'useExcludeSettings', + title: nls.localize('useExcludeSettingsDescription', "Use Exclude Settings"), + isChecked: false, + onChange: (viaKeyboard) => { + this.onOptionChange(null); + if (!viaKeyboard) { + this.inputBox.focus(); + } + } + }); + + controlsDiv.appendChild(this.useIgnoreFilesBox.domNode); + controlsDiv.appendChild(this.useExcludeSettingsBox.domNode); + super.renderSubcontrols(controlsDiv); + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index 8369a8574a53d9c8a950fcaffef031987c935a9d..0b973e895cc040f03ac7b33d83a67ab2cc430c61 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -48,7 +48,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { PatternInputWidget } from 'vs/workbench/parts/search/browser/patternInputWidget'; +import { PatternInputWidget, ExcludePatternInputWidget } from 'vs/workbench/parts/search/browser/patternInputWidget'; import { SearchRenderer, SearchDataSource, SearchSorter, SearchController, SearchAccessibilityProvider, SearchFilter } from 'vs/workbench/parts/search/browser/searchResultsView'; import { SearchWidget } from 'vs/workbench/parts/search/browser/searchWidget'; import { RefreshAction, CollapseAllAction, ClearSearchResultsAction, ConfigureGlobalExclusionsAction } from 'vs/workbench/parts/search/browser/searchActions'; @@ -86,7 +86,7 @@ export class SearchViewlet extends Viewlet { private searchWidget: SearchWidget; private size: Dimension; private queryDetails: HTMLElement; - private inputPatternExclusions: PatternInputWidget; + private inputPatternExclusions: ExcludePatternInputWidget; private inputPatternGlobalExclusions: InputBox; private inputPatternGlobalExclusionsContainer: Builder; private inputPatternIncludes: PatternInputWidget; @@ -167,6 +167,9 @@ export class SearchViewlet extends Viewlet { const useIgnoreFiles = typeof this.viewletSettings['query.useIgnoreFiles'] === 'boolean' ? this.viewletSettings['query.useIgnoreFiles'] : this.configurationService.getConfiguration().search.useIgnoreFilesByDefault; + const useExcludeSettings = typeof this.viewletSettings['query.useExcludeSettings'] === 'boolean' ? + this.viewletSettings['query.useExcludeSettings'] : + true; this.queryDetails = this.searchWidgetsContainer.div({ 'class': ['query-details'] }, (builder) => { builder.div({ 'class': 'more', 'tabindex': 0, 'role': 'button', 'title': nls.localize('moreSearch', "Toggle Search Details") }) @@ -208,14 +211,14 @@ export class SearchViewlet extends Viewlet { let title = nls.localize('searchScope.excludes', "files to exclude"); builder.element('h4', { text: title }); - const configuration = this.configurationService.getConfiguration(); - this.inputPatternExclusions = new PatternInputWidget(builder.getContainer(), this.contextViewService, this.themeService, { + this.inputPatternExclusions = new ExcludePatternInputWidget(builder.getContainer(), this.contextViewService, this.themeService, { ariaLabel: nls.localize('label.excludes', 'Search Exclude Patterns') - }, configuration.search.useRipgrep); + }); this.inputPatternExclusions.setIsGlobPattern(exclusionsUsePattern); this.inputPatternExclusions.setValue(patternExclusions); this.inputPatternExclusions.setUseIgnoreFiles(useIgnoreFiles); + this.inputPatternExclusions.setUseExcludeSettings(useExcludeSettings); this.inputPatternExclusions .on(FindInput.OPTION_CHANGE, (e) => { @@ -908,6 +911,7 @@ export class SearchViewlet extends Viewlet { const patternIncludes = this.inputPatternIncludes.getValue().trim(); const includesUsePattern = this.inputPatternIncludes.isGlobPattern(); const useIgnoreFiles = this.inputPatternExclusions.useIgnoreFiles(); + const useExcludeSettings = this.inputPatternExclusions.useExcludeSettings(); // store memento this.viewletSettings['query.contentPattern'] = contentPattern; @@ -919,6 +923,7 @@ export class SearchViewlet extends Viewlet { this.viewletSettings['query.folderIncludes'] = patternIncludes; this.viewletSettings['query.includesUsePattern'] = includesUsePattern; this.viewletSettings['query.useIgnoreFiles'] = useIgnoreFiles; + this.viewletSettings['query.useExcludeSettings'] = useExcludeSettings; if (!rerunQuery) { return; @@ -942,23 +947,24 @@ export class SearchViewlet extends Viewlet { } } - let content = { + const content = { pattern: contentPattern, isRegExp: isRegex, isCaseSensitive: isCaseSensitive, isWordMatch: isWholeWords }; - let excludes: IExpression = this.inputPatternExclusions.getGlob(); - let includes: IExpression = this.inputPatternIncludes.getGlob(); + const excludes: IExpression = this.inputPatternExclusions.getGlob(); + const includes: IExpression = this.inputPatternIncludes.getGlob(); - let options: IQueryOptions = { + const options: IQueryOptions = { folderResources: this.contextService.hasWorkspace() ? [this.contextService.getWorkspace().resource] : [], extraFileResources: getOutOfWorkspaceEditorResources(this.editorGroupService, this.contextService), excludePattern: excludes, maxResults: SearchViewlet.MAX_TEXT_RESULTS, includePattern: includes, - useIgnoreFiles + useIgnoreFiles, + useExcludeSettings }; this.onQueryTriggered(this.queryBuilder.text(content, options), patternExcludes, patternIncludes); diff --git a/src/vs/workbench/parts/search/common/searchQuery.ts b/src/vs/workbench/parts/search/common/searchQuery.ts index 3ebbbce752800c33c721122f0179bae390bafdd1..c2b85a0470b00288b470cbd3d4e02c9fa517b264 100644 --- a/src/vs/workbench/parts/search/common/searchQuery.ts +++ b/src/vs/workbench/parts/search/common/searchQuery.ts @@ -24,11 +24,13 @@ export class QueryBuilder { private query(type: QueryType, contentPattern: IPatternInfo, options: IQueryOptions = {}): ISearchQuery { const configuration = this.configurationService.getConfiguration(); - const excludePattern = getExcludes(configuration); - if (!options.excludePattern) { - options.excludePattern = excludePattern; - } else { - mixin(options.excludePattern, excludePattern, false /* no overwrite */); + const settingsExcludePattern = getExcludes(configuration); + if (options.useExcludeSettings) { + if (options.excludePattern) { + mixin(options.excludePattern, settingsExcludePattern, false /* no overwrite */); + } else { + options.excludePattern = settingsExcludePattern; + } } return {