Skip to content

Commit 1124315

Browse files
authored
run: refresh prompt layout after paste (anomalyco#28164)
Pasting into the prompt textarea left its layout stale until the next edit, so the visible content did not reflect the pasted text. Mark the layout dirty on paste and notify the content-change handler once the renderer is idle so the prompt updates immediately.
1 parent 2bf3f30 commit 1124315

1 file changed

Lines changed: 44 additions & 2 deletions

File tree

packages/opencode/src/cli/cmd/run/footer.prompt.tsx

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@
66
// while the footer view renders the current menu state below it.
77
/** @jsxImportSource @opentui/solid */
88
import { pathToFileURL } from "bun"
9-
import { StyledText, bg, fg, type KeyBinding, type KeyEvent, type TextareaRenderable } from "@opentui/core"
10-
import { useKeyboard } from "@opentui/solid"
9+
import {
10+
StyledText,
11+
bg,
12+
fg,
13+
type KeyBinding,
14+
type KeyEvent,
15+
type TextareaRenderable,
16+
} from "@opentui/core"
17+
import { useKeyboard, useRenderer } from "@opentui/solid"
1118
import fuzzysort from "fuzzysort"
1219
import path from "path"
1320
import { createEffect, createMemo, createResource, createSignal, onCleanup, onMount, type Accessor } from "solid-js"
@@ -197,13 +204,45 @@ export function RunPromptBody(props: {
197204
onContentChange: () => void
198205
bind: (area?: TextareaRenderable) => void
199206
}) {
207+
const renderer = useRenderer()
200208
let area: TextareaRenderable | undefined
209+
let pasteTick: ReturnType<typeof setTimeout> | undefined
210+
211+
const refreshPasteLayout = () => {
212+
if (pasteTick) {
213+
clearTimeout(pasteTick)
214+
}
215+
216+
pasteTick = setTimeout(() => {
217+
pasteTick = undefined
218+
if (!area || area.isDestroyed) {
219+
return
220+
}
221+
222+
// Paste can leave the textarea layout stale until the next edit.
223+
area.getLayoutNode().markDirty()
224+
renderer.requestRender()
225+
void renderer
226+
.idle()
227+
.then(() => {
228+
if (!area || area.isDestroyed) {
229+
return
230+
}
231+
232+
props.onContentChange()
233+
})
234+
.catch(() => {})
235+
}, 0)
236+
}
201237

202238
onMount(() => {
203239
props.bind(area)
204240
})
205241

206242
onCleanup(() => {
243+
if (pasteTick) {
244+
clearTimeout(pasteTick)
245+
}
207246
props.bind(undefined)
208247
})
209248

@@ -226,6 +265,9 @@ export function RunPromptBody(props: {
226265
keyBindings={props.bindings()}
227266
onSubmit={props.onSubmit}
228267
onKeyDown={props.onKeyDown}
268+
onPaste={() => {
269+
refreshPasteLayout()
270+
}}
229271
onContentChange={props.onContentChange}
230272
ref={(next) => {
231273
area = next

0 commit comments

Comments
 (0)