summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorindeep99 <[email protected]>2026-01-11 22:01:48 -0500
committerGitHub <[email protected]>2026-01-11 22:01:48 -0500
commit82b432349e4063f612f54758ba78999b75cf13fb (patch)
treeb8f57c2fa18bf8296265bd4841c6795c883e958c
parent68ed664a3f08c64061af0781bbcc345ebd245f5a (diff)
downloadopencode-82b432349e4063f612f54758ba78999b75cf13fb.tar.gz
opencode-82b432349e4063f612f54758ba78999b75cf13fb.zip
feat(tui): add mouse hover and click support to questions tool (#7905)
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/question.tsx77
1 files changed, 46 insertions, 31 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/question.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/question.tsx
index e43f4219b..c6518ec3f 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/question.tsx
+++ b/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}>