From 9156f0d7c8439a1b5feb851f46487de6fdf3688b Mon Sep 17 00:00:00 2001 From: Brett Kulp Date: Thu, 21 May 2026 20:05:11 -0500 Subject: [PATCH 1/2] fix vim_system_clipboard_register=true put/yank not working on Linux --- .../cli/cmd/tui/component/prompt/index.tsx | 12 +++---- .../src/cli/cmd/tui/util/clipboard.ts | 36 ++++++++++++++----- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index a8f3b01d943e..eb2e71da930b 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -590,14 +590,15 @@ export function Prompt(props: PromptProps) { }) } - function setVimRegister(register: VimRegister, notify = false) { + async function setVimRegister(register: VimRegister, notify = false) { if (!useSystemClipboardRegister()) { vimState.setRegister(register) return } clipboardRegister = register if (!register) return - Clipboard.copy(register.text) + + await Clipboard.copy(register.text) .then(() => { if (notify) toast.show({ message: "Copied to clipboard", variant: "info" }) }) @@ -606,11 +607,8 @@ export function Prompt(props: PromptProps) { async function syncVimRegisterFromClipboard() { if (!useSystemClipboardRegister()) return - const content = await Clipboard.read() - if (content?.mime !== "text/plain" || !content.data) { - clipboardRegister = null - return - } + const content = await Clipboard.read().catch(() => undefined) + if (content?.mime !== "text/plain" || !content.data) return clipboardRegister = { text: content.data, linewise: clipboardRegister?.text === content.data ? clipboardRegister.linewise : false, diff --git a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts index c34563411e50..8e10a14fb02e 100644 --- a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts +++ b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts @@ -104,15 +104,35 @@ export async function read(): Promise { } if (os === "linux") { - const wayland = await Process.run(["wl-paste", "-t", "image/png"], { nothrow: true }) - if (wayland.stdout.byteLength > 0) { - return { data: Buffer.from(wayland.stdout).toString("base64"), mime: "image/png" } + const which = await getWhich() + const hasWlPaste = !!process.env["WAYLAND_DISPLAY"] && which("wl-paste") + + if (hasWlPaste) { + const wayland = await Process.run(["wl-paste", "-t", "image/png"], { nothrow: true }) + if (wayland.stdout.byteLength > 0) { + return { data: Buffer.from(wayland.stdout).toString("base64"), mime: "image/png" } + } } - const x11 = await Process.run(["xclip", "-selection", "clipboard", "-t", "image/png", "-o"], { - nothrow: true, - }) - if (x11.stdout.byteLength > 0) { - return { data: Buffer.from(x11.stdout).toString("base64"), mime: "image/png" } + + if (!hasWlPaste) { + const x11 = await Process.run(["xclip", "-selection", "clipboard", "-t", "image/png", "-o"], { + nothrow: true, + }) + if (x11.stdout.byteLength > 0) { + return { data: Buffer.from(x11.stdout).toString("base64"), mime: "image/png" } + } + } + + // Read text via native tools before falling back to clipboardy + if (hasWlPaste) { + const text = await Process.text(["wl-paste", "--no-newline"], { nothrow: true }) + if (text.text) return { data: text.text, mime: "text/plain" } + } else if (which("xclip")) { + const text = await Process.text(["xclip", "-selection", "clipboard", "-o"], { nothrow: true }) + if (text.text) return { data: text.text, mime: "text/plain" } + } else if (which("xsel")) { + const text = await Process.text(["xsel", "--clipboard", "--output"], { nothrow: true }) + if (text.text) return { data: text.text, mime: "text/plain" } } } From 8c4fa74a8e7db7f2aee42e045ec21b322bf862cf Mon Sep 17 00:00:00 2001 From: Brett Kulp Date: Fri, 22 May 2026 17:00:40 -0500 Subject: [PATCH 2/2] restore clipboardRegister on Clipboard.read() error --- .../opencode/src/cli/cmd/tui/component/prompt/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index eb2e71da930b..1d056da9363b 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -608,7 +608,11 @@ export function Prompt(props: PromptProps) { async function syncVimRegisterFromClipboard() { if (!useSystemClipboardRegister()) return const content = await Clipboard.read().catch(() => undefined) - if (content?.mime !== "text/plain" || !content.data) return + if (!content) return + if (content.mime !== "text/plain" || !content.data) { + clipboardRegister = null + return + } clipboardRegister = { text: content.data, linewise: clipboardRegister?.text === content.data ? clipboardRegister.linewise : false,