Compare commits

...

2 Commits

Author SHA1 Message Date
David Ibia bbd740fd0d fix(tmux): accept OSC 52 from panes so nested tmux copy reaches the clipboard
The local tmux left set-clipboard at the default "external", which drops
OSC 52 sent by applications in a pane. In a nested setup the remote tmux
sends its copies up as OSC 52, so they never reached the Mac clipboard.
2026-10-05 19:47:14 +01:00
David Ibia e7264987f4 feat(bin): add pbcopy/pbpaste shims for headless clipboard over OSC 52
Headless servers have no DISPLAY or WAYLAND_DISPLAY, so xclip and xsel
cannot reach a clipboard even when installed. These shims use OSC 52 to
hand text to the terminal emulator on the other end of the SSH connection,
which puts it on the local machine's clipboard.

Inside tmux, pbcopy uses `tmux load-buffer -w -` so the text lands in the
tmux paste buffer and is forwarded outward (requires `set-clipboard on`).
Outside tmux it writes the escape sequence to /dev/tty directly. Both fall
back to xclip/wl-copy when a real display is present.

pbpaste reads the tmux buffer only; terminals refuse OSC 52 reads, since
that would let any remote program siphon the user's clipboard.
2026-10-05 19:47:14 +01:00
3 changed files with 57 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# pbcopy -- macOS-style clipboard copy for this headless box.
#
# There is no X/Wayland display here, so xclip/xsel cannot reach a clipboard.
# Instead we use OSC 52: the text is handed to the terminal emulator on the
# other end of the SSH connection, which puts it on YOUR machine's clipboard.
#
# ls -la | pbcopy
# pbcopy < notes.md
set -euo pipefail
# A real local display (rare here, but free to support).
if [[ -n "${DISPLAY:-}" ]] && command -v xclip >/dev/null 2>&1; then
exec xclip -selection clipboard
fi
if [[ -n "${WAYLAND_DISPLAY:-}" ]] && command -v wl-copy >/dev/null 2>&1; then
exec wl-copy
fi
# Inside tmux: load-buffer -w fills the tmux paste buffer and, because
# set-clipboard is on, forwards OSC 52 out to the terminal emulator.
if [[ -n "${TMUX:-}" ]] && command -v tmux >/dev/null 2>&1; then
exec tmux load-buffer -w -
fi
# Bare SSH: emit OSC 52 straight at the controlling terminal.
{ printf '\033]52;c;'; base64 | tr -d '\n'; printf '\a'; } > /dev/tty
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# pbpaste -- companion to pbcopy.
#
# Terminals almost universally refuse OSC 52 *reads* (it would let any remote
# program siphon your clipboard), so this cannot see your local clipboard.
# What it can do is echo back the tmux paste buffer, i.e. whatever pbcopy or
# a tmux copy-mode yank last put there.
set -euo pipefail
if [[ -n "${DISPLAY:-}" ]] && command -v xclip >/dev/null 2>&1; then
exec xclip -selection clipboard -o
fi
if [[ -n "${WAYLAND_DISPLAY:-}" ]] && command -v wl-paste >/dev/null 2>&1; then
exec wl-paste
fi
if [[ -n "${TMUX:-}" ]] && command -v tmux >/dev/null 2>&1; then
exec tmux save-buffer -
fi
echo "pbpaste: no readable clipboard (not in tmux, no display)" >&2
exit 1
+7
View File
@@ -128,6 +128,13 @@ bind-key -T copy-mode-vi 'C-l' select-pane -R
bind-key -T copy-mode-vi 'C-\' select-pane -l bind-key -T copy-mode-vi 'C-\' select-pane -l
# Clipboard (OSC 52)
# Required for nested tmux (local tmux -> ssh/mosh -> remote tmux): the inner
# tmux sends its copies up as OSC 52, and tmux only accepts OSC 52 coming
# from a pane when set-clipboard is "on". The default "external" drops it.
set -g set-clipboard on
set -as terminal-features ',*:clipboard'
# #
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm' run '~/.tmux/plugins/tpm/tpm'