diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 471992d5ed3f9d0ba8eea79a293a98ca6436674f..856a9b30ac6abc21fc7881798884f26a37485161 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -30,6 +30,7 @@ import { ITheme, registerThemingParticipant, IThemeService } from 'vs/platform/t import { Color } from 'vs/base/common/color'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { editorFindRangeHighlight, editorFindMatch, editorFindMatchHighlight, contrastBorder, inputBackground, editorWidgetBackground, inputActiveOptionBorder, widgetShadow, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorBorder, errorForeground, editorWidgetBorder, editorFindMatchBorder, editorFindMatchHighlightBorder, editorFindRangeHighlightBorder, editorWidgetResizeBorder } from 'vs/platform/theme/common/colorRegistry'; +import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/input'; export interface IFindController { @@ -88,6 +89,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _controller: IFindController; private readonly _contextViewProvider: IContextViewProvider; private readonly _keybindingService: IKeybindingService; + private readonly _contextKeyService: IContextKeyService; private _domNode: HTMLElement; private _findInput: FindInput; @@ -131,6 +133,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._state = state; this._contextViewProvider = contextViewProvider; this._keybindingService = keybindingService; + this._contextKeyService = contextKeyService; this._isVisible = false; this._isReplaceVisible = false; @@ -710,7 +713,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _buildFindPart(): HTMLElement { // Find input - this._findInput = this._register(new FindInput(null, this._contextViewProvider, { + this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewProvider, { width: FIND_INPUT_AREA_WIDTH, label: NLS_FIND_INPUT_LABEL, placeholder: NLS_FIND_INPUT_PLACEHOLDER, @@ -733,7 +736,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas return { content: e.message }; } } - })); + }, this._contextKeyService)); this._findInput.setRegex(!!this._state.isRegex); this._findInput.setCaseSensitive(!!this._state.matchCase); this._findInput.setWholeWords(!!this._state.wholeWord); @@ -839,11 +842,11 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas let replaceInput = document.createElement('div'); replaceInput.className = 'replace-input'; replaceInput.style.width = REPLACE_INPUT_AREA_WIDTH + 'px'; - this._replaceInputBox = this._register(new HistoryInputBox(replaceInput, null, { + this._replaceInputBox = this._register(new ContextScopedHistoryInputBox(replaceInput, null, { ariaLabel: NLS_REPLACE_INPUT_LABEL, placeholder: NLS_REPLACE_INPUT_PLACEHOLDER, history: [] - })); + }, this._contextKeyService)); this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'keydown', (e) => this._onReplaceInputKeyDown(e))); this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'input', (e) => { diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 8865f3c3a327382acd87e5cff1d7fa8d505c5747..3c6a927bcf0146fcfccdb59b1e6696a8e86051da 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -14,6 +14,8 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { registerThemingParticipant, ITheme } from 'vs/platform/theme/common/themeService'; import { inputBackground, inputActiveOptionBorder, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorBorder, editorWidgetBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { SimpleButton } from './findWidget'; +import { ContextScopedFindInput } from 'vs/platform/widget/browser/input'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find"); const NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', "Find"); @@ -31,14 +33,15 @@ export abstract class SimpleFindWidget extends Widget { private _updateHistoryDelayer: Delayer; constructor( - @IContextViewService private readonly _contextViewService: IContextViewService + @IContextViewService private readonly _contextViewService: IContextViewService, + @IContextKeyService contextKeyService: IContextKeyService, ) { super(); - this._findInput = this._register(new FindInput(null, this._contextViewService, { + this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewService, { label: NLS_FIND_INPUT_LABEL, placeholder: NLS_FIND_INPUT_PLACEHOLDER, - })); + }, contextKeyService)); // Find History with update delayer this._updateHistoryDelayer = new Delayer(500); diff --git a/src/vs/platform/widget/browser/input.ts b/src/vs/platform/widget/browser/input.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0598517aff3afdd723b8775f982429b10f463ca --- /dev/null +++ b/src/vs/platform/widget/browser/input.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { HistoryInputBox, IHistoryInputOptions } from 'vs/base/browser/ui/inputbox/inputBox'; +import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput'; +import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { createWidgetScopedContextKeyService, IWidget } from 'vs/platform/widget/browser/widget'; + +export const HistoryInputBoxContext = 'historyInputBox'; + +export class ContextScopedHistoryInputBox extends HistoryInputBox implements IWidget { + + constructor(container: HTMLElement, contextViewProvider: IContextViewProvider, options: IHistoryInputOptions, + @IContextKeyService contextKeyService: IContextKeyService + ) { + super(container, contextViewProvider, options); + this._register(createWidgetScopedContextKeyService(contextKeyService, this, HistoryInputBoxContext)); + } +} + +export class ContextScopedFindInput extends FindInput { + + constructor(container: HTMLElement, contextViewProvider: IContextViewProvider, options: IFindInputOptions, + @IContextKeyService contextKeyService: IContextKeyService + ) { + super(container, contextViewProvider, options); + this._register(createWidgetScopedContextKeyService(contextKeyService, this.inputBox, HistoryInputBoxContext)); + } + +} \ No newline at end of file diff --git a/src/vs/platform/widget/browser/widget.contribution.ts b/src/vs/platform/widget/browser/widget.contribution.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a4def1eac253069cc873d836361dee663683652 --- /dev/null +++ b/src/vs/platform/widget/browser/widget.contribution.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { ContextKeyDefinedExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { HistoryInputBoxContext } from 'vs/platform/widget/browser/input'; +import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputbox'; + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'input.action.historyPrevious', + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: new ContextKeyDefinedExpr(HistoryInputBoxContext), + primary: KeyMod.Alt | KeyCode.UpArrow, + handler: (accessor, arg2) => { + const historyInputBox: HistoryInputBox = accessor.get(IContextKeyService).getContext(document.activeElement).getValue(HistoryInputBoxContext); + historyInputBox.showPreviousValue(); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'input.action.historyNext', + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: new ContextKeyDefinedExpr(HistoryInputBoxContext), + primary: KeyMod.Alt | KeyCode.DownArrow, + handler: (accessor, arg2) => { + const historyInputBox: HistoryInputBox = accessor.get(IContextKeyService).getContext(document.activeElement).getValue(HistoryInputBoxContext); + historyInputBox.showNextValue(); + } +}); diff --git a/src/vs/platform/widget/browser/widget.ts b/src/vs/platform/widget/browser/widget.ts new file mode 100644 index 0000000000000000000000000000000000000000..a69bc1356940172875ea0abdd3ef00faca43c5e9 --- /dev/null +++ b/src/vs/platform/widget/browser/widget.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; + +export function createWidgetScopedContextKeyService(contextKeyService: IContextKeyService, widget: IWidget, contextKey: string): IContextKeyService { + const result = contextKeyService.createScoped(widget.element); + const widgetContext = new RawContextKey(contextKey, widget); + widgetContext.bindTo(result); + return result; +} + +export interface IWidget { + + readonly element: HTMLElement; + +} \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/electron-browser/markersPanelActions.ts b/src/vs/workbench/parts/markers/electron-browser/markersPanelActions.ts index 660dd5f731ef039613be00c5c6f7c5cd17ef97f4..eecafd66e3833cae602c5f4809e8aa2723f0dc88 100644 --- a/src/vs/workbench/parts/markers/electron-browser/markersPanelActions.ts +++ b/src/vs/workbench/parts/markers/electron-browser/markersPanelActions.ts @@ -29,6 +29,7 @@ import { badgeBackground, contrastBorder } from 'vs/platform/theme/common/colorR import { localize } from 'vs/nls'; import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/input'; export class ToggleMarkersPanelAction extends TogglePanelAction { @@ -151,7 +152,7 @@ export class MarkersFilterActionItem extends BaseActionItem { } private createInput(container: HTMLElement): void { - this.filterInputBox = this._register(this.instantiationService.createInstance(HistoryInputBox, container, this.contextViewService, { + this.filterInputBox = this._register(this.instantiationService.createInstance(ContextScopedHistoryInputBox, container, this.contextViewService, { placeholder: Messages.MARKERS_PANEL_FILTER_PLACEHOLDER, ariaLabel: Messages.MARKERS_PANEL_FILTER_ARIA_LABEL, history: this.itemOptions.filterHistory @@ -232,14 +233,6 @@ export class MarkersFilterActionItem extends BaseActionItem { } } - private showNextFilter() { - this.filterInputBox.showNextValue(); - } - - private showPreviousFilter() { - this.filterInputBox.showPreviousValue(); - } - private onInputKeyDown(keyboardEvent: IKeyboardEvent, filterInputBox: HistoryInputBox) { let handled = false; switch (keyboardEvent.keyCode) { @@ -247,14 +240,6 @@ export class MarkersFilterActionItem extends BaseActionItem { filterInputBox.value = ''; handled = true; break; - case KeyCode.UpArrow: - this.showPreviousFilter(); - handled = true; - break; - case KeyCode.DownArrow: - this.showNextFilter(); - handled = true; - break; } if (handled) { keyboardEvent.stopPropagation(); diff --git a/src/vs/workbench/parts/search/browser/patternInputWidget.ts b/src/vs/workbench/parts/search/browser/patternInputWidget.ts index 1f25683706ab8b1fab1f3cbd96a650f12ad360e4..522be3a07231d651bffba8e17452c13f1165c915 100644 --- a/src/vs/workbench/parts/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/parts/search/browser/patternInputWidget.ts @@ -14,6 +14,8 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { Event as 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 { ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/input'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export interface IOptions { placeholder?: string; @@ -44,7 +46,8 @@ export class PatternInputWidget extends Widget { public onCancel: CommonEvent = this._onCancel.event; constructor(parent: HTMLElement, private contextViewProvider: IContextViewProvider, options: IOptions = Object.create(null), - @IThemeService protected themeService: IThemeService + @IThemeService protected themeService: IThemeService, + @IContextKeyService private contextKeyService: IContextKeyService ) { super(); this.onOptionChange = null; @@ -146,14 +149,14 @@ export class PatternInputWidget extends Widget { this.domNode.style.width = this.width + 'px'; dom.addClass(this.domNode, 'monaco-findInput'); - this.inputBox = new HistoryInputBox(this.domNode, this.contextViewProvider, { + this.inputBox = new ContextScopedHistoryInputBox(this.domNode, this.contextViewProvider, { placeholder: this.placeholder || '', ariaLabel: this.ariaLabel || '', validationOptions: { validation: null }, history: options.history || [] - }); + }, this.contextKeyService); this._register(attachInputBoxStyler(this.inputBox, this.themeService)); this.inputFocusTracker = dom.trackFocus(this.inputBox.inputElement); this.onkeyup(this.inputBox.inputElement, (keyboardEvent) => this.onInputKeyUp(keyboardEvent)); @@ -186,9 +189,10 @@ export class PatternInputWidget extends Widget { export class ExcludePatternInputWidget extends PatternInputWidget { constructor(parent: HTMLElement, contextViewProvider: IContextViewProvider, options: IOptions = Object.create(null), - @IThemeService themeService: IThemeService + @IThemeService themeService: IThemeService, + @IContextKeyService contextKeyService: IContextKeyService ) { - super(parent, contextViewProvider, options, themeService); + super(parent, contextViewProvider, options, themeService, contextKeyService); } private useExcludesAndIgnoreFilesBox: Checkbox; diff --git a/src/vs/workbench/parts/search/browser/searchWidget.ts b/src/vs/workbench/parts/search/browser/searchWidget.ts index e02db69d9b128eeb5e77f3c807db6d27db98606b..537b3d154fa7f4ea31f7ff9845d23e958e0cfb44 100644 --- a/src/vs/workbench/parts/search/browser/searchWidget.ts +++ b/src/vs/workbench/parts/search/browser/searchWidget.ts @@ -31,6 +31,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ISearchConfigurationProperties } from 'vs/platform/search/common/search'; +import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/input'; export interface ISearchWidgetOptions { value?: string; @@ -243,7 +244,7 @@ export class SearchWidget extends Widget { }; let searchInputContainer = dom.append(parent, dom.$('.search-container.input-box')); - this.searchInput = this._register(new FindInput(searchInputContainer, this.contextViewService, inputOptions)); + this.searchInput = this._register(new ContextScopedFindInput(searchInputContainer, this.contextViewService, inputOptions, this.keyBindingService)); this._register(attachFindInputBoxStyler(this.searchInput, this.themeService)); this.searchInput.onKeyUp((keyboardEvent: IKeyboardEvent) => this.onSearchInputKeyUp(keyboardEvent)); this.searchInput.setValue(options.value || ''); @@ -282,11 +283,11 @@ export class SearchWidget extends Widget { private renderReplaceInput(parent: HTMLElement, options: ISearchWidgetOptions): void { this.replaceContainer = dom.append(parent, dom.$('.replace-container.disabled')); let replaceBox = dom.append(this.replaceContainer, dom.$('.input-box')); - this.replaceInput = this._register(new HistoryInputBox(replaceBox, this.contextViewService, { + this.replaceInput = this._register(new ContextScopedHistoryInputBox(replaceBox, this.contextViewService, { ariaLabel: nls.localize('label.Replace', 'Replace: Type replace term and press Enter to preview or Escape to cancel'), placeholder: nls.localize('search.replace.placeHolder', "Replace"), history: options.replaceHistory || [] - })); + }, this.keyBindingService)); this._register(attachInputBoxStyler(this.replaceInput, this.themeService)); this.onkeyup(this.replaceInput.inputElement, (keyboardEvent) => this.onReplaceInputKeyUp(keyboardEvent)); this.replaceInput.onDidChange(() => this._onReplaceValueChanged.fire()); diff --git a/src/vs/workbench/parts/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/parts/terminal/browser/terminalFindWidget.ts index 54f6566bf1f2e7f000bbb2fef2e7c179e9041fde..a152219e5042a5eb154fb70b7b9389488d79a875 100644 --- a/src/vs/workbench/parts/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/parts/terminal/browser/terminalFindWidget.ts @@ -16,7 +16,7 @@ export class TerminalFindWidget extends SimpleFindWidget { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @ITerminalService private readonly _terminalService: ITerminalService ) { - super(_contextViewService); + super(_contextViewService, _contextKeyService); this._findInputFocused = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED.bindTo(this._contextKeyService); } diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts b/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts index ec7e540b07f7ba68d94942a7be1ec193cd61cfeb..bf92f04e0644ba0fe43f39bccb39f13abd6814b1 100644 --- a/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts @@ -10,7 +10,7 @@ import { getMediaMime, guessMimeTypes } from 'vs/base/common/mime'; import { nativeSep, extname } from 'vs/base/common/paths'; import { startsWith } from 'vs/base/common/strings'; import URI from 'vs/base/common/uri'; -import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; @@ -45,6 +45,7 @@ export class WebviewElement { @IThemeService private readonly _themeService: IThemeService, @IEnvironmentService private readonly _environmentService: IEnvironmentService, @IContextViewService private readonly _contextViewService: IContextViewService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IFileService private readonly _fileService: IFileService, ) { this._webview = document.createElement('webview'); @@ -188,7 +189,7 @@ export class WebviewElement { }), ); - this._webviewFindWidget = new WebviewFindWidget(this._contextViewService, this); + this._webviewFindWidget = new WebviewFindWidget(this._contextViewService, this._contextKeyService, this); this._disposables.push(this._webviewFindWidget); this.style(this._themeService.getTheme()); diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewFindWidget.ts b/src/vs/workbench/parts/webview/electron-browser/webviewFindWidget.ts index 13ca4b99ce4c61801fcbfc7e792e3e3f966d803a..2d3189af716bc6c5314ee9f86ebfd66d6a6f555f 100644 --- a/src/vs/workbench/parts/webview/electron-browser/webviewFindWidget.ts +++ b/src/vs/workbench/parts/webview/electron-browser/webviewFindWidget.ts @@ -6,14 +6,16 @@ import { SimpleFindWidget } from 'vs/editor/contrib/find/simpleFindWidget'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { WebviewElement } from './webviewElement'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export class WebviewFindWidget extends SimpleFindWidget { constructor( @IContextViewService contextViewService: IContextViewService, + @IContextKeyService contextKeyService: IContextKeyService, private readonly webview: WebviewElement ) { - super(contextViewService); + super(contextViewService, contextKeyService); } public find(previous: boolean) { diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 938aafcedab7f5fa8561df63abc39661bd92f01a..5feaad584c7e3d02c41b3353208c3f9cb1824304 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -15,6 +15,9 @@ import 'vs/workbench/services/configuration/common/configurationExtensionPoint'; // Editor import 'vs/editor/editor.all'; +// Platform +import 'vs/platform/widget/browser/widget.contribution'; + // Menus/Actions import 'vs/workbench/services/actions/electron-browser/menusExtensionPoint';