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

tui: fix focus management and dialog interactions

Dax Raad 5 месяцев назад
Родитель
Сommit
f42e1c6375

+ 2 - 4
packages/opencode/script/publish.ts

@@ -125,10 +125,8 @@ if (!Script.preview) {
     "build() {",
     `  cd "opencode-\${pkgver}"`,
     `  bun install`,
-    "  cd packages/tui",
-    `  CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=\${pkgver}" -o tui cmd/opencode/main.go`,
-    "  cd ../opencode",
-    `  bun build --define OPENCODE_TUI_PATH="'$(realpath ../tui/tui)'" --define OPENCODE_VERSION="'\${pkgver}'" --compile --target=bun-linux-x64 --outfile=opencode ./src/index.ts`,
+    "  cd ./packages/opencode",
+    `  OPENCODE_CHANNEL=latest OPENCODE_VERSION=${pkgver} bun run ./script/build.ts --single`,
     "}",
     "",
     "package() {",

+ 1 - 0
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx

@@ -134,6 +134,7 @@ export function Prompt(props: PromptProps) {
         keybind: "input_submit",
         category: "Prompt",
         onSelect: (dialog) => {
+          if (!input.focused) return
           submit()
           dialog.clear()
         },

+ 3 - 12
packages/opencode/src/cli/cmd/tui/routes/home.tsx

@@ -1,5 +1,5 @@
-import { Prompt, type PromptRef } from "@tui/component/prompt"
-import { createEffect, createMemo, Match, Show, Switch, type ParentProps } from "solid-js"
+import { Prompt } from "@tui/component/prompt"
+import { createMemo, Match, Show, Switch, type ParentProps } from "solid-js"
 import { useTheme } from "@tui/context/theme"
 import { useKeybind } from "../context/keybind"
 import type { KeybindsConfig } from "@opencode-ai/sdk"
@@ -7,22 +7,13 @@ import { Logo } from "../component/logo"
 import { Locale } from "@/util/locale"
 import { useSync } from "../context/sync"
 import { Toast } from "../ui/toast"
-import { useDialog } from "../ui/dialog"
 
 export function Home() {
   const sync = useSync()
   const { theme } = useTheme()
-  const dialog = useDialog()
   const mcpError = createMemo(() => {
     return Object.values(sync.data.mcp).some((x) => x.status === "failed")
   })
-  let promptRef: PromptRef | undefined = undefined
-
-  createEffect(() => {
-    dialog.allClosedEvent.listen(() => {
-      promptRef?.focus()
-    })
-  })
 
   const Hint = (
     <Show when={Object.keys(sync.data.mcp).length > 0}>
@@ -64,7 +55,7 @@ export function Home() {
         <HelpRow keybind="agent_cycle">Switch agent</HelpRow>
       </box>
       <box width="100%" maxWidth={75} zIndex={1000} paddingTop={1}>
-        <Prompt hint={Hint} ref={(r) => (promptRef = r)} />
+        <Prompt hint={Hint} />
       </box>
       <Toast />
     </box>

+ 0 - 6
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

@@ -112,12 +112,6 @@ export function Session() {
   let prompt: PromptRef
   const keybind = useKeybind()
 
-  createEffect(() => {
-    dialog.allClosedEvent.listen(() => {
-      prompt.focus()
-    })
-  })
-
   useKeyboard((evt) => {
     if (dialog.stack.length > 0) return
 

+ 1 - 1
packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx

@@ -130,7 +130,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
     if (evt.name === "return") {
       const option = selected()
       if (option) {
-        evt.preventDefault()
+        // evt.preventDefault()
         if (option.onSelect) option.onSelect(dialog)
         props.onSelect?.(option)
       }

+ 4 - 21
packages/opencode/src/cli/cmd/tui/ui/dialog.tsx

@@ -1,17 +1,8 @@
 import { useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/solid"
-import {
-  batch,
-  createContext,
-  createEffect,
-  Show,
-  useContext,
-  type JSX,
-  type ParentProps,
-} from "solid-js"
+import { batch, createContext, Show, useContext, type JSX, type ParentProps } from "solid-js"
 import { useTheme } from "@tui/context/theme"
 import { Renderable, RGBA } from "@opentui/core"
 import { createStore } from "solid-js/store"
-import { createEventBus } from "@solid-primitives/event-bus"
 
 export function Dialog(
   props: ParentProps<{
@@ -59,7 +50,6 @@ function init() {
     }[],
     size: "medium" as "medium" | "large",
   })
-  const allClosedEvent = createEventBus<void>()
 
   useKeyboard((evt) => {
     if (evt.name === "escape" && store.stack.length > 0) {
@@ -90,12 +80,6 @@ function init() {
     }, 1)
   }
 
-  createEffect(() => {
-    if (store.stack.length === 0) {
-      allClosedEvent.emit()
-    }
-  })
-
   return {
     clear() {
       for (const item of store.stack) {
@@ -108,7 +92,9 @@ function init() {
       refocus()
     },
     replace(input: any, onClose?: () => void) {
-      if (store.stack.length === 0) focus = renderer.currentFocusedRenderable
+      if (store.stack.length === 0) {
+        focus = renderer.currentFocusedRenderable
+      }
       for (const item of store.stack) {
         if (item.onClose) item.onClose()
       }
@@ -129,9 +115,6 @@ function init() {
     setSize(size: "medium" | "large") {
       setStore("size", size)
     },
-    get allClosedEvent() {
-      return allClosedEvent
-    },
   }
 }
 

+ 1 - 0
packages/script/src/index.ts

@@ -20,6 +20,7 @@ const CHANNEL =
   (await $`git branch --show-current`.text().then((x) => x.trim()))
 const IS_PREVIEW = CHANNEL !== "latest"
 const VERSION = await (async () => {
+  if (process.env["OPENCODE_VERSION"]) return process.env["OPENCODE_VERSION"]
   if (IS_PREVIEW)
     return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
   const version = await fetch("https://registry.npmjs.org/opencode-ai/latest")