summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMikheil Berishvili <[email protected]>2025-12-07 22:25:35 +0400
committerGitHub <[email protected]>2025-12-07 12:25:35 -0600
commit4eb82e8c0458af9c8713f1ebdb3933ad889561d5 (patch)
tree45ae51d63369757465c948fd79e2cba21f037044
parenta45f0aac90671a0082eb342056d564f59d66aa61 (diff)
downloadopencode-4eb82e8c0458af9c8713f1ebdb3933ad889561d5.tar.gz
opencode-4eb82e8c0458af9c8713f1ebdb3933ad889561d5.zip
fix: autocomplete popup repositions on window resize (#5196)
-rw-r--r--packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx48
1 files changed, 37 insertions, 11 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 c397bc23c..7db1b85af 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
@@ -1,13 +1,14 @@
import type { BoxRenderable, TextareaRenderable, KeyEvent } from "@opentui/core"
import fuzzysort from "fuzzysort"
import { firstBy } from "remeda"
-import { createMemo, createResource, createEffect, onMount, For, Show } from "solid-js"
+import { createMemo, createResource, createEffect, onMount, onCleanup, For, Show, createSignal } from "solid-js"
import { createStore } from "solid-js/store"
import { useSDK } from "@tui/context/sdk"
import { useSync } from "@tui/context/sync"
import { useTheme, selectedForeground } from "@tui/context/theme"
import { SplitBorder } from "@tui/component/border"
import { useCommandDialog } from "@tui/component/dialog-command"
+import { useTerminalDimensions } from "@opentui/solid"
import { Locale } from "@/util/locale"
import type { PromptInfo } from "./history"
@@ -41,13 +42,43 @@ export function Autocomplete(props: {
const sync = useSync()
const command = useCommandDialog()
const { theme } = useTheme()
+ const dimensions = useTerminalDimensions()
const [store, setStore] = createStore({
index: 0,
selected: 0,
visible: false as AutocompleteRef["visible"],
- position: { x: 0, y: 0, width: 0 },
})
+
+ const [positionTick, setPositionTick] = createSignal(0)
+
+ createEffect(() => {
+ if (store.visible) {
+ let lastPos = { x: 0, y: 0, width: 0 }
+ const interval = setInterval(() => {
+ const anchor = props.anchor()
+ if (anchor.x !== lastPos.x || anchor.y !== lastPos.y || anchor.width !== lastPos.width) {
+ lastPos = { x: anchor.x, y: anchor.y, width: anchor.width }
+ setPositionTick((t) => t + 1)
+ }
+ }, 50)
+
+ onCleanup(() => clearInterval(interval))
+ }
+ })
+
+ const position = createMemo(() => {
+ if (!store.visible) return { x: 0, y: 0, width: 0 }
+ const dims = dimensions()
+ positionTick()
+ const anchor = props.anchor()
+ return {
+ x: anchor.x,
+ y: anchor.y,
+ width: anchor.width,
+ }
+ })
+
const filter = createMemo(() => {
if (!store.visible) return
// Track props.value to make memo reactive to text changes
@@ -118,7 +149,7 @@ export function Autocomplete(props: {
// Add file options
if (!result.error && result.data) {
- const width = store.position.width - 4
+ const width = props.anchor().width - 4
options.push(
...result.data.map(
(item): AutocompleteOption => ({
@@ -361,11 +392,6 @@ export function Autocomplete(props: {
setStore({
visible: mode,
index: props.input().cursorOffset,
- position: {
- x: props.anchor().x,
- y: props.anchor().y,
- width: props.anchor().width,
- },
})
}
@@ -457,9 +483,9 @@ export function Autocomplete(props: {
<box
visible={store.visible !== false}
position="absolute"
- top={store.position.y - height()}
- left={store.position.x}
- width={store.position.width}
+ top={position().y - height()}
+ left={position().x}
+ width={position().width}
zIndex={100}
{...SplitBorder}
borderColor={theme.border}