diff --git a/src/vs/platform/quickOpen/common/quickOpen.ts b/src/vs/platform/quickOpen/common/quickOpen.ts index 24975fa0e092f..a6a169303b971 100644 --- a/src/vs/platform/quickOpen/common/quickOpen.ts +++ b/src/vs/platform/quickOpen/common/quickOpen.ts @@ -33,6 +33,7 @@ export interface IPickOpenEntry { run?: (context: IEntryRunContext) => void; action?: IAction; payload?: any; + selected?: boolean; } export interface IPickOpenItem { @@ -84,6 +85,8 @@ export interface IPickOptions { * a context key to set when this picker is active */ contextKey?: string; + + multiSelect?: boolean; } export interface IInputOptions { diff --git a/src/vs/platform/quickinput/common/quickInput.ts b/src/vs/platform/quickinput/common/quickInput.ts new file mode 100644 index 0000000000000..c5e05dc6cd4f0 --- /dev/null +++ b/src/vs/platform/quickinput/common/quickInput.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IPickOptions, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; +import { CancellationToken } from 'vs/base/common/cancellation'; + +export const IQuickInputService = createDecorator('quickInputService'); + +export interface IQuickInputService { + + _serviceBrand: any; + + pick(picks: TPromise, options?: IPickOptions, token?: CancellationToken): TPromise; +} diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 070409e485b02..0db6fc8d414c7 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1554,12 +1554,22 @@ declare module 'vscode' { */ ignoreFocusOut?: boolean; + multiSelect?: boolean; + /** * An optional function that is invoked whenever an item is selected. */ onDidSelectItem?(item: QuickPickItem | string): any; } + export interface MultiSelectQuickPickItem extends QuickPickItem { + selected?: boolean; + } + + export interface MultiSelectQuickPickOptions extends QuickPickOptions { + multiSelect: true; + } + /** * Options to configure the behaviour of the [workspace folder](#WorkspaceFolder) pick UI. */ @@ -5069,6 +5079,7 @@ declare module 'vscode' { * @param token A token that can be used to signal cancellation. * @return A promise that resolves to the selection or `undefined`. */ + export function showQuickPick(items: string[] | Thenable, options: MultiSelectQuickPickOptions, token?: CancellationToken): Thenable; export function showQuickPick(items: string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; /** @@ -5079,6 +5090,7 @@ declare module 'vscode' { * @param token A token that can be used to signal cancellation. * @return A promise that resolves to the selected item or `undefined`. */ + export function showQuickPick(items: T[] | Thenable, options: MultiSelectQuickPickOptions, token?: CancellationToken): Thenable; export function showQuickPick(items: T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; /** diff --git a/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts b/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts index 7ac56ff2c6313..959efeff31d49 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { asWinJsPromise } from 'vs/base/common/async'; import { IQuickOpenService, IPickOptions, IInputOptions } from 'vs/platform/quickOpen/common/quickOpen'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { InputBoxOptions } from 'vscode'; import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; @@ -23,7 +24,8 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { constructor( extHostContext: IExtHostContext, - @IQuickOpenService quickOpenService: IQuickOpenService + @IQuickOpenService quickOpenService: IQuickOpenService, + @IQuickInputService private _quickInputService: IQuickInputService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostQuickOpen); this._quickOpenService = quickOpenService; @@ -32,7 +34,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { public dispose(): void { } - $show(options: IPickOptions): TPromise { + $show(options: IPickOptions): TPromise { const myToken = ++this._token; @@ -50,12 +52,25 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { }; }); - return asWinJsPromise(token => this._quickOpenService.pick(this._contents, options, token)).then(item => { - if (item) { - return item.handle; + return asWinJsPromise(token => { + if (options.multiSelect) { + return this._quickInputService.pick(this._contents, options, token) + .then(items => { + if (items) { + return items.map(item => item.handle); + } + return undefined; + }); + } else { + return this._quickOpenService.pick(this._contents, options, token) + .then(item => { + if (item) { + return item.handle; + } + return undefined; + }); } - return undefined; - }, undefined, progress => { + }).then(undefined, undefined, progress => { if (progress) { this._proxy.$onItemSelected((progress).handle); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 82fc8af5feaea..de10ae5c3cfd5 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -366,7 +366,7 @@ export function createApiFactory( showErrorMessage(message, first, ...rest) { return extHostMessageService.showMessage(extension, Severity.Error, message, first, rest); }, - showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) { + showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken): any { return extHostQuickOpen.showQuickPick(items, options, token); }, showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 8a1b10bc57baf..1a1336e336739 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -327,7 +327,7 @@ export interface MyQuickPickItems extends IPickOpenEntry { handle: number; } export interface MainThreadQuickOpenShape extends IDisposable { - $show(options: IPickOptions): TPromise; + $show(options: IPickOptions): TPromise; $setItems(items: MyQuickPickItems[]): TPromise; $setError(error: Error): TPromise; $input(options: vscode.InputBoxOptions, validateInput: boolean): TPromise; diff --git a/src/vs/workbench/api/node/extHostQuickOpen.ts b/src/vs/workbench/api/node/extHostQuickOpen.ts index 2d32ed719fe4d..b95da3ae7b22e 100644 --- a/src/vs/workbench/api/node/extHostQuickOpen.ts +++ b/src/vs/workbench/api/node/extHostQuickOpen.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { wireCancellationToken, asWinJsPromise } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder } from 'vscode'; +import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder, MultiSelectQuickPickItem, MultiSelectQuickPickOptions } from 'vscode'; import { MainContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, IMainContext } from './extHost.protocol'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; @@ -29,9 +29,10 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { this._commands = commands; } + showQuickPick(itemsOrItemsPromise: MultiSelectQuickPickItem[] | Thenable, options: MultiSelectQuickPickOptions, token?: CancellationToken): Thenable; showQuickPick(itemsOrItemsPromise: string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; - showQuickPick(itemsOrItemsPromise: Item[] | Thenable, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable { + showQuickPick(itemsOrItemsPromise: Item[] | Thenable, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable { // clear state from last invocation this._onDidSelectItem = undefined; @@ -43,7 +44,8 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { placeHolder: options && options.placeHolder, matchOnDescription: options && options.matchOnDescription, matchOnDetail: options && options.matchOnDetail, - ignoreFocusLost: options && options.ignoreFocusOut + ignoreFocusLost: options && options.ignoreFocusOut, + multiSelect: options && options.multiSelect }); const promise = TPromise.any([]>[quickPickWidget, itemsPromise]).then(values => { @@ -60,6 +62,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { let label: string; let description: string; let detail: string; + let selected: boolean; if (typeof item === 'string') { label = item; @@ -67,12 +70,14 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { label = item.label; description = item.description; detail = item.detail; + selected = options && options.multiSelect ? (item).selected : undefined; } pickItems.push({ label, description, handle, - detail + detail, + selected }); } @@ -89,6 +94,8 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { return quickPickWidget.then(handle => { if (typeof handle === 'number') { return items[handle]; + } else if (Array.isArray(handle)) { + return handle.map(h => items[h]); } return undefined; }); @@ -98,7 +105,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { return TPromise.wrapError(err); }); }); - return wireCancellationToken(token, promise, true); + return wireCancellationToken(token, promise, true); } $onItemSelected(handle: number): void { diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 0699347dc75ca..620b755fefbf3 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -9,6 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as errors from 'vs/base/common/errors'; import { Part } from 'vs/workbench/browser/part'; import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; +import { QuickInputService } from 'vs/workbench/browser/parts/quickinput/quickInput'; import { Sash, ISashEvent, IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider, Orientation } from 'vs/base/browser/ui/sash/sash'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPartService, Position, ILayoutOptions, Parts } from 'vs/workbench/services/part/common/partService'; @@ -67,6 +68,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal private panel: Part; private statusbar: Part; private quickopen: QuickOpenController; + private quickInput: QuickInputService; private notificationsCenter: NotificationsCenter; private notificationsToasts: NotificationsToasts; private toUnbind: IDisposable[]; @@ -97,6 +99,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal statusbar: Part }, quickopen: QuickOpenController, + quickInput: QuickInputService, notificationsCenter: NotificationsCenter, notificationsToasts: NotificationsToasts, @IStorageService private storageService: IStorageService, @@ -116,6 +119,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.panel = parts.panel; this.statusbar = parts.statusbar; this.quickopen = quickopen; + this.quickInput = quickInput; this.notificationsCenter = notificationsCenter; this.notificationsToasts = notificationsToasts; this.toUnbind = []; @@ -651,6 +655,9 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Quick open this.quickopen.layout(this.workbenchSize); + // Quick input + this.quickInput.layout(this.workbenchSize); + // Notifications this.notificationsCenter.layout(this.workbenchSize); this.notificationsToasts.layout(this.workbenchSize); diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.css b/src/vs/workbench/browser/parts/quickinput/quickInput.css new file mode 100644 index 0000000000000..b8e411d30cf36 --- /dev/null +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.css @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.quick-input-widget { + position: absolute; + width: 600px; + z-index: 2000; + padding-bottom: 6px; + left: 50%; + margin-left: -300px; +} + +.quick-input-actions { + padding: 3px; +} + +.quick-input-actions button { + border: 0; + padding: 0px 4px 1px 4px; + float: right; + margin-left: 4px; +} + +.quick-input-actions button:focus { + outline:0; +} \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts new file mode 100644 index 0000000000000..dd1b1817aa254 --- /dev/null +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -0,0 +1,217 @@ +/*--------------------------------------------------------------------------------------------- + * 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 'vs/css!./quickInput'; +import { Component } from 'vs/workbench/common/component'; +import { IQuickInputService } from 'vs/platform/quickInput/common/quickInput'; +import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { Dimension } from 'vs/base/browser/builder'; +import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list'; +import * as dom from 'vs/base/browser/dom'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { WorkbenchList } from 'vs/platform/list/browser/listService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService'; +import { buttonBackground, buttonForeground, contrastBorder, buttonHoverBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { SIDE_BAR_BACKGROUND, SIDE_BAR_FOREGROUND } from 'vs/workbench/common/theme'; +import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { CancellationToken } from 'vs/base/common/cancellation'; + +const $ = dom.$; + +export interface ISelectedElement { + item: object; + label: string; + selected: boolean; +} + +interface ISelectedElementTemplateData { + element: HTMLElement; + name: HTMLElement; + checkbox: HTMLInputElement; + context: ISelectedElement; + toDispose: IDisposable[]; +} + +class SelectedElementRenderer implements IRenderer { + + static readonly ID = 'selectedelement'; + + get templateId() { + return SelectedElementRenderer.ID; + } + + renderTemplate(container: HTMLElement): ISelectedElementTemplateData { + const data: ISelectedElementTemplateData = Object.create(null); + data.element = dom.append(container, $('.selected_element')); + + data.checkbox = $('input'); + data.checkbox.type = 'checkbox'; + data.toDispose = []; + data.toDispose.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => data.context.selected = !data.context.selected)); + + dom.append(data.element, data.checkbox); + + data.name = dom.append(data.element, $('span.label')); + + return data; + } + + renderElement(element: ISelectedElement, index: number, data: ISelectedElementTemplateData): void { + data.context = element; + data.name.textContent = element.label; + data.element.title = data.name.textContent; + data.checkbox.checked = element.selected; + } + + disposeTemplate(templateData: ISelectedElementTemplateData): void { + dispose(templateData.toDispose); + } +} + +class SelectedElementDelegate implements IDelegate { + + getHeight(element: ISelectedElement): number { + return 22; + } + + getTemplateId(element: ISelectedElement): string { + return SelectedElementRenderer.ID; + } +} + +export class QuickInputService extends Component implements IQuickInputService { + + public _serviceBrand: any; + + private static readonly ID = 'workbench.component.quickinput'; + private static readonly MAX_WIDTH = 600; // Max total width of quick open widget + // private static readonly MAX_ITEMS_HEIGHT = 20 * 22; // Max height of item list below input field + + private layoutDimensions: Dimension; + private container: HTMLElement; + private list: WorkbenchList; + + private elements: ISelectedElement[] = []; + private resolve: (value?: object[] | Thenable) => void; + + constructor( + @IInstantiationService private instantiationService: IInstantiationService, + @IPartService private partService: IPartService, + @IThemeService themeService: IThemeService + ) { + super(QuickInputService.ID, themeService); + } + + private create() { + if (this.container) { + return; + } + + const workbench = document.getElementById(this.partService.getWorkbenchElementId()); + this.container = dom.append(workbench, $('.quick-input-widget')); + this.container.style.display = 'none'; + + const listContainer = dom.append(this.container, $('.quick-input-list')); + const delegate = new SelectedElementDelegate(); + this.list = this.instantiationService.createInstance(WorkbenchList, listContainer, delegate, [new SelectedElementRenderer()], { + identityProvider: element => element.label, + multipleSelectionSupport: false + }) as WorkbenchList; + + const buttonContainer = dom.append(this.container, $('.quick-input-actions')); + const cancel = dom.append(buttonContainer, $('button')); + cancel.textContent = 'Cancel'; // TODO + this.toUnbind.push(dom.addDisposableListener(cancel, dom.EventType.CLICK, e => this.close(false))); + const ok = dom.append(buttonContainer, $('button')); + ok.textContent = 'OK'; // TODO + this.toUnbind.push(dom.addDisposableListener(ok, dom.EventType.CLICK, e => this.close(true))); + + this.toUnbind.push(dom.addDisposableListener(this.container, 'focusout', (e: FocusEvent) => { + for (let element = e.relatedTarget; element; element = element.parentElement) { + if (element === this.container) { + return; + } + } + this.close(false); + })); + } + + private close(ok: boolean) { + if (ok) { + this.resolve(this.elements.filter(e => e.selected).map(e => e.item)); + } else { + this.resolve(); + } + this.container.style.display = 'none'; + } + + async pick(picks: TPromise, options?: IPickOptions, token?: CancellationToken): TPromise { + this.create(); + + // TODO: Progress indication. + this.elements = (await picks).map(item => ({ + item, + label: item.label, + selected: !!item.selected + })); + this.list.splice(0, this.list.length, this.elements); + + this.container.style.display = null; + this.updateLayout(); + this.list.focusFirst(); + this.list.domFocus(); + + return new TPromise(resolve => this.resolve = resolve); + } + + public layout(dimension: Dimension): void { + this.layoutDimensions = dimension; + this.updateLayout(); + } + + private updateLayout() { + if (this.layoutDimensions && this.container) { + const titlebarOffset = this.partService.getTitleBarOffset(); + this.container.style.top = `${titlebarOffset}px`; + + const style = this.container.style; + const width = Math.min(this.layoutDimensions.width * 0.62 /* golden cut */, QuickInputService.MAX_WIDTH); + style.width = width + 'px'; + style.marginLeft = '-' + (width / 2) + 'px'; + + this.list.layout(); + } + } +} + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + const sideBarBackground = theme.getColor(SIDE_BAR_BACKGROUND); + const sideBarForeground = theme.getColor(SIDE_BAR_FOREGROUND); + const contrastBorderColor = theme.getColor(contrastBorder); + const widgetShadowColor = theme.getColor(widgetShadow); + collector.addRule(`.quick-input-widget { + ${sideBarBackground ? `background-color: ${sideBarBackground};` : ''} + ${sideBarForeground ? `color: ${sideBarForeground};` : ''} + ${contrastBorderColor ? `border: 1px solid ${contrastBorderColor};` : ''} + ${widgetShadowColor ? `box-shadow: 0 5px 8px ${widgetShadowColor};` : ''} + }`); + + const buttonBackgroundColor = theme.getColor(buttonBackground); + const buttonForegroundColor = theme.getColor(buttonForeground); + collector.addRule(`.quick-input-actions button { + ${buttonBackgroundColor ? `background-color: ${buttonBackgroundColor};` : ''} + ${buttonForegroundColor ? `color: ${buttonForegroundColor};` : ''} + ${contrastBorderColor ? `border: 1px solid ${contrastBorderColor};` : ''} + }`); + + const buttonHoverBackgroundColor = theme.getColor(buttonHoverBackground); + if (buttonHoverBackgroundColor) { + collector.addRule(`.quick-input-actions button:hover { background-color: ${buttonHoverBackgroundColor}; }`); + } +}); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 88d3f128bba09..ba962650df67d 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -35,6 +35,8 @@ import { WorkbenchLayout } from 'vs/workbench/browser/layout'; import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { QuickInputService } from 'vs/workbench/browser/parts/quickinput/quickInput'; import { getServices } from 'vs/platform/instantiation/common/extensions'; import { Position, Parts, IPartService, ILayoutOptions, Dimension } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -199,6 +201,7 @@ export class Workbench implements IPartService { private editorPart: EditorPart; private statusbarPart: StatusbarPart; private quickOpen: QuickOpenController; + private quickInput: QuickInputService; private notificationsCenter: NotificationsCenter; private notificationsToasts: NotificationsToasts; private workbenchLayout: WorkbenchLayout; @@ -622,6 +625,11 @@ export class Workbench implements IPartService { this.toUnbind.push({ dispose: () => this.quickOpen.shutdown() }); serviceCollection.set(IQuickOpenService, this.quickOpen); + // Quick input service + this.quickInput = this.instantiationService.createInstance(QuickInputService); + this.toUnbind.push({ dispose: () => this.quickInput.shutdown() }); + serviceCollection.set(IQuickInputService, this.quickInput); + // Contributed services const contributedServices = getServices(); for (let contributedService of contributedServices) { @@ -1154,6 +1162,7 @@ export class Workbench implements IPartService { statusbar: this.statusbarPart, // Statusbar }, this.quickOpen, // Quickopen + this.quickInput, // QuickInput this.notificationsCenter, // Notifications Center this.notificationsToasts // Notifications Toasts );