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 }} + >