/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { IQuickInputService, IQuickPickItem, IPickOptions, IQuickPick, QuickPickInput, } from '../../../../vs/platform/quickinput/common/quickInput'; import { ILayoutService } from '../../../../vs/platform/layout/browser/layoutService'; import { IInstantiationService } from '../../../../vs/platform/instantiation/common/instantiation'; import { IThemeService, Themable, } from '../../../../vs/platform/theme/common/themeService'; import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground, quickInputListFocusBackground, keybindingLabelBackground, keybindingLabelForeground, keybindingLabelBorder, keybindingLabelBottomBorder, quickInputListFocusForeground, } from '../../../../vs/platform/theme/common/colorRegistry'; import { CancellationToken } from '../../../../vs/base/common/cancellation'; import { computeStyles } from '../../../../vs/platform/theme/common/styler'; import { IContextKeyService, RawContextKey, IContextKey, } from '../../../../vs/platform/contextkey/common/contextkey'; import { IAccessibilityService } from '../../../../vs/platform/accessibility/common/accessibility'; import { QuickInputController, IQuickInputStyles, IQuickInputOptions, } from '../../../../vs/base/parts/quickinput/browser/quickInput'; import { WorkbenchList, IWorkbenchListOptions, } from '../../../../vs/platform/list/browser/listService'; import { List } from '../../../../vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, } from '../../../../vs/base/browser/ui/list/list'; import { IQuickAccessController } from '../../../../vs/platform/quickinput/common/quickAccess'; import { QuickAccessController } from '../../../../vs/platform/quickinput/browser/quickAccess'; export interface IQuickInputControllerHost extends ILayoutService {} export class QuickInputService extends Themable implements IQuickInputService { declare readonly _serviceBrand: undefined; private _controller: QuickInputController | undefined; private get controller(): QuickInputController { if (!this._controller) { this._controller = this._register(this.createController()); } return this._controller; } private _quickAccess: IQuickAccessController | undefined; get quickAccess(): IQuickAccessController { if (!this._quickAccess) { this._quickAccess = this._register( this.instantiationService.createInstance(QuickAccessController) ); } return this._quickAccess; } private readonly contexts = new Map>(); constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService protected readonly contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @IAccessibilityService private readonly accessibilityService: IAccessibilityService, @ILayoutService protected readonly layoutService: ILayoutService ) { super(themeService); } protected createController( host: IQuickInputControllerHost = this.layoutService, options?: Partial ): QuickInputController { const defaultOptions: IQuickInputOptions = { idPrefix: 'quickInput_', // Constant since there is still only one. container: host.container, ignoreFocusOut: () => false, isScreenReaderOptimized: () => this.accessibilityService.isScreenReaderOptimized(), backKeybindingLabel: () => undefined, setContextKey: (id?: string) => this.setContextKey(id), returnFocus: () => host.focus(), createList: ( user: string, container: HTMLElement, delegate: IListVirtualDelegate, renderers: IListRenderer[], options: IWorkbenchListOptions ) => this.instantiationService.createInstance( WorkbenchList, user, container, delegate, renderers, options ) as List, styles: this.computeStyles(), }; const controller = this._register( new QuickInputController({ ...defaultOptions, ...options, }) ); controller.layout(host.dimension, host.offset?.top ?? 0); // Layout changes this._register( host.onDidLayout((dimension) => controller.layout(dimension, host.offset?.top ?? 0) ) ); // Context keys this._register(controller.onShow(() => this.resetContextKeys())); this._register(controller.onHide(() => this.resetContextKeys())); return controller; } private setContextKey(id?: string) { let key: IContextKey | undefined; if (id) { key = this.contexts.get(id); if (!key) { key = new RawContextKey(id, false).bindTo( this.contextKeyService ); this.contexts.set(id, key); } } if (key && key.get()) { return; // already active context } this.resetContextKeys(); if (key) { key.set(true); } } private resetContextKeys() { this.contexts.forEach((context) => { if (context.get()) { context.reset(); } }); } pick>( picks: Promise[]> | QuickPickInput[], options: O = {}, token: CancellationToken = CancellationToken.None ): Promise<(O extends { canPickMany: true } ? T[] : T) | undefined> { return this.controller.pick(picks, options, token); } createQuickPick(): IQuickPick { return this.controller.createQuickPick(); } protected override updateStyles() { this.controller.applyStyles(this.computeStyles()); } private computeStyles(): IQuickInputStyles { return { widget: { ...computeStyles(this.theme, { quickInputBackground, quickInputForeground, quickInputTitleBackground, contrastBorder, widgetShadow, }), }, inputBox: computeStyles(this.theme, { inputForeground, inputBackground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, }), countBadge: computeStyles(this.theme, { badgeBackground, badgeForeground, badgeBorder: contrastBorder, }), button: computeStyles(this.theme, { buttonForeground, buttonBackground, buttonHoverBackground, buttonBorder: contrastBorder, }), progressBar: computeStyles(this.theme, { progressBarBackground, }), keybindingLabel: computeStyles(this.theme, { keybindingLabelBackground, keybindingLabelForeground, keybindingLabelBorder, keybindingLabelBottomBorder, keybindingLabelShadow: widgetShadow, }), list: computeStyles(this.theme, { listBackground: quickInputBackground, // Look like focused when inactive. listInactiveFocusForeground: quickInputListFocusForeground, listInactiveFocusBackground: quickInputListFocusBackground, listFocusOutline: activeContrastBorder, listInactiveFocusOutline: activeContrastBorder, pickerGroupBorder, pickerGroupForeground, }), }; } }