Skip to content

Commit 3bead6a

Browse files
committed
fix(tui): support middle-click paste from X11 primary selection
1 parent fff9863 commit 3bead6a

2 files changed

Lines changed: 38 additions & 2 deletions

File tree

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import { BoxRenderable, TextareaRenderable, MouseEvent, PasteEvent, decodePasteBytes, t, dim, fg } from "@opentui/core"
1+
import {
2+
BoxRenderable,
3+
TextareaRenderable,
4+
MouseEvent,
5+
MouseButton,
6+
PasteEvent,
7+
decodePasteBytes,
8+
t,
9+
dim,
10+
fg,
11+
} from "@opentui/core"
212
import { createEffect, createMemo, onMount, createSignal, onCleanup, on, Show, Switch, Match } from "solid-js"
313
import "opentui-spinner/solid"
414
import path from "path"
@@ -1080,7 +1090,15 @@ export function Prompt(props: PromptProps) {
10801090
input.cursorColor = theme.text
10811091
}, 0)
10821092
}}
1083-
onMouseDown={(r: MouseEvent) => r.target?.focus()}
1093+
onMouseDown={async (r: MouseEvent) => {
1094+
r.target?.focus()
1095+
if (r.button !== MouseButton.MIDDLE) return
1096+
if (props.disabled) return
1097+
r.preventDefault()
1098+
const text = await Clipboard.readPrimary()
1099+
if (!text || !input || input.isDestroyed) return
1100+
input.insertText(text)
1101+
}}
10841102
focusedBackgroundColor={theme.backgroundElement}
10851103
cursorColor={theme.text}
10861104
syntaxStyle={syntax()}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,24 @@ export namespace Clipboard {
101101
}
102102
}
103103

104+
export async function readPrimary(): Promise<string | undefined> {
105+
const os = platform()
106+
if (os === "linux") {
107+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-paste")) {
108+
const text = await $`wl-paste --primary --no-newline`.nothrow().text()
109+
if (text) return text
110+
}
111+
if (Bun.which("xclip")) {
112+
const text = await $`xclip -selection primary -o`.nothrow().text()
113+
if (text) return text
114+
}
115+
if (Bun.which("xsel")) {
116+
const text = await $`xsel --primary --output`.nothrow().text()
117+
if (text) return text
118+
}
119+
}
120+
}
121+
104122
const getCopyMethod = lazy(() => {
105123
const os = platform()
106124

0 commit comments

Comments
 (0)