Przeglądaj źródła

feat(tui): add mouse hover and click support to questions tool (#7905)

indeep99 1 miesiąc temu
rodzic
commit
82b432349e

+ 46 - 31
packages/opencode/src/cli/cmd/tui/routes/session/question.tsx

@@ -86,6 +86,38 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
     setStore("answers", answers)
   }
 
+  function moveTo(index: number) {
+    setStore("selected", index)
+  }
+
+  function selectTab(index: number) {
+    setStore("tab", index)
+    setStore("selected", 0)
+  }
+
+  function selectOption() {
+    if (other()) {
+      if (!multi()) {
+        setStore("editing", true)
+        return
+      }
+      const value = input()
+      if (value && customPicked()) {
+        toggle(value)
+        return
+      }
+      setStore("editing", true)
+      return
+    }
+    const opt = options()[store.selected]
+    if (!opt) return
+    if (multi()) {
+      toggle(opt.label)
+      return
+    }
+    pick(opt.label)
+  }
+
   const dialog = useDialog()
 
   useKeyboard((evt) => {
@@ -149,16 +181,12 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
 
     if (evt.name === "left" || evt.name === "h") {
       evt.preventDefault()
-      const next = (store.tab - 1 + tabs()) % tabs()
-      setStore("tab", next)
-      setStore("selected", 0)
+      selectTab((store.tab - 1 + tabs()) % tabs())
     }
 
     if (evt.name === "right" || evt.name === "l") {
       evt.preventDefault()
-      const next = (store.tab + 1) % tabs()
-      setStore("tab", next)
-      setStore("selected", 0)
+      selectTab((store.tab + 1) % tabs())
     }
 
     if (confirm()) {
@@ -176,36 +204,17 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
 
       if (evt.name === "up" || evt.name === "k") {
         evt.preventDefault()
-        setStore("selected", (store.selected - 1 + total) % total)
+        moveTo((store.selected - 1 + total) % total)
       }
 
       if (evt.name === "down" || evt.name === "j") {
         evt.preventDefault()
-        setStore("selected", (store.selected + 1) % total)
+        moveTo((store.selected + 1) % total)
       }
 
       if (evt.name === "return") {
         evt.preventDefault()
-        if (other()) {
-          if (!multi()) {
-            setStore("editing", true)
-            return
-          }
-          const value = input()
-          if (value && customPicked()) {
-            toggle(value)
-            return
-          }
-          setStore("editing", true)
-          return
-        }
-        const opt = opts[store.selected]
-        if (!opt) return
-        if (multi()) {
-          toggle(opt.label)
-          return
-        }
-        pick(opt.label)
+        selectOption()
       }
 
       if (evt.name === "escape" || keybind.match("app_exit", evt)) {
@@ -236,6 +245,7 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
                     paddingLeft={1}
                     paddingRight={1}
                     backgroundColor={isActive() ? theme.accent : theme.backgroundElement}
+                    onMouseUp={() => selectTab(index())}
                   >
                     <text fg={isActive() ? theme.selectedListItemText : isAnswered() ? theme.text : theme.textMuted}>
                       {q.header}
@@ -244,7 +254,12 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
                 )
               }}
             </For>
-            <box paddingLeft={1} paddingRight={1} backgroundColor={confirm() ? theme.accent : theme.backgroundElement}>
+            <box
+              paddingLeft={1}
+              paddingRight={1}
+              backgroundColor={confirm() ? theme.accent : theme.backgroundElement}
+              onMouseUp={() => selectTab(questions().length)}
+            >
               <text fg={confirm() ? theme.selectedListItemText : theme.textMuted}>Confirm</text>
             </box>
           </box>
@@ -264,7 +279,7 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
                   const active = () => i() === store.selected
                   const picked = () => store.answers[store.tab]?.includes(opt.label) ?? false
                   return (
-                    <box>
+                    <box onMouseOver={() => moveTo(i())} onMouseUp={() => selectOption()}>
                       <box flexDirection="row" gap={1}>
                         <box backgroundColor={active() ? theme.backgroundElement : undefined}>
                           <text fg={active() ? theme.secondary : picked() ? theme.success : theme.text}>
@@ -280,7 +295,7 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
                   )
                 }}
               </For>
-              <box>
+              <box onMouseOver={() => moveTo(options().length)} onMouseUp={() => selectOption()}>
                 <box flexDirection="row" gap={1}>
                   <box backgroundColor={other() ? theme.backgroundElement : undefined}>
                     <text fg={other() ? theme.secondary : customPicked() ? theme.success : theme.text}>