Skip to content

Commit 28f0d3f

Browse files
committed
fix(tui): support middle-click paste from X11 primary selection
1 parent 54078c4 commit 28f0d3f

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BoxRenderable, TextareaRenderable, MouseEvent, PasteEvent, decodePasteBytes } from "@opentui/core"
1+
import { BoxRenderable, TextareaRenderable, MouseEvent, MouseButton, PasteEvent, decodePasteBytes } from "@opentui/core"
22
import { createEffect, createMemo, onMount, createSignal, onCleanup, on, Show, Switch, Match } from "solid-js"
33
import "opentui-spinner/solid"
44
import path from "path"
@@ -1106,7 +1106,15 @@ export function Prompt(props: PromptProps) {
11061106
input.cursorColor = theme.text
11071107
}, 0)
11081108
}}
1109-
onMouseDown={(r: MouseEvent) => r.target?.focus()}
1109+
onMouseDown={async (r: MouseEvent) => {
1110+
r.target?.focus()
1111+
if (r.button !== MouseButton.MIDDLE) return
1112+
if (props.disabled) return
1113+
r.preventDefault()
1114+
const text = await Clipboard.readPrimary()
1115+
if (!text || !input || input.isDestroyed) return
1116+
input.insertText(text)
1117+
}}
11101118
focusedBackgroundColor={theme.backgroundElement}
11111119
cursorColor={theme.text}
11121120
syntaxStyle={syntax()}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,23 @@ export async function read(): Promise<Content | undefined> {
110110
}
111111
}
112112

113+
export async function readPrimary(): Promise<string | undefined> {
114+
if (platform() !== "linux") return
115+
const which = await getWhich()
116+
if (process.env["WAYLAND_DISPLAY"] && which("wl-paste")) {
117+
const result = await Process.text(["wl-paste", "--primary", "--no-newline"], { nothrow: true })
118+
if (result.text) return result.text
119+
}
120+
if (which("xclip")) {
121+
const result = await Process.text(["xclip", "-selection", "primary", "-o"], { nothrow: true })
122+
if (result.text) return result.text
123+
}
124+
if (which("xsel")) {
125+
const result = await Process.text(["xsel", "--primary", "--output"], { nothrow: true })
126+
if (result.text) return result.text
127+
}
128+
}
129+
113130
const getCopyMethod = lazy(async () => {
114131
const os = platform()
115132
const which = await getWhich()

0 commit comments

Comments
 (0)