Copying and Pasting with tmux 2.4+

Posted on by in Development

At Carbon Five it’s pretty common to do our editing in vim embedded in a tmux session. Tmux, if you haven’t used it, is a “terminal multiplexer” that lets you create multiple tabs and panes in a terminal, persist terminal sessions, and (with plugins) send commands from vim to another pane. It’s also great for remote pair programming, since you can share a session over the internet.

It’s pretty nice, but getting copy and paste working within tmux on macOS is surprisingly tricky, due to some peculiarities with MacOS’s security setup. Tmux is run as a daemon process, and daemons haven’t had access to user-level services like the pasteboard since OS X 10.5. So while you can copy text into tmux’s register, tmux can’t put that text on the pasteboard where anything else could get to it. This can get pretty frustrating when you want to copy an error code into Google!

Happily, there’s a library called reattach-to-user-namespace that uses some private operating system functions to get tmux access to the pasteboard — but it takes a little configuring, and the correct configuration recently changed.

First, you can install it with

brew install reattach-to-user-namespace

Then, you’ll need to add a few lines to your .tmux.conf file.

First, add this line, replacing bash with your shell of choice.

set-option -g default-command "reattach-to-user-namespace -l bash"

That’ll get reattach-to-user-namespace to do its magic whenever tmux starts up, and allow calls to the clipboard to go through. But by itself, that still won’t get copy and paste working.

To do that, you have to tell tmux to actually send copied text to pbcopy. Tmux 1.8 (from 2015) added a copy-pipe option that lets you do something with yanked text after tmux copied it to its internal register. Then in April tmux 2.4 introduced breaking changes, changing some names and syntax and making copy-pipe no longer remove you from copy mode by default.

So depending on how recent your version of tmux is, the magic configuration is one of these:

# New 2.4 version:
bind-key -T copy-mode-vi 'v' send -X begin-selection
bind-key -T copy-mode-vi 'y' send -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy"
# Old 1.8 version:
bind-key -t vi-copy 'v' begin-selection
bind-key -t vi-copy 'y' copy-pipe "reattach-to-user-namespace pbcopy"

Note on vi-mode

I’m assuming that you’re using tmux with vim, want vi-style bindings for your copying, and have added set-window-option -g mode-keys vi to your .tmux.conf

If you want to copy from tmux, but don’t want to use vim keys, your .tmux.conf should instead have something like:

bind-key -T copy-mode 'Enter' send -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy"

Sharing your dotfiles across operating systems

If you’re sharing your .tmux.conf across systems, and want to make sure you’re not trying to use reattach-to-user-namespace on Linux or another non-macOS environment, you can instead set up normal copy/paste in your .tmux.conf and put the macOS-specific configuration in a separate file.

### .tmux.conf
set-window-option -g mode-keys vi

# vi-style copying
bind-key -T copy-mode-vi 'v' send -X begin-selection
bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel

# Import macOS-only config
if-shell 'test "$(uname -s)" = Darwin' 'source-file ~/.tmux-osx.conf'
### .tmux-oxs.conf
# Unbind from non-macOS setup
unbind-key -T copy-mode-vi 'y'
# Copy now goes to macOS clipboard
bind-key -T copy-mode-vi 'y' send -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy"

.tmux-osx.conf will only get run on a mac, and overwrites the normal configuration.

That’s it! You should now (finally) be able to copy things over to Google!