Просмотр исходного кода

Revert "add dialog prompt submit keybind (#27807)" (#27815)

Sebastian 3 месяцев назад
Родитель
Сommit
cc9c0b15c7

+ 0 - 1
packages/opencode/src/cli/cmd/tui/config/keybind.ts

@@ -188,7 +188,6 @@ 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"),

+ 8 - 33
packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx

@@ -1,10 +1,8 @@
 import { TextareaRenderable, TextAttributes } from "@opentui/core"
 import { useTheme } from "../context/theme"
 import { useDialog, type DialogContext } from "./dialog"
-import { Show, createEffect, createSignal, onMount, type JSX } from "solid-js"
+import { Show, createEffect, 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
@@ -20,32 +18,8 @@ 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<TextareaRenderable>()
   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(() => {
@@ -85,10 +59,13 @@ export function DialogPrompt(props: DialogPromptProps) {
       <box gap={1}>
         {props.description}
         <textarea
+          onSubmit={() => {
+            if (props.busy) return
+            props.onConfirm?.(textarea.plainText)
+          }}
           height={3}
           ref={(val: TextareaRenderable) => {
             textarea = val
-            setTextareaTarget(val)
           }}
           initialValue={props.value}
           placeholder={props.placeholder ?? "Enter text"}
@@ -103,11 +80,9 @@ export function DialogPrompt(props: DialogPromptProps) {
       </box>
       <box paddingBottom={1} gap={1} flexDirection="row">
         <Show when={!props.busy} fallback={<text fg={theme.textMuted}>processing...</text>}>
-          <Show when={submitShortcut()}>
-            <text fg={theme.text}>
-              {submitShortcut()} <span style={{ fg: theme.textMuted }}>submit</span>
-            </text>
-          </Show>
+          <text fg={theme.text}>
+            enter <span style={{ fg: theme.textMuted }}>submit</span>
+          </text>
         </Show>
       </box>
     </box>

+ 0 - 146
packages/opencode/test/cli/tui/dialog-prompt.test.tsx

@@ -1,146 +0,0 @@
-/** @jsxImportSource @opentui/solid */
-import { TextareaRenderable } from "@opentui/core"
-import { createDefaultOpenTuiKeymap } from "@opentui/keymap/opentui"
-import { testRender, useRenderer } from "@opentui/solid"
-import { expect, test } from "bun:test"
-import { mkdir } from "node:fs/promises"
-import path from "node:path"
-import { onCleanup } from "solid-js"
-import { tmpdir } from "../../fixture/fixture"
-import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
-import type { TuiKeybind } from "../../../src/cli/cmd/tui/config/keybind"
-
-async function wait(fn: () => boolean, timeout = 2000) {
-  const start = Date.now()
-  while (!fn()) {
-    if (Date.now() - start > timeout) throw new Error("timed out waiting for condition")
-    await Bun.sleep(10)
-  }
-}
-
-async function mountPrompt(input: {
-  root: string
-  keybinds: Partial<TuiKeybind.Keybinds>
-  onConfirm: (value: string) => void
-}) {
-  const { Global } = await import("@opencode-ai/core/global")
-  const previous = {
-    config: Global.Path.config,
-    state: Global.Path.state,
-  }
-  Global.Path.config = path.join(input.root, "config")
-  Global.Path.state = path.join(input.root, "state")
-  await mkdir(Global.Path.config, { recursive: true })
-  await mkdir(Global.Path.state, { recursive: true })
-  await Bun.write(path.join(Global.Path.state, "kv.json"), "{}")
-
-  const [
-    { DialogProvider },
-    { DialogPrompt },
-    { KVProvider },
-    { ThemeProvider },
-    { TuiConfigProvider },
-    { ToastProvider },
-    { OpencodeKeymapProvider, registerOpencodeKeymap },
-  ] = await Promise.all([
-    import("../../../src/cli/cmd/tui/ui/dialog"),
-    import("../../../src/cli/cmd/tui/ui/dialog-prompt"),
-    import("../../../src/cli/cmd/tui/context/kv"),
-    import("../../../src/cli/cmd/tui/context/theme"),
-    import("../../../src/cli/cmd/tui/context/tui-config"),
-    import("../../../src/cli/cmd/tui/ui/toast"),
-    import("../../../src/cli/cmd/tui/keymap"),
-  ])
-
-  function Harness() {
-    const renderer = useRenderer()
-    const keymap = createDefaultOpenTuiKeymap(renderer)
-    const resolvedConfig = createTuiResolvedConfig({
-      keybinds: input.keybinds,
-      leader_timeout: 1000,
-    })
-    const off = registerOpencodeKeymap(keymap, renderer, resolvedConfig)
-    onCleanup(off)
-
-    return (
-      <OpencodeKeymapProvider keymap={keymap}>
-        <TuiConfigProvider config={resolvedConfig}>
-          <KVProvider>
-            <ThemeProvider mode="dark">
-              <ToastProvider>
-                <DialogProvider>
-                  <DialogPrompt title="Rename Session" value="draft" onConfirm={input.onConfirm} />
-                </DialogProvider>
-              </ToastProvider>
-            </ThemeProvider>
-          </KVProvider>
-        </TuiConfigProvider>
-      </OpencodeKeymapProvider>
-    )
-  }
-
-  const app = await testRender(() => <Harness />, { kittyKeyboard: true })
-  return {
-    app,
-    async cleanup() {
-      app.renderer.destroy()
-      Global.Path.config = previous.config
-      Global.Path.state = previous.state
-    },
-  }
-}
-
-test("dialog prompt submit wins when return is also input newline", async () => {
-  await using tmp = await tmpdir()
-  const confirmed: string[] = []
-  const prompt = await mountPrompt({
-    root: tmp.path,
-    keybinds: {
-      input_submit: "super+return",
-      input_newline: "return,shift+return,alt+return,ctrl+j",
-    },
-    onConfirm: (value) => confirmed.push(value),
-  })
-
-  try {
-    await wait(() => prompt.app.renderer.currentFocusedEditor instanceof TextareaRenderable)
-    const textarea = prompt.app.renderer.currentFocusedEditor
-    if (!(textarea instanceof TextareaRenderable)) throw new Error("expected focused dialog textarea")
-
-    prompt.app.mockInput.pressEnter()
-
-    expect(confirmed).toEqual(["draft"])
-    expect(textarea.plainText).toBe("draft")
-  } finally {
-    await prompt.cleanup()
-  }
-})
-
-test("dialog prompt submit can be rebound separately from input submit", async () => {
-  await using tmp = await tmpdir()
-  const confirmed: string[] = []
-  const prompt = await mountPrompt({
-    root: tmp.path,
-    keybinds: {
-      input_submit: "return",
-      "dialog.prompt.submit": "ctrl+y",
-    },
-    onConfirm: (value) => confirmed.push(value),
-  })
-
-  try {
-    await wait(() => prompt.app.renderer.currentFocusedEditor instanceof TextareaRenderable)
-    const textarea = prompt.app.renderer.currentFocusedEditor
-    if (!(textarea instanceof TextareaRenderable)) throw new Error("expected focused dialog textarea")
-
-    prompt.app.mockInput.pressEnter()
-    expect(confirmed).toEqual([])
-    expect(textarea.plainText).toBe("draft")
-
-    prompt.app.mockInput.pressKey("y", { ctrl: true })
-
-    expect(confirmed).toEqual(["draft"])
-  } finally {
-    await prompt.cleanup()
-  }
-})

+ 0 - 2
packages/opencode/test/config/tui.test.ts

@@ -470,7 +470,6 @@ it.instance("resolves keybind lookup from canonical keybinds", () =>
           which_key_toggle: "alt+k",
           editor_open: "ctrl+e",
           "prompt.autocomplete.next": "ctrl+j",
-          "dialog.prompt.submit": "ctrl+s",
           "dialog.mcp.toggle": "ctrl+t",
           model_favorite_toggle: "ctrl+f",
           "dialog.plugins.install": "shift+i",
@@ -492,7 +491,6 @@ it.instance("resolves keybind lookup from canonical keybinds", () =>
       )
       expect(config.keybinds.get("prompt.editor")?.[0]?.key).toBe("ctrl+e")
       expect(config.keybinds.get("prompt.autocomplete.next")?.[0]?.key).toBe("ctrl+j")
-      expect(config.keybinds.get("dialog.prompt.submit")?.[0]?.key).toBe("ctrl+s")
       expect(config.keybinds.get("dialog.mcp.toggle")?.[0]?.key).toBe("ctrl+t")
       expect(config.keybinds.get("model.dialog.favorite")?.[0]?.key).toBe("ctrl+f")
       expect(config.keybinds.get("dialog.plugins.install")?.[0]?.key).toBe("shift+i")

+ 0 - 1
packages/web/src/content/docs/keybinds.mdx

@@ -145,7 +145,6 @@ OpenCode has a list of keybinds that you can customize through `tui.json`.
     "dialog.select.home": "home",
     "dialog.select.end": "end",
     "dialog.select.submit": "return",
-    "dialog.prompt.submit": "return",
     "dialog.mcp.toggle": "space",
     "prompt.autocomplete.prev": "up,ctrl+p",
     "prompt.autocomplete.next": "down,ctrl+n",