Skip to content

Commit 1424eb8

Browse files
committed
fix(tui): support middle-click paste from X11 primary selection
1 parent 700d0fe commit 1424eb8

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, type JSX, onMount, createSignal, onCleanup, on, Show, Switch, Match } from "solid-js"
313
import "opentui-spinner/solid"
414
import path from "path"
@@ -1005,7 +1015,15 @@ export function Prompt(props: PromptProps) {
10051015
input.cursorColor = theme.text
10061016
}, 0)
10071017
}}
1008-
onMouseDown={(r: MouseEvent) => r.target?.focus()}
1018+
onMouseDown={async (r: MouseEvent) => {
1019+
r.target?.focus()
1020+
if (r.button !== MouseButton.MIDDLE) return
1021+
if (props.disabled) return
1022+
r.preventDefault()
1023+
const text = await Clipboard.readPrimary()
1024+
if (!text || !input || input.isDestroyed) return
1025+
input.insertText(text)
1026+
}}
10091027
focusedBackgroundColor={theme.backgroundElement}
10101028
cursorColor={theme.text}
10111029
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
@@ -91,6 +91,24 @@ export namespace Clipboard {
9191
}
9292
}
9393

94+
export async function readPrimary(): Promise<string | undefined> {
95+
const os = platform()
96+
if (os === "linux") {
97+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-paste")) {
98+
const text = await $`wl-paste --primary --no-newline`.nothrow().text()
99+
if (text) return text
100+
}
101+
if (Bun.which("xclip")) {
102+
const text = await $`xclip -selection primary -o`.nothrow().text()
103+
if (text) return text
104+
}
105+
if (Bun.which("xsel")) {
106+
const text = await $`xsel --primary --output`.nothrow().text()
107+
if (text) return text
108+
}
109+
}
110+
}
111+
94112
const getCopyMethod = lazy(() => {
95113
const os = platform()
96114

0 commit comments

Comments
 (0)