fix(tui): copy pasted prompt content (#28156)

This commit is contained in:
Shoubhit Dash 2026-05-18 17:02:34 +05:30 committed by GitHub
parent c813927bb6
commit 564cde393e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 21 additions and 3 deletions

View File

@ -28,7 +28,7 @@ import { MessageID, PartID } from "@/session/schema"
import { createStore, produce, unwrap } from "solid-js/store" import { createStore, produce, unwrap } from "solid-js/store"
import { usePromptHistory, type PromptInfo } from "./history" import { usePromptHistory, type PromptInfo } from "./history"
import { computePromptTraits } from "./traits" import { computePromptTraits } from "./traits"
import { assign } from "./part" import { assign, expandPastedTextPlaceholders } from "./part"
import { usePromptStash } from "./stash" import { usePromptStash } from "./stash"
import { DialogStash } from "../dialog-stash" import { DialogStash } from "../dialog-stash"
import { type AutocompleteRef, Autocomplete } from "./autocomplete" import { type AutocompleteRef, Autocomplete } from "./autocomplete"
@ -1544,6 +1544,9 @@ export function Prompt(props: PromptProps) {
}} }}
ref={(r: TextareaRenderable) => { ref={(r: TextareaRenderable) => {
input = r input = r
Object.assign(r, {
getClipboardText: (text: string) => expandPastedTextPlaceholders(text, store.prompt.parts),
})
setInputTarget(r) setInputTarget(r)
if (promptPartTypeId === 0) { if (promptPartTypeId === 0) {
promptPartTypeId = input.extmarks.registerType("prompt-part") promptPartTypeId = input.extmarks.registerType("prompt-part")

View File

@ -14,3 +14,10 @@ export function assign(part: Item): Item & { id: PartID } {
id: PartID.ascending(), id: PartID.ascending(),
} }
} }
export function expandPastedTextPlaceholders(text: string, parts: PromptInfo["parts"]) {
return parts.reduce((result, part) => {
if (part.type !== "text" || !part.source?.text) return result
return result.replace(part.source.text.value, part.text)
}, text)
}

View File

@ -7,6 +7,7 @@ type Toast = {
type FocusableSelectionTarget = { type FocusableSelectionTarget = {
hasSelection: () => boolean hasSelection: () => boolean
getClipboardText?: (text: string) => string
} }
type Renderer = { type Renderer = {
@ -23,10 +24,17 @@ type SelectionKeyEvent = {
} }
export function copy(renderer: Renderer, toast: Toast): boolean { export function copy(renderer: Renderer, toast: Toast): boolean {
const text = renderer.getSelection()?.getSelectedText() const selection = renderer.getSelection()
if (!selection) return false
const text = selection.getSelectedText()
if (!text) return false if (!text) return false
Clipboard.copy(text) const focus = renderer.currentFocusedRenderable
const clipboardText =
focus?.getClipboardText && selection.selectedRenderables.includes(focus) ? focus.getClipboardText(text) : text
Clipboard.copy(clipboardText)
.then(() => toast.show({ message: "Copied to clipboard", variant: "info" })) .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
.catch(toast.error) .catch(toast.error)