diff --git a/src/config-flow.ts b/src/config-flow.ts index 2941dff..b3324d4 100644 --- a/src/config-flow.ts +++ b/src/config-flow.ts @@ -90,6 +90,7 @@ async function selectModel( ): Promise { return runMenu({ message: t("select_model"), + searchable:true, items: models.map((m) => ({ label: `${m.name} (${m.key})`, value: m, diff --git a/src/utils/menu.ts b/src/utils/menu.ts index b533ebd..1d7271f 100644 --- a/src/utils/menu.ts +++ b/src/utils/menu.ts @@ -22,10 +22,11 @@ export interface MenuConfig { items: MenuItem[]; loop?: boolean; context?: MenuContext; + searchable?: boolean; } export async function runMenu(config: MenuConfig): Promise { - const { message, items, loop = false, context } = config; + const { message, items, loop = false, context, searchable = false } = config; const ctx = context ?? { logger: createLogger("Menu") }; @@ -40,6 +41,7 @@ export async function runMenu(config: MenuConfig): Promise { selected = await escSelect>({ message, choices, + searchable, }); } catch (err) { if (isPromptCancelled(err)) { diff --git a/src/utils/prompt.ts b/src/utils/prompt.ts index 19e13bd..414b3f0 100644 --- a/src/utils/prompt.ts +++ b/src/utils/prompt.ts @@ -1,4 +1,4 @@ -import { select, input, password } from "@inquirer/prompts"; +import { select, search, input, password } from "@inquirer/prompts"; /** * 用户通过 ESC 键取消 prompt 时抛出的错误 @@ -51,11 +51,36 @@ async function withEscapeCancel( * 支持 ESC 取消的 select */ export async function escSelect( - config: Parameters>[0], + config: Parameters>[0] & { searchable?: boolean }, context?: Parameters>[1] ): Promise { + const { searchable, ...selectConfig } = config; + + if (searchable) { + // Convert select config to search config + const choices = selectConfig.choices || []; + const searchConfig = { + message: selectConfig.message, + source: async (searchTerm: string | undefined) => { + const term = (searchTerm || "").toLowerCase(); + return choices.filter((choice) => { + if (choice && typeof choice === "object" && "name" in choice && choice.name) { + return choice.name.toLowerCase().includes(term); + } + return true; + }); + }, + pageSize: selectConfig.pageSize, + theme: selectConfig.theme, + }; + + return withEscapeCancel((signal) => + search(searchConfig as Parameters>[0], { ...context, signal }) + ); + } + return withEscapeCancel((signal) => - select(config, { ...context, signal }) + select(selectConfig, { ...context, signal }) ); }