First cut of quick pick separators as kind. ref #74967

This commit is contained in:
Tyler Leonhardt 2021-11-10 11:26:20 -08:00
parent 958a5ad8bb
commit a41001c482
No known key found for this signature in database
GPG key ID: 1BC2B6244363E77E
4 changed files with 113 additions and 78 deletions

View file

@ -2762,4 +2762,11 @@ declare module 'vscode' {
//#endregion
//#region quickPickItemKind: https://github.com/microsoft/vscode/issues/74967
export interface QuickPickItem {
kind?: string | { label: string; };
}
//#endregion
}

View file

@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
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 { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, TransferQuickPickItem, MainContext, IExtHostContext, TransferQuickInput, TransferQuickInputButton, IInputBoxOptions, TransferQuickPickItemOrSeparator } 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';
interface QuickInputSession {
input: IQuickInput;
handlesToItems: Map<number, TransferQuickPickItems>;
handlesToItems: Map<number, TransferQuickPickItem>;
}
function reviveIconPathUris(iconPath: { dark: URI; light?: URI | undefined; }) {
@ -27,7 +27,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
private readonly _proxy: ExtHostQuickOpenShape;
private readonly _quickInputService: IQuickInputService;
private readonly _items: Record<number, {
resolve(items: TransferQuickPickItems[]): void;
resolve(items: TransferQuickPickItemOrSeparator[]): void;
reject(error: Error): void;
}> = {};
@ -42,8 +42,8 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
public dispose(): void {
}
$show(instance: number, options: IPickOptions<TransferQuickPickItems>, token: CancellationToken): Promise<number | number[] | undefined> {
const contents = new Promise<TransferQuickPickItems[]>((resolve, reject) => {
$show(instance: number, options: IPickOptions<TransferQuickPickItem>, token: CancellationToken): Promise<number | number[] | undefined> {
const contents = new Promise<TransferQuickPickItemOrSeparator[]>((resolve, reject) => {
this._items[instance] = { resolve, reject };
});
@ -51,7 +51,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
...options,
onDidFocus: el => {
if (el) {
this._proxy.$onItemSelected((<TransferQuickPickItems>el).handle);
this._proxy.$onItemSelected((<TransferQuickPickItem>el).handle);
}
}
};
@ -73,7 +73,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
}
}
$setItems(instance: number, items: TransferQuickPickItems[]): Promise<void> {
$setItems(instance: number, items: TransferQuickPickItemOrSeparator[]): Promise<void> {
if (this._items[instance]) {
this._items[instance].resolve(items);
delete this._items[instance];
@ -140,13 +140,13 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
// Add extra events specific for quickpick
const quickpick = input as IQuickPick<IQuickPickItem>;
quickpick.onDidChangeActive(items => {
this._proxy.$onDidChangeActive(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
this._proxy.$onDidChangeActive(sessionId, items.map(item => (item as TransferQuickPickItem).handle));
});
quickpick.onDidChangeSelection(items => {
this._proxy.$onDidChangeSelection(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
this._proxy.$onDidChangeSelection(sessionId, items.map(item => (item as TransferQuickPickItem).handle));
});
quickpick.onDidTriggerItemButton((e) => {
this._proxy.$onDidTriggerItemButton(sessionId, (e.item as TransferQuickPickItems).handle, (e.button as TransferQuickInputButton).handle);
this._proxy.$onDidTriggerItemButton(sessionId, (e.item as TransferQuickPickItem).handle, (e.button as TransferQuickInputButton).handle);
});
}
@ -169,7 +169,11 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
}
} else if (param === 'items') {
handlesToItems.clear();
params[param].forEach((item: TransferQuickPickItems) => {
params[param].forEach((item: TransferQuickPickItemOrSeparator) => {
if (item.type === 'separator') {
return;
}
if (item.buttons) {
item.buttons = item.buttons.map((button: TransferQuickInputButton) => {
if (button.iconPath) {

View file

@ -510,7 +510,8 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
$sendProcessExit(terminalId: number, exitCode: number | undefined): void;
}
export interface TransferQuickPickItems extends quickInput.IQuickPickItem {
export type TransferQuickPickItemOrSeparator = TransferQuickPickItem | quickInput.IQuickPickSeparator;
export interface TransferQuickPickItem extends quickInput.IQuickPickItem {
handle: number;
buttons?: TransferQuickInputButton[];
}
@ -548,7 +549,7 @@ export interface TransferQuickPick extends BaseTransferQuickInput {
buttons?: TransferQuickInputButton[];
items?: TransferQuickPickItems[];
items?: TransferQuickPickItemOrSeparator[];
activeItems?: number[];
@ -593,8 +594,8 @@ export interface IInputBoxOptions {
}
export interface MainThreadQuickOpenShape extends IDisposable {
$show(instance: number, options: quickInput.IPickOptions<TransferQuickPickItems>, token: CancellationToken): Promise<number | number[] | undefined>;
$setItems(instance: number, items: TransferQuickPickItems[]): Promise<void>;
$show(instance: number, options: quickInput.IPickOptions<TransferQuickPickItem>, token: CancellationToken): Promise<number | number[] | undefined>;
$setItems(instance: number, items: TransferQuickPickItemOrSeparator[]): Promise<void>;
$setError(instance: number, error: Error): Promise<void>;
$input(options: IInputBoxOptions | undefined, validateInput: boolean, token: CancellationToken): Promise<string | undefined>;
$createOrUpdate(params: TransferQuickInput): Promise<void>;

View file

@ -10,7 +10,7 @@ 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, QuickPickItemButtonEvent, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode';
import { ExtHostQuickOpenShape, IMainContext, MainContext, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from './extHost.protocol';
import { ExtHostQuickOpenShape, IMainContext, MainContext, TransferQuickInput, TransferQuickInputButton, TransferQuickPickItemOrSeparator } from './extHost.protocol';
import { URI } from 'vs/base/common/uri';
import { ThemeIcon, QuickInputButtons } from 'vs/workbench/api/common/extHostTypes';
import { isPromiseCanceledError } from 'vs/base/common/errors';
@ -59,7 +59,7 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Promise<QuickPickItem[]>, enableProposedApi: boolean, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Promise<QuickPickItem[] | undefined>;
showQuickPick(itemsOrItemsPromise: string[] | Promise<string[]>, enableProposedApi: boolean, options?: QuickPickOptions, token?: CancellationToken): Promise<string | undefined>;
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Promise<QuickPickItem[]>, enableProposedApi: boolean, options?: QuickPickOptions, token?: CancellationToken): Promise<QuickPickItem | undefined>;
showQuickPick(itemsOrItemsPromise: Item[] | Promise<Item[]>, enableProposedApi: boolean, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Promise<Item | Item[] | undefined> {
async showQuickPick(itemsOrItemsPromise: Item[] | Promise<Item[]>, enableProposedApi: boolean, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Promise<Item | Item[] | undefined> {
// clear state from last invocation
this._onDidSelectItem = undefined;
@ -80,70 +80,81 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
const widgetClosedMarker = {};
const widgetClosedPromise = quickPickWidget.then(() => widgetClosedMarker);
return Promise.race([widgetClosedPromise, itemsPromise]).then(result => {
if (result === widgetClosedMarker) {
return undefined;
const result = await Promise.race([widgetClosedPromise, itemsPromise]);
if (result === widgetClosedMarker) {
return undefined;
}
const items = await itemsPromise;
const pickItems: TransferQuickPickItemOrSeparator[] = [];
let lastKind: string | { label: string; } | undefined = undefined;
for (let handle = 0; handle < items.length; handle++) {
const item = items[handle];
let label: string;
let description: string | undefined;
let detail: string | undefined;
let picked: boolean | undefined;
let alwaysShow: boolean | undefined;
if (typeof item === 'string') {
// 'string' items have a kind of undefined so
// if the previous item had a kind, that is considered a
// change and would cause the addition of a separator.
if (lastKind) {
pickItems.push({ type: 'separator' });
lastKind = undefined;
}
label = item;
} else {
if (lastKind !== item.kind) {
const label: string | undefined = typeof item.kind === 'string' ? item.kind : item.kind?.label;
pickItems.push({ type: 'separator', label });
lastKind = item.kind;
}
label = item.label;
description = item.description;
detail = item.detail;
picked = item.picked;
alwaysShow = item.alwaysShow;
}
return itemsPromise.then(items => {
const pickItems: TransferQuickPickItems[] = [];
for (let handle = 0; handle < items.length; handle++) {
const item = items[handle];
let label: string;
let description: string | undefined;
let detail: string | undefined;
let picked: boolean | undefined;
let alwaysShow: boolean | undefined;
if (typeof item === 'string') {
label = item;
} else {
label = item.label;
description = item.description;
detail = item.detail;
picked = item.picked;
alwaysShow = item.alwaysShow;
}
pickItems.push({
label,
description,
handle,
detail,
picked,
alwaysShow
});
}
// handle selection changes
if (options && typeof options.onDidSelectItem === 'function') {
this._onDidSelectItem = (handle) => {
options.onDidSelectItem!(items[handle]);
};
}
// show items
proxy.$setItems(instance, pickItems);
return quickPickWidget.then(handle => {
if (typeof handle === 'number') {
return items[handle];
} else if (Array.isArray(handle)) {
return handle.map(h => items[h]);
}
return undefined;
});
pickItems.push({
label,
description,
handle,
detail,
picked,
alwaysShow
});
}).then(undefined, err => {
}
// handle selection changes
if (options && typeof options.onDidSelectItem === 'function') {
this._onDidSelectItem = (handle) => {
options.onDidSelectItem!(items[handle]);
};
}
// show items
proxy.$setItems(instance, pickItems);
try {
return quickPickWidget.then(handle => {
if (typeof handle === 'number') {
return items[handle];
} else if (Array.isArray(handle)) {
return handle.map(h => items[h]);
}
return undefined;
});
} catch (err) {
if (isPromiseCanceledError(err)) {
return undefined;
}
proxy.$setError(instance, err);
return Promise.reject(err);
});
throw err;
}
}
$onItemSelected(handle: number): void {
@ -553,8 +564,16 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
this._handlesToItems.set(i, item);
this._itemsToHandles.set(item, i);
});
this.update({
items: items.map((item, i) => ({
const itemsItems: Array<TransferQuickPickItemOrSeparator> = [];
let lastKind: string | { label: string; } | undefined = undefined;
items.forEach((item, i) => {
if (lastKind !== item.kind) {
const label: string | undefined = typeof item.kind === 'string' ? item.kind : item.kind?.label;
itemsItems.push({ type: 'separator', label });
lastKind = item.kind;
}
itemsItems.push({
label: item.label,
description: item.description,
handle: i,
@ -567,8 +586,12 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
tooltip: button.tooltip,
handle: i
};
}),
}))
})
});
});
this.update({
items: itemsItems
});
}