Nvim isn't a single process attached to the terminal: the process that actually spawns jobs (clipboard-copy included) is a separate `nvim --embed` core process with no tty of its own (ps shows `?`); the real pty belongs to a distinct parent UI process. Checking only the immediate parent's tty (as the previous fix did) found the embed process's `?` and fell through to the broken /dev/tty path every time in real interactive use, even though it looked fine in headless testing. Walk up the process tree past any tty-less ancestors instead. Verified against the real docker-compose path in actual (non-headless) TUI mode, with real keystrokes fed through a pty: the OSC 52 sequence now reaches the terminal with no error, where it previously still failed.
46 lines
2.1 KiB
Bash
Executable File
46 lines
2.1 KiB
Bash
Executable File
#!/bin/sh
|
|
# Copy stdin to the system clipboard, regardless of platform or how deep in
|
|
# ssh/tmux this shell is: prefer a local clipboard tool for the current
|
|
# display server, and fall back to a single plain OSC 52 write when no local
|
|
# tool is available (e.g. a headless remote host). Any tmux hops in between
|
|
# here and the real terminal relay that onward themselves, recursively, via
|
|
# the pane-set-clipboard hook in tmux.conf -- this doesn't need to know or
|
|
# guess how many hops there are.
|
|
if command -v pbcopy >/dev/null 2>&1; then
|
|
exec pbcopy
|
|
elif [ -n "$WAYLAND_DISPLAY" ] && command -v wl-copy >/dev/null 2>&1; then
|
|
# wl-copy/xclip both hold the selection by staying alive as a background
|
|
# process (X11/Wayland selections have no central store -- the owner has
|
|
# to serve paste requests live). setsid -f detaches that process from
|
|
# our session so tmux's copy-pipe job cleanup can't kill it right after.
|
|
setsid -f wl-copy
|
|
elif [ -n "$DISPLAY" ] && command -v xclip >/dev/null 2>&1; then
|
|
setsid -f xclip -selection clipboard
|
|
else
|
|
data=$(base64 | tr -d '\n')
|
|
# /dev/tty needs this process's own session to have a controlling
|
|
# terminal, but a job spawned by nvim's clipboard provider doesn't get
|
|
# one (nvim's job-spawning doesn't establish a ctty for children). Nvim
|
|
# itself also isn't a single process: the one actually spawning jobs is
|
|
# a `nvim --embed` core process with no tty of its own (shown as `?` in
|
|
# ps) -- the real terminal belongs to a separate parent UI process. Walk
|
|
# up the process tree past any tty-less ancestors to find it.
|
|
real_tty=""
|
|
pid="$PPID"
|
|
i=0
|
|
while [ "$i" -lt 10 ] && [ -n "$pid" ] && [ "$pid" != "0" ]; do
|
|
t=$(ps -o tty= -p "$pid" 2>/dev/null | tr -d ' ')
|
|
if [ -n "$t" ] && [ "$t" != "?" ]; then
|
|
real_tty="/dev/$t"
|
|
break
|
|
fi
|
|
pid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ')
|
|
i=$((i + 1))
|
|
done
|
|
if [ -n "$real_tty" ] && [ -w "$real_tty" ]; then
|
|
printf '\033]52;c;%s\a' "$data" > "$real_tty"
|
|
else
|
|
printf '\033]52;c;%s\a' "$data" > /dev/tty
|
|
fi
|
|
fi
|