From d441e931f995d6be39058dfd9b19e5603385af36 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 16 May 2026 03:11:46 +0200 Subject: [PATCH] add dialog prompt submit keybind (#27807) --- .../src/cli/cmd/tui/config/keybind.ts | 1 + .../src/cli/cmd/tui/ui/dialog-prompt.tsx | 41 ++++- .../test/cli/tui/dialog-prompt.test.tsx | 146 ++++++++++++++++++ packages/opencode/test/config/tui.test.ts | 2 + packages/web/src/content/docs/keybinds.mdx | 1 + 5 files changed, 183 insertions(+), 8 deletions(-) create mode 100644 packages/opencode/test/cli/tui/dialog-prompt.test.tsx diff --git a/packages/opencode/src/cli/cmd/tui/config/keybind.ts b/packages/opencode/src/cli/cmd/tui/config/keybind.ts index bd26cd5d95..a375573828 100644 --- a/packages/opencode/src/cli/cmd/tui/config/keybind.ts +++ b/packages/opencode/src/cli/cmd/tui/config/keybind.ts @@ -188,6 +188,7 @@ export const Definitions = { "dialog.select.home": keybind("home", "Move to first dialog item"), "dialog.select.end": keybind("end", "Move to last dialog item"), "dialog.select.submit": keybind("return", "Submit selected dialog item"), + "dialog.prompt.submit": keybind("return", "Submit dialog prompt"), "dialog.mcp.toggle": keybind("space", "Toggle MCP in MCP dialog"), "prompt.autocomplete.prev": keybind("up,ctrl+p", "Move to previous autocomplete item"), "prompt.autocomplete.next": keybind("down,ctrl+n", "Move to next autocomplete item"), diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx index 34ab9161f6..dfd8091852 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx @@ -1,8 +1,10 @@ import { TextareaRenderable, TextAttributes } from "@opentui/core" import { useTheme } from "../context/theme" import { useDialog, type DialogContext } from "./dialog" -import { Show, createEffect, onMount, type JSX } from "solid-js" +import { Show, createEffect, createSignal, onMount, type JSX } from "solid-js" import { Spinner } from "../component/spinner" +import { useTuiConfig } from "../context/tui-config" +import { useBindings, useCommandShortcut } from "../keymap" export type DialogPromptProps = { title: string @@ -18,8 +20,32 @@ export type DialogPromptProps = { export function DialogPrompt(props: DialogPromptProps) { const dialog = useDialog() const { theme } = useTheme() + const tuiConfig = useTuiConfig() + const submitShortcut = useCommandShortcut("dialog.prompt.submit") + const [textareaTarget, setTextareaTarget] = createSignal() let textarea: TextareaRenderable + function confirm() { + if (props.busy) return + props.onConfirm?.(textarea.plainText) + } + + useBindings(() => ({ + target: textareaTarget, + enabled: textareaTarget() !== undefined && !props.busy, + // Dialog form semantics must win over the global managed textarea input layer. + priority: 1, + commands: [ + { + name: "dialog.prompt.submit", + title: "Submit dialog prompt", + category: "Dialog", + run: confirm, + }, + ], + bindings: tuiConfig.keybinds.gather("dialog.prompt", ["dialog.prompt.submit"]), + })) + onMount(() => { dialog.setSize("medium") setTimeout(() => { @@ -59,13 +85,10 @@ export function DialogPrompt(props: DialogPromptProps) { {props.description}