diff --git a/packages/common/src/ide/types/QuickPickOptions.ts b/packages/common/src/ide/types/QuickPickOptions.ts index 41868a6897..89ffd110c0 100644 --- a/packages/common/src/ide/types/QuickPickOptions.ts +++ b/packages/common/src/ide/types/QuickPickOptions.ts @@ -1,10 +1,21 @@ -export interface UnknownValuesOptions { - allowed: true; +export interface QuickPickOptions { + /** + * An optional string that represents the title of the quick pick. + */ + title?: string; + + /** + * An optional string that represents the default value to be selected in the quick pick. + */ + defaultValue?: string; /** - * An optional template to use when displaying the new option to the user. The - * template must include `{}` as a substring, which will be replaced with the - * user's input when displaying an option to add the unknown item. + * Indicates whether the quick pick should allow unknown values, and if so, + * how to handle them. + * + * If provided as a string: An optional template to use when displaying the new + * option to the user. The template must include `{}` as a substring, which will + * be replaced with the user's input when displaying an option to add the unknown item. * * For example: * @@ -16,18 +27,5 @@ export interface UnknownValuesOptions { * * "Add new value 'foo' →" */ - newValueTemplate?: string; -} - -export interface QuickPickOptions { - /** - * An optional string that represents the title of the quick pick. - */ - title?: string; - - /** - * Indicates whether the quick pick should allow unknown values, and if so, - * how to handle them. - */ - unknownValues?: UnknownValuesOptions; + unknownValues?: boolean | string; } diff --git a/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts b/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts index 65adc58d40..c235ddd0f9 100644 --- a/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts +++ b/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts @@ -58,11 +58,11 @@ export class VscodeIDE implements IDE { this.editorMap = new WeakMap(); } - async showQuickPick( + showQuickPick( items: readonly string[], options?: QuickPickOptions, ): Promise { - return await vscodeShowQuickPick(items, options); + return vscodeShowQuickPick(items, options); } setHighlightRanges( diff --git a/packages/cursorless-vscode/src/ide/vscode/vscodeShowQuickPick.ts b/packages/cursorless-vscode/src/ide/vscode/vscodeShowQuickPick.ts index eec26dd236..d16aaf3b85 100644 --- a/packages/cursorless-vscode/src/ide/vscode/vscodeShowQuickPick.ts +++ b/packages/cursorless-vscode/src/ide/vscode/vscodeShowQuickPick.ts @@ -1,26 +1,5 @@ +import type { QuickPickOptions } from "@cursorless/common"; import * as vscode from "vscode"; -import type { - QuickPickOptions, - UnknownValuesOptions, -} from "@cursorless/common"; - -export async function vscodeShowQuickPick( - items: readonly string[], - options: QuickPickOptions | undefined, -) { - if (options?.unknownValues == null) { - return await vscode.window.showQuickPick(items, options); - } - - const { unknownValues, ...rest } = options; - return await showQuickPickAllowingUnknown(items, unknownValues, rest); -} - -interface CustomQuickPickItem extends vscode.QuickPickItem { - value: string; -} - -const DEFAULT_NEW_VALUE_TEMPLATE = "Add new value '{}' →"; /** * Show a quick pick that allows the user to enter a new value. We do this by @@ -29,43 +8,58 @@ const DEFAULT_NEW_VALUE_TEMPLATE = "Add new value '{}' →"; * detect that it is an unknown value and handle that case. * * Based on https://stackoverflow.com/a/69842249 - * @param items - * @param options */ -function showQuickPickAllowingUnknown( - choices: readonly string[], - unknownValues: UnknownValuesOptions, - options: vscode.QuickPickOptions, + +interface CustomQuickPickItem extends vscode.QuickPickItem { + value: string; +} + +export function vscodeShowQuickPick( + items: readonly string[], + options: QuickPickOptions | undefined, ) { return new Promise((resolve, _reject) => { const quickPick = vscode.window.createQuickPick(); - const quickPickItems = choices.map((choice) => ({ - label: choice, - value: choice, + + const quickPickItems = items.map((item) => ({ + label: item, + value: item, })); + quickPick.items = quickPickItems; - if (options.title != null) { + if (options?.title != null) { quickPick.title = options.title; } - const { newValueTemplate = DEFAULT_NEW_VALUE_TEMPLATE } = unknownValues; + if (options?.defaultValue != null) { + quickPick.activeItems = quickPickItems.filter( + (item) => item.value === options.defaultValue, + ); + } + + if (options?.unknownValues) { + const newValueTemplate = + typeof options.unknownValues === "string" + ? options.unknownValues + : "Add new value '{}' →"; - quickPick.onDidChangeValue(() => { - quickPick.items = [ - ...quickPickItems, + quickPick.onDidChangeValue(() => { + quickPick.items = [ + ...quickPickItems, - // INJECT user values into proposed values - ...(choices.includes(quickPick.value) - ? [] - : [ - { - label: newValueTemplate.replace("{}", quickPick.value), - value: quickPick.value, - }, - ]), - ]; - }); + // INJECT user values into proposed values + ...(items.includes(quickPick.value) || quickPick.value.trim() === "" + ? [] + : [ + { + label: newValueTemplate.replace("{}", quickPick.value), + value: quickPick.value, + }, + ]), + ]; + }); + } quickPick.onDidAccept(() => { const selection = quickPick.activeItems[0]; diff --git a/packages/test-case-recorder/src/ScopeTestRecorder.ts b/packages/test-case-recorder/src/ScopeTestRecorder.ts index 9158505738..d8068bddfc 100644 --- a/packages/test-case-recorder/src/ScopeTestRecorder.ts +++ b/packages/test-case-recorder/src/ScopeTestRecorder.ts @@ -118,6 +118,7 @@ export class ScopeTestRecorder { languageIds.sort(); return this.ide.showQuickPick(languageIds, { title: "Select language to record scope tests for", + defaultValue: this.ide.activeTextEditor?.document.languageId, }); } } diff --git a/packages/test-case-recorder/src/TestCaseRecorder.ts b/packages/test-case-recorder/src/TestCaseRecorder.ts index fb6dd24c6b..3466ea9790 100644 --- a/packages/test-case-recorder/src/TestCaseRecorder.ts +++ b/packages/test-case-recorder/src/TestCaseRecorder.ts @@ -418,10 +418,7 @@ export class TestCaseRecorder { walkDirsSync(this.fixtureRoot).concat("/"), { title: "Select directory for new test cases", - unknownValues: { - allowed: true, - newValueTemplate: "Create new directory '{}' →", - }, + unknownValues: "Create new directory '{}' →", }, );