Skip to content

Commit 59ad2ce

Browse files
authored
Merge pull request #97 from alexyaroshuk/fix/tui-clipboard-paste-windows-fork
fix(tui): cannot paste clipboard text on windows
2 parents 02c68ca + 7c7cb0f commit 59ad2ce

1 file changed

Lines changed: 24 additions & 6 deletions

File tree

packages/opencode/src/cli/cmd/tui/util/clipboard.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,38 @@ export async function read(): Promise<Content | undefined> {
7474
}
7575
}
7676

77-
// Windows/WSL: probe clipboard for images via PowerShell.
78-
// Bracketed paste can't carry image data so we read it directly.
77+
// Windows/WSL: read image and text via PowerShell. clipboardy's bundled .exe
78+
// fails silently under Bun on Windows, so we bypass it for text too.
7979
if (os === "win32" || release().includes("WSL")) {
8080
const script =
81-
"Add-Type -AssemblyName System.Windows.Forms; $img = [System.Windows.Forms.Clipboard]::GetImage(); if ($img) { $ms = New-Object System.IO.MemoryStream; $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); [System.Convert]::ToBase64String($ms.ToArray()) }"
82-
const base64 = await Process.text(["powershell.exe", "-NonInteractive", "-NoProfile", "-command", script], {
81+
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; " +
82+
"Add-Type -AssemblyName System.Windows.Forms; " +
83+
"$img = [System.Windows.Forms.Clipboard]::GetImage(); " +
84+
"if ($img) { " +
85+
" $ms = New-Object System.IO.MemoryStream; " +
86+
" $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); " +
87+
" Write-Output ('IMG:' + [System.Convert]::ToBase64String($ms.ToArray())) " +
88+
"} else { " +
89+
" $t = Get-Clipboard -Raw; " +
90+
" if ($t) { Write-Output ('TXT:' + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($t))) } " +
91+
"}"
92+
const result = await Process.text(["powershell.exe", "-NonInteractive", "-NoProfile", "-Command", script], {
8393
nothrow: true,
8494
})
85-
if (base64.text) {
86-
const imageBuffer = Buffer.from(base64.text.trim(), "base64")
95+
const raw = result.text.trim()
96+
if (raw.startsWith("IMG:")) {
97+
const imageBuffer = Buffer.from(raw.slice(4), "base64")
8798
if (imageBuffer.length > 0) {
8899
return { data: imageBuffer.toString("base64"), mime: "image/png" }
89100
}
90101
}
102+
if (raw.startsWith("TXT:")) {
103+
const decoded = Buffer.from(raw.slice(4), "base64").toString("utf8")
104+
const normalized = decoded.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n$/, "")
105+
if (normalized.length > 0) {
106+
return { data: normalized, mime: "text/plain" }
107+
}
108+
}
91109
}
92110

93111
if (os === "linux") {

0 commit comments

Comments
 (0)