From f9ef27842a50cb524e9218fd24a6a88b5d5aaabb Mon Sep 17 00:00:00 2001
From: LukeParkerDev <10430890+Hona@users.noreply.github.com>
Date: Mon, 23 Feb 2026 10:42:06 +1000
Subject: [PATCH 1/3] fix(tui): align sidebar and global scroll physics with
config
---
packages/opencode/src/cli/cmd/tui/app.tsx | 3 ++-
.../cmd/tui/component/prompt/autocomplete.tsx | 3 +++
.../src/cli/cmd/tui/routes/session/index.tsx | 23 ++-----------------
.../cli/cmd/tui/routes/session/permission.tsx | 3 +++
.../cli/cmd/tui/routes/session/sidebar.tsx | 4 ++++
.../src/cli/cmd/tui/ui/dialog-select.tsx | 6 +++++
.../opencode/src/cli/cmd/tui/util/scroll.ts | 23 +++++++++++++++++++
7 files changed, 43 insertions(+), 22 deletions(-)
create mode 100644 packages/opencode/src/cli/cmd/tui/util/scroll.ts
diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx
index ab3d09689252..b38ad60d0819 100644
--- a/packages/opencode/src/cli/cmd/tui/app.tsx
+++ b/packages/opencode/src/cli/cmd/tui/app.tsx
@@ -38,6 +38,7 @@ import { ArgsProvider, useArgs, type Args } from "./context/args"
import open from "open"
import { writeHeapSnapshot } from "v8"
import { PromptRefProvider, usePromptRef } from "./context/prompt"
+import { getScrollAcceleration } from "./util/scroll"
async function getTerminalBackgroundColor(): Promise<"dark" | "light"> {
// can't set raw mode if not a TTY
@@ -831,7 +832,7 @@ function ErrorComponent(props: {
Exit
-
+
{props.error.stack}
{props.error.message}
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 3240afab326a..c3eed5eac2e8 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
@@ -6,6 +6,7 @@ import { createMemo, createResource, createEffect, onMount, onCleanup, Index, Sh
import { createStore } from "solid-js/store"
import { useSDK } from "@tui/context/sdk"
import { useSync } from "@tui/context/sync"
+import { getScrollAcceleration } from "../../util/scroll"
import { useTheme, selectedForeground } from "@tui/context/theme"
import { SplitBorder } from "@tui/component/border"
import { useCommandDialog } from "@tui/component/dialog-command"
@@ -605,6 +606,7 @@ export function Autocomplete(props: {
})
let scroll: ScrollBoxRenderable
+ const scrollAcceleration = createMemo(() => getScrollAcceleration(sync.data.config.tui))
return (
timestamps() === "show")
const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4)
- const scrollAcceleration = createMemo(() => {
- const tui = sync.data.config.tui
- if (tui?.scroll_acceleration?.enabled) {
- return new MacOSScrollAccel()
- }
- if (tui?.scroll_speed) {
- return new CustomSpeedScroll(tui.scroll_speed)
- }
-
- return new CustomSpeedScroll(3)
- })
+ const scrollAcceleration = createMemo(() => getScrollAcceleration(sync.data.config.tui))
createEffect(async () => {
await sync.session
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
index 389fc2418cc6..7abb38239aa4 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
@@ -15,6 +15,7 @@ import { Keybind } from "@/util/keybind"
import { Locale } from "@/util/locale"
import { Global } from "@/global"
import { useDialog } from "../../ui/dialog"
+import { getScrollAcceleration } from "../../util/scroll"
type PermissionStage = "permission" | "always" | "reject"
@@ -61,12 +62,14 @@ function EditBody(props: { request: PermissionRequest }) {
})
const ft = createMemo(() => filetype(filepath()))
+ const scrollAcceleration = createMemo(() => getScrollAcceleration(sync.data.config.tui))
return (
sync.data.session_diff[props.sessionID] ?? [])
const todo = createMemo(() => sync.data.todo[props.sessionID] ?? [])
const messages = createMemo(() => sync.data.message[props.sessionID] ?? [])
+ const scrollAcceleration = createMemo(() => getScrollAcceleration(sync.data.config.tui))
const [expanded, setExpanded] = createStore({
mcp: true,
@@ -82,6 +85,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
>
{
title: string
@@ -50,6 +52,9 @@ export type DialogSelectRef = {
export function DialogSelect(props: DialogSelectProps) {
const dialog = useDialog()
const { theme } = useTheme()
+ const sync = useSync()
+ const scrollAcceleration = createMemo(() => getScrollAcceleration(sync.data.config.tui))
+
const [store, setStore] = createStore({
selected: 0,
filter: "",
@@ -275,6 +280,7 @@ export function DialogSelect(props: DialogSelectProps) {
paddingLeft={1}
paddingRight={1}
scrollbarOptions={{ visible: false }}
+ scrollAcceleration={scrollAcceleration()}
ref={(r: ScrollBoxRenderable) => (scroll = r)}
maxHeight={height()}
>
diff --git a/packages/opencode/src/cli/cmd/tui/util/scroll.ts b/packages/opencode/src/cli/cmd/tui/util/scroll.ts
new file mode 100644
index 000000000000..d34f0d48a09a
--- /dev/null
+++ b/packages/opencode/src/cli/cmd/tui/util/scroll.ts
@@ -0,0 +1,23 @@
+import { MacOSScrollAccel, type ScrollAcceleration } from "@opentui/core"
+import type { Config } from "@opencode-ai/sdk/v2"
+
+export class CustomSpeedScroll implements ScrollAcceleration {
+ constructor(private speed: number) {}
+
+ tick(_now?: number): number {
+ return this.speed
+ }
+
+ reset(): void {}
+}
+
+export function getScrollAcceleration(tuiConfig?: Config["tui"]): ScrollAcceleration {
+ if (tuiConfig?.scroll_acceleration?.enabled) {
+ return new MacOSScrollAccel()
+ }
+ if (tuiConfig?.scroll_speed) {
+ return new CustomSpeedScroll(tuiConfig.scroll_speed)
+ }
+
+ return new CustomSpeedScroll(3)
+}
From 7d48823ff764ce8b6bd019c95a8473e7c78d1086 Mon Sep 17 00:00:00 2001
From: LukeParkerDev <10430890+Hona@users.noreply.github.com>
Date: Thu, 2 Apr 2026 09:00:35 +1000
Subject: [PATCH 2/3] remove test_resolve.ts
---
packages/opencode/test_resolve.ts | 2 --
1 file changed, 2 deletions(-)
delete mode 100644 packages/opencode/test_resolve.ts
diff --git a/packages/opencode/test_resolve.ts b/packages/opencode/test_resolve.ts
deleted file mode 100644
index f4aaf8f2ac58..000000000000
--- a/packages/opencode/test_resolve.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import core from "@opentui/core"
-console.log(require.resolve("@opentui/core"))
From c4d2178b33fb758d9ce893373d205cdba911807d Mon Sep 17 00:00:00 2001
From: LukeParkerDev <10430890+Hona@users.noreply.github.com>
Date: Thu, 2 Apr 2026 09:04:58 +1000
Subject: [PATCH 3/3] chore: remove temporary test files
---
packages/opencode/test_renderable.ts | 2 --
temp.ts | 1 -
2 files changed, 3 deletions(-)
delete mode 100644 packages/opencode/test_renderable.ts
delete mode 100644 temp.ts
diff --git a/packages/opencode/test_renderable.ts b/packages/opencode/test_renderable.ts
deleted file mode 100644
index bb411ce43f25..000000000000
--- a/packages/opencode/test_renderable.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Renderable } from "@opentui/core"
-console.log(typeof ({} as Renderable).hasSelection)
diff --git a/temp.ts b/temp.ts
deleted file mode 100644
index 3b8dd03d21d5..000000000000
--- a/temp.ts
+++ /dev/null
@@ -1 +0,0 @@
-import { Renderable } from "@opentui/core"; type T = Renderable["hasSelection"];