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

Preserve prompt input when creating new session (#4993)

Daniel Gray 2 месяцев назад
Родитель
Сommit
27c99b46cb

+ 9 - 1
packages/opencode/src/cli/cmd/tui/app.tsx

@@ -32,6 +32,7 @@ import { KVProvider, useKV } from "./context/kv"
 import { Provider } from "@/provider/provider"
 import { ArgsProvider, useArgs, type Args } from "./context/args"
 import open from "open"
+import { PromptRefProvider, usePromptRef } from "./context/prompt"
 
 async function getTerminalBackgroundColor(): Promise<"dark" | "light"> {
   // can't set raw mode if not a TTY
@@ -119,7 +120,9 @@ export function tui(input: { url: string; args: Args; onExit?: () => Promise<voi
                                 <DialogProvider>
                                   <CommandProvider>
                                     <PromptHistoryProvider>
-                                      <App />
+                                      <PromptRefProvider>
+                                        <App />
+                                      </PromptRefProvider>
                                     </PromptHistoryProvider>
                                   </CommandProvider>
                                 </DialogProvider>
@@ -160,6 +163,7 @@ function App() {
   const { theme, mode, setMode } = useTheme()
   const sync = useSync()
   const exit = useExit()
+  const promptRef = usePromptRef()
 
   createEffect(() => {
     console.log(JSON.stringify(route.data))
@@ -225,8 +229,12 @@ function App() {
       keybind: "session_new",
       category: "Session",
       onSelect: () => {
+        const current = promptRef.current
+        // Don't require focus - if there's any text, preserve it
+        const currentPrompt = current?.current?.input ? current.current : undefined
         route.navigate({
           type: "home",
+          initialPrompt: currentPrompt,
         })
         dialog.clear()
       },

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

@@ -37,6 +37,7 @@ export type PromptProps = {
 
 export type PromptRef = {
   focused: boolean
+  current: PromptInfo
   set(prompt: PromptInfo): void
   reset(): void
   blur(): void
@@ -377,6 +378,9 @@ export function Prompt(props: PromptProps) {
     get focused() {
       return input.focused
     },
+    get current() {
+      return store.prompt
+    },
     focus() {
       input.focus()
     },

+ 18 - 0
packages/opencode/src/cli/cmd/tui/context/prompt.tsx

@@ -0,0 +1,18 @@
+import { createSimpleContext } from "./helper"
+import type { PromptRef } from "../component/prompt"
+
+export const { use: usePromptRef, provider: PromptRefProvider } = createSimpleContext({
+  name: "PromptRef",
+  init: () => {
+    let current: PromptRef | undefined
+
+    return {
+      get current() {
+        return current
+      },
+      set(ref: PromptRef | undefined) {
+        current = ref
+      },
+    }
+  },
+})

+ 2 - 0
packages/opencode/src/cli/cmd/tui/context/route.tsx

@@ -1,8 +1,10 @@
 import { createStore } from "solid-js/store"
 import { createSimpleContext } from "./helper"
+import type { PromptInfo } from "../component/prompt/history"
 
 export type HomeRoute = {
   type: "home"
+  initialPrompt?: PromptInfo
 }
 
 export type SessionRoute = {

+ 16 - 6
packages/opencode/src/cli/cmd/tui/routes/home.tsx

@@ -1,15 +1,14 @@
 import { Prompt, type PromptRef } from "@tui/component/prompt"
-import { createMemo, Match, onMount, Show, Switch, type ParentProps } from "solid-js"
+import { createMemo, Match, onMount, Show, Switch } from "solid-js"
 import { useTheme } from "@tui/context/theme"
-import { useKeybind } from "../context/keybind"
-import type { KeybindsConfig } from "@opencode-ai/sdk"
 import { Logo } from "../component/logo"
 import { Locale } from "@/util/locale"
 import { useSync } from "../context/sync"
 import { Toast } from "../ui/toast"
 import { useArgs } from "../context/args"
-import { Global } from "@/global"
 import { useDirectory } from "../context/directory"
+import { useRoute, useRouteData } from "@tui/context/route"
+import { usePromptRef } from "../context/prompt"
 
 // TODO: what is the best way to do this?
 let once = false
@@ -17,6 +16,8 @@ let once = false
 export function Home() {
   const sync = useSync()
   const { theme } = useTheme()
+  const route = useRouteData("home")
+  const promptRef = usePromptRef()
   const mcp = createMemo(() => Object.keys(sync.data.mcp).length > 0)
   const mcpError = createMemo(() => {
     return Object.values(sync.data.mcp).some((x) => x.status === "failed")
@@ -45,7 +46,10 @@ export function Home() {
   const args = useArgs()
   onMount(() => {
     if (once) return
-    if (args.prompt) {
+    if (route.initialPrompt) {
+      prompt.set(route.initialPrompt)
+      once = true
+    } else if (args.prompt) {
       prompt.set({ input: args.prompt, parts: [] })
       once = true
     }
@@ -57,7 +61,13 @@ export function Home() {
       <box flexGrow={1} justifyContent="center" alignItems="center" paddingLeft={2} paddingRight={2} gap={1}>
         <Logo />
         <box width="100%" maxWidth={75} zIndex={1000} paddingTop={1}>
-          <Prompt ref={(r) => (prompt = r)} hint={Hint} />
+          <Prompt
+            ref={(r) => {
+              prompt = r
+              promptRef.set(r)
+            }}
+            hint={Hint}
+          />
         </box>
         <Toast />
       </box>

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

@@ -63,6 +63,7 @@ import { useKV } from "../../context/kv.tsx"
 import { Editor } from "../../util/editor"
 import stripAnsi from "strip-ansi"
 import { Footer } from "./footer.tsx"
+import { usePromptRef } from "../../context/prompt"
 
 addDefaultParsers(parsers.parsers)
 
@@ -99,6 +100,7 @@ export function Session() {
   const sync = useSync()
   const kv = useKV()
   const { theme } = useTheme()
+  const promptRef = usePromptRef()
   const session = createMemo(() => sync.session.get(route.sessionID)!)
   const messages = createMemo(() => sync.data.message[route.sessionID] ?? [])
   const permissions = createMemo(() => sync.data.permission[route.sessionID] ?? [])
@@ -949,7 +951,10 @@ export function Session() {
             </scrollbox>
             <box flexShrink={0}>
               <Prompt
-                ref={(r) => (prompt = r)}
+                ref={(r) => {
+                  prompt = r
+                  promptRef.set(r)
+                }}
                 disabled={permissions().length > 0}
                 onSubmit={() => {
                   toBottom()