Blog - OSC 52 and (nested) GNU Screen

Added on Saturday, 2022-10-29 22:21 CEST in category Programming
OSC 52 is an ANSI escape sequence that can be used to instruct your terminal to put text into the OS clipboard. It doesn't matter where the text comes from (including over an SSH connection), as long as it's received by the terminal.

I'd been stuck using the mouse to copy/paste text from my terminal for years, and now OSC 52 would let me do it using my keyboard or even programmatically, great! (See also this Reddit post.)

Support throughout the stack

For OSC 52 to work, the entire stack needs to support it, though: the terminal, the shell, my terminal multiplexer GNU Screen, and the programs running in it.

GNOME Terminal doesn't support OSC 52, so I switched over to Alacritty (see my alacritty.yml).

GNU Screen sort of supports OSC 52 if you wrap it in the DCS sequence "ESC P" (see the Screen manual). This is exactly what scripts like osc52.sh and vim-oscyank do. However, I use GNU Screen twice in a nested way (one local and one remote), and then things become a bit more complicated.

OSC 52 and (nested) GNU Screen

The control sequence "ESC P" (DCS) tells GNU Screen to "output a string directly to the host terminal without interpretation". These are example commands without GNU Screen, with GNU Screen, and with a nested GNU Screen (with "\033" being "ESC" and "\a" being "BEL"):
printf "\033]52;c;$(printf "%s" "test" | base64)\a"

printf "\033P\033]52;c;$(printf "%s" "test" | base64)\a\033\\\\"

printf "\033P\033P\033]52;c;$(printf "%s" "test" | base64)\a\033\033\\\\\033\\\\\\\\"

The double escaping on the third line is pretty weird, but it works!

GNU Screen limits the length of OSC 52 sequences, so larger texts need to be split up with "\033\\\\\033P" in between chunks. This needs to be escaped again for a nested GNU Screen, i.e., with "\033\033\\\\\033\\\\\\\\\033P\033P". Unfortunately, the twice-escaped sequence doesn't work in a non-nested GNU Screen (or outside of GNU Screen), so I had to resort to setting a per-device shell variable "$SHELL_LEVEL": on my servers it's set to "2", and on my clients to "1".

P.S.: I have sent a patch for GNU Screen to support OSC 52, but it hasn't made it in yet.

Changes to osc52.sh and vim-oscyank

I've added support for a nested GNU Screen in osc52.sh and oscyank.vim. You'll need to set the right "$SHELL_LEVEL" in your shell and "g:oscyank_screen_level" in your vimrc.

With this, I can now copy the current selection in Vim with OSC 52 by typing "\y", and the current filename using "\j". And in the shell, I can pipe any text (under ~100k in size) to osc52.sh, and it'll end up in my OS clipboard. Amazing!