diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 1463c813e8a..53c66d85c06 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -15,7 +15,7 @@ import { usePromptStash } from "./stash" import { DialogStash } from "../dialog-stash" import { type AutocompleteRef, Autocomplete } from "./autocomplete" import { useCommandDialog } from "../dialog-command" -import { useRenderer } from "@opentui/solid" +import { useRenderer, useKeyboard } from "@opentui/solid" import { Editor } from "@tui/util/editor" import { useExit } from "../../context/exit" import { Clipboard } from "../../util/clipboard" @@ -610,6 +610,33 @@ export function Prompt(props: PromptProps) { } const exit = useExit() + let lastEscTime = 0 + const DOUBLE_ESC_THRESHOLD = 300 + + // Global keyboard handler for double-ESC to clear input + useKeyboard((evt) => { + if (props.disabled) return + if (!input?.focused) return + if (evt.name !== "escape") return + if (store.prompt.input === "") return + if (dialog.stack.length > 0) return + + const now = Date.now() + if (now - lastEscTime < DOUBLE_ESC_THRESHOLD) { + input.clear() + input.extmarks.clear() + setStore("prompt", { + input: "", + parts: [], + }) + setStore("extmarkToPartIndex", new Map()) + lastEscTime = 0 + evt.preventDefault() + return + } + lastEscTime = now + }) + function pasteText(text: string, virtualText: string) { const currentOffset = input.visualCursor.offset const extmarkStart = currentOffset diff --git a/packages/web/src/content/docs/keybinds.mdx b/packages/web/src/content/docs/keybinds.mdx index 267d194c099..66eb03fa8e4 100644 --- a/packages/web/src/content/docs/keybinds.mdx +++ b/packages/web/src/content/docs/keybinds.mdx @@ -146,6 +146,7 @@ The OpenCode desktop app prompt input supports common Readline/Emacs-style short | `alt+d` | Kill next word | | `ctrl+t` | Transpose characters | | `ctrl+g` | Cancel popovers / abort running response | +| `esc esc`| Clear input field (double press) | ---