Clipboard integration using OSC 52

I use Kakoune in WSL and usually inside tmux, which made setting up hooks for copying to system clipboard and/or tmux buffers, and keeping track of both a bit cumbersome.

I recently learned about and set up copying to system clipboard using OSC 52 escape sequence, after seeing that tmux has a set-clipboard option. They also recently created a very nice wiki page explaining its usage and OSC 52.

I found a few advantages to using the escape sequence:

  1. tmux integration is transparent with the set-clipboard on option: If tmux is running, the escape sequence sent by an application will set tmux buffer which will get forwarded to the terminal by tmux, otherwise it will have directly sent it to the terminal
  2. The clipboard will get forwarded through SSH sessions, so that you can copy from terminal applications from the remote application

Kakoune setup

Following the examples in Kakoune wiki, we can hook up the escape sequence to a yank/delete/change operation:

hook global NormalKey y|d|c %{
    nop %sh{
        encoded=$(printf %s "$kak_main_reg_dquote" | base64 | tr -d '\n')
        printf "\e]52;;%s\e\\" "$encoded" >/dev/tty

tmux setup

AFAICT tmux 2.6+ supports the set-clipboard on option, while the default is set-clipboard external which will let applications set the tmux buffer but tmux will not forward them to the terminal. set-clipboard on will also enable forwarding to the terminal to set the system clipboard.

Terminal support

Most terminals seem to have support for setting the system clipboard when the sequence is received. The aforementioned tmux wiki page details support for most terminals, some of which requires setting options; a notable holdout is VTE terminals like Gnome terminal.

I use WSLtty which is not documented there, but it supports it by setting AllowSetSelection=true in its config file.


alacritty - not documented on the tmux wiki page - works, too, with this trick.

I’m quite happy with this setup!

1 Like

For whatever reason the hook, or this equivalent script doesn’t work on Ubuntu 16 (it just prints the sequence to stdout), while it works fine on Ubuntu 20.

stdin=$(cat /dev/stdin; echo .)
encoded=$(printf %s "$stdin" | base64 | tr -d '\n')
printf "\e]52;c;%s\a" "$encoded" >/dev/tty

Maybe I need to copy a terminfo entry or something?
The weird thing is if I run that printf command in a shell, it works fine.

ok seems to be a problem with the version of dash on Ubuntu 16; it works when I use bash instead

I think I still didn’t manage to configure tmux to interpret OSC 52 but it turns out I can skip that for most scenarios because I can just write to the underlying TTY that tmux runs on top of. Here’s what I use, it works great over SSH

printf "\e]52;c;%s\a" "$encoded" > "$(tmux display-message -p '#{client_tty}')"

That’s a good trick to know, there might be scenarios where you want to bypass tmux anyway. I have been using this approach with set-clipboard on for some time now, most recently with Windows Terminal.

It’s possible to join selections using the following pattern:

nop %sh{
  printf 'echo -to-file "%s" -- "%%val{selections}"' "$kak_response_fifo" > "$kak_command_fifo"
  tr '\0' '\n' < "$kak_response_fifo"
1 Like

I recently ran into some trouble using this approach with clients connected to headless servers, where /dev/tty is no longer accessible from the server. mawww pointed to /proc/$kak_client_pid/fd/0 on Discord as a way to find the tty of the client (at least on Linux) so the copy command can be updated to the following to be more robust:

printf "\e]52;;%s\e\\" "$encoded" >"/proc/$kak_client_pid/fd/0"
1 Like