From e003fd9a5d8a17965d307f3fc1955671d3336bdc Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Tue, 10 Aug 2021 14:45:35 -0700 Subject: [PATCH] initial support --- src/vs/vscode.proposed.d.ts | 14 +++ .../api/browser/mainThreadQuickOpen.ts | 102 +++++++++--------- .../workbench/api/common/extHost.protocol.ts | 6 +- .../workbench/api/common/extHostQuickOpen.ts | 70 ++++++++++-- 4 files changed, 127 insertions(+), 65 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index cd75a3c00a042..3b5e19d82ccea 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2765,4 +2765,18 @@ declare module 'vscode' { } //#endregion + + //#region https://github.com/microsoft/vscode/issues/88716 + export interface QuickPickItem { + buttons?: QuickInputButton[]; + } + export interface QuickPick extends QuickInput { + readonly onDidTriggerItemButton: Event>; + } + export interface QuickPickItemButtonEvent { + button: QuickInputButton; + item: T; + } + + //#endregion } diff --git a/src/vs/workbench/api/browser/mainThreadQuickOpen.ts b/src/vs/workbench/api/browser/mainThreadQuickOpen.ts index 45f9f5511309e..6baffac194dac 100644 --- a/src/vs/workbench/api/browser/mainThreadQuickOpen.ts +++ b/src/vs/workbench/api/browser/mainThreadQuickOpen.ts @@ -3,18 +3,24 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IPickOptions, IInputOptions, IQuickInputService, IQuickInput } from 'vs/platform/quickinput/common/quickInput'; +import { IPickOptions, IInputOptions, IQuickInputService, IQuickInput, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, TransferQuickPickItems, MainContext, IExtHostContext, TransferQuickInput, TransferQuickInputButton, IInputBoxOptions } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ThemeIcon } from 'vs/platform/theme/common/themeService'; interface QuickInputSession { input: IQuickInput; handlesToItems: Map; } +function reviveIconPathUris(iconPath: { dark: URI; light?: URI | undefined; }) { + iconPath.dark = URI.revive(iconPath.dark); + if (iconPath.light) { + iconPath.light = URI.revive(iconPath.light); + } +} + @extHostNamedCustomer(MainContext.MainThreadQuickOpen) export class MainThreadQuickOpen implements MainThreadQuickOpenShape { @@ -115,49 +121,39 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { const sessionId = params.id; let session = this.sessions.get(sessionId); if (!session) { + + const input = params.type === 'quickPick' ? this._quickInputService.createQuickPick() : this._quickInputService.createInputBox(); + input.onDidAccept(() => { + this._proxy.$onDidAccept(sessionId); + }); + input.onDidTriggerButton(button => { + this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle); + }); + input.onDidChangeValue(value => { + this._proxy.$onDidChangeValue(sessionId, value); + }); + input.onDidHide(() => { + this._proxy.$onDidHide(sessionId); + }); + if (params.type === 'quickPick') { - const input = this._quickInputService.createQuickPick(); - input.onDidAccept(() => { - this._proxy.$onDidAccept(sessionId); - }); - input.onDidChangeActive(items => { + // Add extra events specific for quickpick + const quickpick = input as IQuickPick; + quickpick.onDidChangeActive(items => { this._proxy.$onDidChangeActive(sessionId, items.map(item => (item as TransferQuickPickItems).handle)); }); - input.onDidChangeSelection(items => { + quickpick.onDidChangeSelection(items => { this._proxy.$onDidChangeSelection(sessionId, items.map(item => (item as TransferQuickPickItems).handle)); }); - input.onDidTriggerButton(button => { - this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle); - }); - input.onDidChangeValue(value => { - this._proxy.$onDidChangeValue(sessionId, value); + quickpick.onDidTriggerItemButton((e) => { + this._proxy.$onDidTriggerItemButton(sessionId, (e.item as TransferQuickPickItems).handle, (e.button as TransferQuickInputButton).handle); }); - input.onDidHide(() => { - this._proxy.$onDidHide(sessionId); - }); - session = { - input, - handlesToItems: new Map() - }; - } else { - const input = this._quickInputService.createInputBox(); - input.onDidAccept(() => { - this._proxy.$onDidAccept(sessionId); - }); - input.onDidTriggerButton(button => { - this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle); - }); - input.onDidChangeValue(value => { - this._proxy.$onDidChangeValue(sessionId, value); - }); - input.onDidHide(() => { - this._proxy.$onDidHide(sessionId); - }); - session = { - input, - handlesToItems: new Map() - }; } + + session = { + input, + handlesToItems: new Map() + }; this.sessions.set(sessionId, session); } const { input, handlesToItems } = session; @@ -174,6 +170,15 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { } else if (param === 'items') { handlesToItems.clear(); params[param].forEach((item: TransferQuickPickItems) => { + if (item.buttons) { + item.buttons = item.buttons.map((button: TransferQuickInputButton) => { + if (button.iconPath) { + reviveIconPathUris(button.iconPath); + } + + return button; + }); + } handlesToItems.set(item.handle, item); }); (input as any)[param] = params[param]; @@ -186,23 +191,12 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { if (button.handle === -1) { return this._quickInputService.backButton; } - const { iconPath, tooltip, handle } = button; - if ('id' in iconPath) { - return { - iconClass: ThemeIcon.asClassName(iconPath), - tooltip, - handle - }; - } else { - return { - iconPath: { - dark: URI.revive(iconPath.dark), - light: iconPath.light && URI.revive(iconPath.light) - }, - tooltip, - handle - }; + + if (button.iconPath) { + reviveIconPathUris(button.iconPath); } + + return button; }); } else { (input as any)[param] = params[param]; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 80c99f0707cf3..b7cc43b682c4b 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -516,12 +516,11 @@ export interface MainThreadTerminalServiceShape extends IDisposable { export interface TransferQuickPickItems extends quickInput.IQuickPickItem { handle: number; + buttons?: TransferQuickInputButton[]; } -export interface TransferQuickInputButton { +export interface TransferQuickInputButton extends quickInput.IQuickInputButton { handle: number; - iconPath: { dark: URI; light?: URI; } | { id: string; }; - tooltip?: string; } export type TransferQuickInput = TransferQuickPick | TransferInputBox; @@ -1706,6 +1705,7 @@ export interface ExtHostQuickOpenShape { $onDidAccept(sessionId: number): void; $onDidChangeValue(sessionId: number, value: string): void; $onDidTriggerButton(sessionId: number, handle: number): void; + $onDidTriggerItemButton(sessionId: number, itemHandle: number, buttonHandle: number): void; $onDidHide(sessionId: number): void; } diff --git a/src/vs/workbench/api/common/extHostQuickOpen.ts b/src/vs/workbench/api/common/extHostQuickOpen.ts index 41a6eaae09041..a04f27fc3dedd 100644 --- a/src/vs/workbench/api/common/extHostQuickOpen.ts +++ b/src/vs/workbench/api/common/extHostQuickOpen.ts @@ -9,7 +9,7 @@ import { Emitter } from 'vs/base/common/event'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace'; -import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode'; +import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickItemButtonEvent, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode'; import { ExtHostQuickOpenShape, IMainContext, MainContext, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from './extHost.protocol'; import { URI } from 'vs/base/common/uri'; import { ThemeIcon, QuickInputButtons } from 'vs/workbench/api/common/extHostTypes'; @@ -17,6 +17,7 @@ import { isPromiseCanceledError } from 'vs/base/common/errors'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { coalesce } from 'vs/base/common/arrays'; import Severity from 'vs/base/common/severity'; +import { ThemeIcon as ThemeIconUtils } from 'vs/platform/theme/common/themeService'; export type Item = string | QuickPickItem; @@ -238,6 +239,13 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx } } + $onDidTriggerItemButton(sessionId: number, itemHandle: number, buttonHandle: number): void { + const session = this._sessions.get(sessionId); + if (session instanceof ExtHostQuickPick) { + session._fireDidTriggerItemButton(itemHandle, buttonHandle); + } + } + $onDidHide(sessionId: number): void { const session = this._sessions.get(sessionId); if (session) { @@ -369,11 +377,13 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx this._handlesToButtons.set(handle, button); }); this.update({ - buttons: buttons.map((button, i) => ({ - iconPath: getIconUris(button.iconPath), - tooltip: button.tooltip, - handle: button === QuickInputButtons.Back ? -1 : i, - })) + buttons: buttons.map((button, i) => { + return { + ...getIconPathOrClass(button), + tooltip: button.tooltip, + handle: button === QuickInputButtons.Back ? -1 : i, + }; + }) }); } @@ -481,6 +491,22 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx return typeof iconPath === 'object' && 'dark' in iconPath ? iconPath.dark : iconPath; } + function getIconPathOrClass(button: QuickInputButton) { + const iconPathOrIconClass = getIconUris(button.iconPath); + let iconPath: { dark: URI; light?: URI | undefined; } | undefined; + let iconClass: string | undefined; + if ('id' in iconPathOrIconClass) { + iconClass = ThemeIconUtils.asClassName(iconPathOrIconClass); + } else { + iconPath = iconPathOrIconClass; + } + + return { + iconPath, + iconClass + }; + } + class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick { private _items: T[] = []; @@ -494,12 +520,14 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx private readonly _onDidChangeActiveEmitter = new Emitter(); private _selectedItems: T[] = []; private readonly _onDidChangeSelectionEmitter = new Emitter(); + private readonly _onDidTriggerItemButtonEmitter = new Emitter>(); - constructor(extensionId: ExtensionIdentifier, enableProposedApi: boolean, onDispose: () => void) { + constructor(extensionId: ExtensionIdentifier, private readonly enableProposedApi: boolean, onDispose: () => void) { super(extensionId, onDispose); this._disposables.push( this._onDidChangeActiveEmitter, this._onDidChangeSelectionEmitter, + this._onDidTriggerItemButtonEmitter ); this.update({ type: 'quickPick' }); } @@ -523,7 +551,17 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx handle: i, detail: item.detail, picked: item.picked, - alwaysShow: item.alwaysShow + alwaysShow: item.alwaysShow, + // Proposed API only at the moment + buttons: item.buttons && this.enableProposedApi + ? item.buttons.map((button, i) => { + return { + ...getIconPathOrClass(button), + tooltip: button.tooltip, + handle: i + }; + }) + : undefined, })) }); } @@ -597,6 +635,22 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx this._selectedItems = items; this._onDidChangeSelectionEmitter.fire(items); } + + onDidTriggerItemButton = this._onDidTriggerItemButtonEmitter.event; + + _fireDidTriggerItemButton(itemHandle: number, buttonHandle: number) { + const item = this._handlesToItems.get(itemHandle)!; + if (!item || !item.buttons || !item.buttons.length) { + return; + } + const button = item.buttons[buttonHandle]; + if (button) { + this._onDidTriggerItemButtonEmitter.fire({ + button, + item + }); + } + } } class ExtHostInputBox extends ExtHostQuickInput implements InputBox {