On tmux OSC-52 support

Several days ago, OSC-52 support was merged into NeoVim, and this sparkled my interest. It was just natural, given that both NeoVim and OSC-52 are essential part of my daily workflow.

For those unfamiliar, OSC stands for Operating System Command, and it's a set of escape sequences originally defined by Xterm, but now adopted by various modern terminal emulators[1]. OSC-52, in particular, is an escape sequence that allows copying to and pasting from the system clipboard.

I have a few development environments running in virtual machines or systemd-nspawn containers, and I typically SSH into them and run NeoVim from within. Needless to say that a NeoVim instance running inside container has no access to the system clipboard[2], and this is where OSC-52 comes to the rescue!

G cluster_Host Host cluster_VM VM cluster_Container1 Container cluster_Container2 Container neovim1 NeoVim neovim2 NeoVim neovim3 NeoVim

If your terminal emulator supports it, NeoVim's built-in OSC-52 clipboard provider just works! Here's the thing though: if you're a happy tmux user, things might not go the way you expect them to go. I quickly noticed a peculiar behavior that I initially mistook for a bug: OSC-52 pasting didn't paste the content of the system clipboard, but rather the content of tmux top buffer.

Despite being called a multiplexer, tmux acts as a terminal emulator, which means it implements many OSC sequences itself, including OSC-52. When it comes to copying, tmux saves captured text to its buffer and passes the escape sequence up to the parent terminal to set the system clipboard. Pasting, on the other hand, always retrieves a content from a tmux buffer, forms a response and passes it up to the parent terminal for pasting. The content of the buffer may be a text you previously copied (and hence implicitly saved) or a text you explicitly saved to a buffer.

What does this mean practically? It means that a text you copy in NeoVim can be pasted in a browser. However, a text that you copied in a browser cannot be pasted to NeoVim. Lame, huh?

Unfortunately, this is intentional behavior because tmux supports multiple clients that may be attached from multiple hosts[3]. It's a no-brainer with copying: we just send a text we want to copy to all clients and let their terminal emulators to set the system clipboard. But what should we do with pasting? What attached client should be used as a clipboard source?

G cluster_Host1 Host A cluster_Host2 Host B clipboard1 clipboard tmux_server tmux server tmux_client1 tmux client tmux_server->tmux_client1 tmux_client2 tmux client tmux_server->tmux_client2 clipboard2 clipboard

Fortunately, tmux gives us a command, refresh-client -l, that can be executed by any client to sync the content of the system clipboard to a tmux buffer, that can subsequently be used to paste the content via OSC-52.

I decided to share this information, as I spent at least an hour running tmux under gdb, chasing a ghost that doesn't exist. I don't want anyone to repeat my experience.

  1. OSC-52 is at least supported by alacritty, contour, foot, hterm, iterm2, kitty, rxvt, st, tmux, wezterm, windows terminal and zelij. ↩︎

  2. In my case, VMs and containers have no access to the wayland socket, and I don't want them to. ↩︎

  3. If I understand maintainer's comment correctly. ↩︎