Using tmux with the X clipboard

May 12, 2023

Sometimes I would like to paste shell command invocations from my browser into my terminal and use bracketed pasting, i.e., pasting without running the command directly.

Since I am running tmux (tmux 3.1c) inside of xterm, in an i3 and Xorg desktop environment, I also want to use the X clipboard. The X clipboard is used when copying text from the browser as well.

Pasting things into tmux

The X clipboard can be accessed through various commands, such as xsel and xclip. I decided to use xsel, since it appears to be shipped with Debian 11 by default. Other than the clipboard, X also maintains two more selections called primary and secondary.

The primary selection is often accidentally discovered when accidentally pressing the middle mouse button pastes text where it is not supposed to go in an X application.

Tmux, on top of that, maintains its own copy buffers, of which there can exist an unlimited amount that can be named arbitrarily. To see the current buffers, you can run the following in a terminal:

tmux list-buffers

If we want to paste arbitrary text, for example, the current date, into a tmux buffer called hello-world, we can use the following command:

# The hyphen at the end indicates that we read from stdin
date -I | tmux load-buffer -b hello-world -

Then, to verify the contents of this buffer, we can dump it like so:

tmux show-buffer -b hello-world

So, if we want to paste something from the X clipboard, which we can dump by running xsel --clipboard, we need to do three things:

  1. Output the current X clipboard contents
  2. Read them into a tmux buffer
  3. Dump the contents of that tmux buffer into the currently active tmux pane

I came up with the following key binding, which I have saved into my tmux.conf:

bind-key ']' run "xsel --clipboard | tmux load-buffer - " \; paste-buffer -p

Using paste-buffer with the -p flag ensures we use bracketed pasting. Conveniently, you can add multiple commands to the same key binding executed in series using an escaped semicolon.

Since my tmux prefix is C-b, I can press C-b and then ] to paste cleanly into most terminal applications that understand bracketed pasting.

Copying from tmux

To copy something from tmux, we make use of tmux’s vi mode, which I have configured in tmux like so:

set-window-option -g mode-keys vi

Once entering tmux, the default configuration is to copy the selection to a tmux buffer using the Enter key. Instead, I would like to copy it to the X clipboard. This can be achieved with the following key binding:

bind-key -T copy-mode-vi 'Enter' send-keys -X copy-pipe-and-cancel 'xsel --clipboard --input'

Then, when you enter vi copy mode, you can copy your selection to the X clipboard.

Scenarios made possible by this

I often copy code snippets, boilerplate, and so on from documentation and paste it into Neovim. This is possible out of the box since Neovim integrates with the x clipboard. It breaks down, though, when editing files as root. For example, while using sudo nano /etc/$SOME_CONFIG_FILE, neither GNU nano support accessing the X clipboard, nor is it being shared between a sudo session and the currently active desktop. Using tmux to gently wrap around X is tremendously helpful here.

Copying and pasting text is challenging due to troubles with RSI that I currently face. Using the configuration described above, I can now easily copy things from my terminal. For example, I can paste the output of dmesg into my browser without having to resort to overly complex keyboard chords and precise mouse cursor placements in xterm.

This is yet another triumph for open and configurable software. Being able to customize your desktop environment is essential for accessible software development.

I would be thrilled to hear from you! Please share your thoughts and ideas with me via email.

Back to Index