From e0bb50950fb9706116564f21634ab4660e7f94d4 Mon Sep 17 00:00:00 2001
From: GGX <1056937524@qq.com>
Date: Mon, 15 Dec 2025 22:08:50 +0800
Subject: [PATCH 1/4] feat(tui): implement smooth scrolling for autocomplete
dropdown navigation
---
.../cmd/tui/component/prompt/autocomplete.tsx | 39 +++++++++++++------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
index 37e6ccda5de0..0deeb73cfb45 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
@@ -1,4 +1,4 @@
-import type { BoxRenderable, TextareaRenderable, KeyEvent } from "@opentui/core"
+import type { BoxRenderable, TextareaRenderable, KeyEvent, ScrollBoxRenderable } from "@opentui/core"
import fuzzysort from "fuzzysort"
import { firstBy } from "remeda"
import { createMemo, createResource, createEffect, onMount, onCleanup, For, Show, createSignal } from "solid-js"
@@ -360,10 +360,9 @@ export function Autocomplete(props: {
store.visible === "@" ? [...agents(), ...(files.loading ? files.latest || [] : files())] : [...commands()]
).filter((x) => x.disabled !== true)
const currentFilter = filter()
- if (!currentFilter) return mixed.slice(0, 10)
+ if (!currentFilter) return mixed
const result = fuzzysort.go(currentFilter, mixed, {
keys: [(obj) => obj.display.trimEnd(), "description", (obj) => obj.aliases?.join(" ") ?? ""],
- limit: 10,
})
return result.map((arr) => arr.obj)
})
@@ -373,15 +372,29 @@ export function Autocomplete(props: {
setStore("selected", 0)
})
- function move(direction: -1 | 1) {
- if (!store.visible) return
- if (!options().length) return
- let next = store.selected + direction
- if (next < 0) next = options().length - 1
- if (next >= options().length) next = 0
- setStore("selected", next)
+ function move(direction: -1 | 1) {
+ if (!store.visible) return
+ if (!options().length) return
+ let next = store.selected + direction
+ if (next < 0) next = options().length - 1
+ if (next >= options().length) next = 0
+ moveTo(next)
}
+ function moveTo(next: number) {
+ setStore("selected", next);
+ if (!scroll) return;
+
+ const viewportHeight = Math.min(10, options().length);
+ const scrollBottom = scroll.scrollTop + viewportHeight;
+
+ if (next < scroll.scrollTop) {
+ scroll.scrollBy(next - scroll.scrollTop);
+ } else if (next + 1 > scrollBottom) {
+ scroll.scrollBy((next + 1) - scrollBottom);
+ }
+ }
+
function select() {
const selected = options()[store.selected]
if (!selected) return
@@ -481,6 +494,8 @@ export function Autocomplete(props: {
return 1
})
+ let scroll: ScrollBoxRenderable
+
return (
-
+ (scroll = r)} backgroundColor={theme.backgroundMenu} height={height()}>
)}
-
+
)
}
From 89659dd86dc6c96841fe799169faf095812e768e Mon Sep 17 00:00:00 2001
From: GGX <1056937524@qq.com>
Date: Mon, 15 Dec 2025 22:34:45 +0800
Subject: [PATCH 2/4] feat(tui): replace hardcoded value with dynamic height
calculation in moveTo function
---
.../cli/cmd/tui/component/prompt/autocomplete.tsx | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
index 0deeb73cfb45..b21f6e32af15 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
@@ -372,12 +372,12 @@ export function Autocomplete(props: {
setStore("selected", 0)
})
- function move(direction: -1 | 1) {
- if (!store.visible) return
- if (!options().length) return
- let next = store.selected + direction
- if (next < 0) next = options().length - 1
- if (next >= options().length) next = 0
+ function move(direction: -1 | 1) {
+ if (!store.visible) return
+ if (!options().length) return
+ let next = store.selected + direction
+ if (next < 0) next = options().length - 1
+ if (next >= options().length) next = 0
moveTo(next)
}
@@ -385,7 +385,7 @@ export function Autocomplete(props: {
setStore("selected", next);
if (!scroll) return;
- const viewportHeight = Math.min(10, options().length);
+ const viewportHeight = Math.min(height(), options().length);
const scrollBottom = scroll.scrollTop + viewportHeight;
if (next < scroll.scrollTop) {
From 5322f46085a12570ffcbe9081ffae1fc1e1b7468 Mon Sep 17 00:00:00 2001
From: Sherlock Holmes <1056937524@qq.com>
Date: Tue, 16 Dec 2025 13:19:02 +0800
Subject: [PATCH 3/4] Refactor move and moveTo functions for clarity
---
.../cmd/tui/component/prompt/autocomplete.tsx | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
index ff61baef0079..cc5a95e33641 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
@@ -383,23 +383,21 @@ export function Autocomplete(props: {
function move(direction: -1 | 1) {
if (!store.visible) return
if (!options().length) return
- let next = store.selected + direction
+ let next = store.selected + direction
if (next < 0) next = options().length - 1
if (next >= options().length) next = 0
moveTo(next)
}
- function moveTo(next: number) {
- setStore("selected", next);
- if (!scroll) return;
-
- const viewportHeight = Math.min(height(), options().length);
- const scrollBottom = scroll.scrollTop + viewportHeight;
-
+ function moveTo(next: number) {
+ setStore("selected", next)
+ if (!scroll) return
+ const viewportHeight = Math.min(height(), options().length)
+ const scrollBottom = scroll.scrollTop + viewportHeight
if (next < scroll.scrollTop) {
- scroll.scrollBy(next - scroll.scrollTop);
+ scroll.scrollBy(next - scroll.scrollTop)
} else if (next + 1 > scrollBottom) {
- scroll.scrollBy((next + 1) - scrollBottom);
+ scroll.scrollBy((next + 1) - scrollBottom)
}
}
From 9df8ff297f4e5ca7eb6e65fb6d87c190fc814118 Mon Sep 17 00:00:00 2001
From: Aiden Cline
Date: Fri, 19 Dec 2025 00:34:51 -0600
Subject: [PATCH 4/4] tweak: hide sidebar
---
.../src/cli/cmd/tui/component/prompt/autocomplete.tsx | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
index ffc0497d7fd2..b2221a3b6cac 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
@@ -406,10 +406,10 @@ export function Autocomplete(props: {
if (next < scroll.scrollTop) {
scroll.scrollBy(next - scroll.scrollTop)
} else if (next + 1 > scrollBottom) {
- scroll.scrollBy((next + 1) - scrollBottom)
+ scroll.scrollBy(next + 1 - scrollBottom)
}
}
-
+
function select() {
const selected = options()[store.selected]
if (!selected) return
@@ -522,7 +522,12 @@ export function Autocomplete(props: {
{...SplitBorder}
borderColor={theme.border}
>
- (scroll = r)} backgroundColor={theme.backgroundMenu} height={height()}>
+ (scroll = r)}
+ backgroundColor={theme.backgroundMenu}
+ height={height()}
+ scrollbarOptions={{ visible: false }}
+ >