From 8d666f34e6caff28ca1a1c983b78c3a662d0e319 Mon Sep 17 00:00:00 2001 From: Ryan Stringham Date: Mon, 29 May 2017 15:54:30 -0600 Subject: [PATCH] Add history navigation for file includes and excludes patterns in the search viewlet --- .../search/browser/patternInputWidget.ts | 31 +++++++++ .../search/browser/search.contribution.ts | 40 ++++++++++++ .../parts/search/browser/searchActions.ts | 64 +++++++++++++++++++ .../parts/search/browser/searchViewlet.ts | 24 ++++++- .../parts/search/common/constants.ts | 2 + 5 files changed, 158 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/search/browser/patternInputWidget.ts b/src/vs/workbench/parts/search/browser/patternInputWidget.ts index 17487587812..5c071d58847 100644 --- a/src/vs/workbench/parts/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/parts/search/browser/patternInputWidget.ts @@ -20,6 +20,7 @@ import CommonEvent, { Emitter } from 'vs/base/common/event'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachInputBoxStyler, attachCheckboxStyler } from 'vs/platform/theme/common/styler'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { HistoryNavigator } from 'vs/base/common/history'; export interface IOptions { placeholder?: string; @@ -45,11 +46,14 @@ export class PatternInputWidget extends Widget { private inputNode: HTMLInputElement; protected inputBox: InputBox; + private history: HistoryNavigator; + private _onSubmit = this._register(new Emitter()); public onSubmit: CommonEvent = this._onSubmit.event; constructor(parent: HTMLElement, private contextViewProvider: IContextViewProvider, protected themeService: IThemeService, options: IOptions = Object.create(null)) { super(); + this.history = new HistoryNavigator(); this.onOptionChange = null; this.width = options.width || 100; this.placeholder = options.placeholder || ''; @@ -185,6 +189,26 @@ export class PatternInputWidget extends Widget { return this.pattern.width(); } + public showNextTerm() { + let next = this.history.next(); + if (next) { + this.setValue(next); + } + } + + public showPreviousTerm() { + let previous; + if (this.getValue().length === 0) { + previous = this.history.current(); + } else { + this.history.addIfNotPresent(this.getValue()); + previous = this.history.previous(); + } + if (previous) { + this.setValue(previous); + } + } + private render(): void { this.domNode = document.createElement('div'); this.domNode.style.width = this.width + 'px'; @@ -221,6 +245,13 @@ export class PatternInputWidget extends Widget { }); this._register(attachCheckboxStyler(this.pattern, this.themeService)); + this._register(this.onSubmit(() => { + let value = this.getValue(); + if (value.length > 0) { + this.history.add(this.getValue()); + } + })); + $(this.pattern.domNode).on('mouseover', () => { if (this.isGlobPattern()) { this.showGlobHelp(); diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index 2627a97b70e..26d50d5eb30 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -140,6 +140,46 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: searchActions.ShowNextSearchIncludeAction.ID, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.PatternIncludesFocussedKey), + primary: ShowNextFindTermKeybinding.primary, + handler: (accessor, args: any) => { + accessor.get(IInstantiationService).createInstance(searchActions.ShowNextSearchIncludeAction, searchActions.ShowNextSearchIncludeAction.ID, '').run(); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: searchActions.ShowPreviousSearchIncludeAction.ID, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.PatternIncludesFocussedKey), + primary: ShowPreviousFindTermKeybinding.primary, + handler: (accessor, args: any) => { + accessor.get(IInstantiationService).createInstance(searchActions.ShowPreviousSearchIncludeAction, searchActions.ShowPreviousSearchIncludeAction.ID, '').run(); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: searchActions.ShowNextSearchExcludeAction.ID, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.PatternExcludesFocussedKey), + primary: ShowNextFindTermKeybinding.primary, + handler: (accessor, args: any) => { + accessor.get(IInstantiationService).createInstance(searchActions.ShowNextSearchExcludeAction, searchActions.ShowNextSearchExcludeAction.ID, '').run(); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: searchActions.ShowPreviousSearchExcludeAction.ID, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.PatternExcludesFocussedKey), + primary: ShowPreviousFindTermKeybinding.primary, + handler: (accessor, args: any) => { + accessor.get(IInstantiationService).createInstance(searchActions.ShowPreviousSearchExcludeAction, searchActions.ShowPreviousSearchExcludeAction.ID, '').run(); + } +}); + KeybindingsRegistry.registerCommandAndKeybindingRule({ id: searchActions.ShowNextSearchTermAction.ID, weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 346ecc21b54..5c9663585fb 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -88,6 +88,70 @@ export class ToggleRegexAction extends Action { } } +export class ShowNextSearchIncludeAction extends Action { + + public static ID = 'search.history.showNextIncludePattern'; + public static LABEL = nls.localize('nextSearchIncludePattern', "Show Next Search Include Pattern"); + + constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { + super(id, label); + } + + public run(): TPromise { + let searchAndReplaceWidget = (this.viewletService.getActiveViewlet()).searchIncludePattern; + searchAndReplaceWidget.showNextTerm(); + return TPromise.as(null); + } +} + +export class ShowPreviousSearchIncludeAction extends Action { + + public static ID = 'search.history.showPreviousIncludePattern'; + public static LABEL = nls.localize('previousSearchIncludePattern', "Show Previous Search Include Pattern"); + + constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { + super(id, label); + } + + public run(): TPromise { + let searchAndReplaceWidget = (this.viewletService.getActiveViewlet()).searchIncludePattern; + searchAndReplaceWidget.showPreviousTerm(); + return TPromise.as(null); + } +} + +export class ShowNextSearchExcludeAction extends Action { + + public static ID = 'search.history.showNextExcludePattern'; + public static LABEL = nls.localize('nextSearchExcludePattern', "Show Next Search Exclude Pattern"); + + constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { + super(id, label); + } + + public run(): TPromise { + let searchAndReplaceWidget = (this.viewletService.getActiveViewlet()).searchExcludePattern; + searchAndReplaceWidget.showNextTerm(); + return TPromise.as(null); + } +} + +export class ShowPreviousSearchExcludeAction extends Action { + + public static ID = 'search.history.showPreviousExcludePattern'; + public static LABEL = nls.localize('previousSearchExcludePattern', "Show Previous Search Exclude Pattern"); + + constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { + super(id, label); + } + + public run(): TPromise { + let searchAndReplaceWidget = (this.viewletService.getActiveViewlet()).searchExcludePattern; + searchAndReplaceWidget.showPreviousTerm(); + return TPromise.as(null); + } +} + export class ShowNextSearchTermAction extends Action { public static ID = 'search.history.showNext'; diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index 1aaebaee816..2e73a0cf36a 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -78,6 +78,8 @@ export class SearchViewlet extends Viewlet { private viewletVisible: IContextKey; private inputBoxFocussed: IContextKey; + private inputPatternIncludesFocussed: IContextKey; + private inputPatternExclusionsFocussed: IContextKey; private firstMatchFocussed: IContextKey; private fileMatchOrMatchFocussed: IContextKey; private fileMatchFocussed: IContextKey; @@ -129,6 +131,8 @@ export class SearchViewlet extends Viewlet { this.toDispose = []; this.viewletVisible = Constants.SearchViewletVisibleKey.bindTo(contextKeyService); this.inputBoxFocussed = Constants.InputBoxFocussedKey.bindTo(this.contextKeyService); + this.inputPatternIncludesFocussed = Constants.PatternIncludesFocussedKey.bindTo(this.contextKeyService); + this.inputPatternExclusionsFocussed = Constants.PatternExcludesFocussedKey.bindTo(this.contextKeyService); this.firstMatchFocussed = Constants.FirstMatchFocusKey.bindTo(contextKeyService); this.fileMatchOrMatchFocussed = Constants.FileMatchOrMatchFocusKey.bindTo(contextKeyService); this.fileMatchFocussed = Constants.FileFocusKey.bindTo(contextKeyService); @@ -217,7 +221,7 @@ export class SearchViewlet extends Viewlet { }); this.inputPatternIncludes.onSubmit(() => this.onQueryChanged(true, true)); - this.trackInputBox(this.inputPatternIncludes.inputFocusTracker); + this.trackInputBox(this.inputPatternIncludes.inputFocusTracker, this.inputPatternIncludesFocussed); }); //pattern exclusion list @@ -240,7 +244,7 @@ export class SearchViewlet extends Viewlet { }); this.inputPatternExclusions.onSubmit(() => this.onQueryChanged(true, true)); - this.trackInputBox(this.inputPatternExclusions.inputFocusTracker); + this.trackInputBox(this.inputPatternExclusions.inputFocusTracker, this.inputPatternExclusionsFocussed); }); // add hint if we have global exclusion @@ -288,6 +292,14 @@ export class SearchViewlet extends Viewlet { return this.searchWidget; } + public get searchIncludePattern(): PatternInputWidget { + return this.inputPatternIncludes; + } + + public get searchExcludePattern(): PatternInputWidget { + return this.inputPatternExclusions; + } + private createSearchWidget(builder: Builder): void { let contentPattern = this.viewletSettings['query.contentPattern'] || ''; let isRegex = this.viewletSettings['query.regex'] === true; @@ -326,15 +338,21 @@ export class SearchViewlet extends Viewlet { this.trackInputBox(this.searchWidget.replaceInputFocusTracker); } - private trackInputBox(inputFocusTracker: dom.IFocusTracker): void { + private trackInputBox(inputFocusTracker: dom.IFocusTracker, contextKey?: IContextKey): void { this.toUnbind.push(inputFocusTracker.addFocusListener(() => { this.inputBoxFocussed.set(true); + if (contextKey) { + contextKey.set(true); + } })); this.toUnbind.push(inputFocusTracker.addBlurListener(() => { this.inputBoxFocussed.set(this.searchWidget.searchInputHasFocus() || this.searchWidget.replaceInputHasFocus() || this.inputPatternIncludes.inputHasFocus() || this.inputPatternExclusions.inputHasFocus()); + if (contextKey) { + contextKey.set(false); + } })); } diff --git a/src/vs/workbench/parts/search/common/constants.ts b/src/vs/workbench/parts/search/common/constants.ts index 08d01f86b26..77b7da9c75f 100644 --- a/src/vs/workbench/parts/search/common/constants.ts +++ b/src/vs/workbench/parts/search/common/constants.ts @@ -25,6 +25,8 @@ export const SearchViewletVisibleKey = new RawContextKey('searchViewlet export const InputBoxFocussedKey = new RawContextKey('inputBoxFocus', false); export const SearchInputBoxFocussedKey = new RawContextKey('searchInputBoxFocus', false); export const ReplaceInputBoxFocussedKey = new RawContextKey('replaceInputBoxFocus', false); +export const PatternIncludesFocussedKey = new RawContextKey('patternIncludesInputBoxFocus', false); +export const PatternExcludesFocussedKey = new RawContextKey('patternExcludesInputBoxFocus', false); export const ReplaceActiveKey = new RawContextKey('replaceActive', false); export const FirstMatchFocusKey = new RawContextKey('firstMatchFocus', false); -- GitLab