Use System Clipboard for Vi Copy Mode in Tmux in macOS and Linux

Since I sync my dotfiles through GitHub, I wanted to implement something that will work on both macOS and Linux. Enter if-shell, which is documented in tmux’s man page:

 if-shell [-bF] [-t target-pane] shell-command command [command]
               (alias: if)
         Execute the first command if shell-command returns success or the second command otherwise.  Before being executed, shell-command is expanded using the rules specified
         in the FORMATS section, including those relevant to target-pane.  With -b, shell-command is run in the background.

         If -F is given, shell-command is not executed but considered success if neither empty nor zero (after formats are expanded).

In short, you can run a command conditionally, based on whether your “if” condition returns true. Interestingly, you can also run an “else” command without saying “else.”

Since we want to determine whether we’re on macOS or Linux, we can use the uname command. It returns Darwin for macOS and Linux for Linux.

The system-dependent commands to access the system clipboard are pbcopy on macOS and xclip on Linux. In addition, on macOS only, we must use the reattach-to-user-namespace utility to access the system clipboard in tmux.

One final note: we must wrap the commands that follow our “if” condition in quotes or braces. If braces, we don’t have to worry about escaping things, and we can specify multiple commands on multiple lines.

Here’s what I’ve put in my .tmux.conf, so that I can copy the selection, when in vi mode, into the system clipboard:

if-shell "uname | grep -q Darwin" {
  bind-key -T copy-mode-vi 'y' send -X copy-pipe-and-cancel 'reattach-to-user-namespace pbcopy'
  bind-key -T copy-mode-vi Enter send -X copy-pipe-and-cancel 'reattach-to-user-namespace pbcopy'
} {
  bind-key -T copy-mode-vi 'y' send -X copy-pipe-and-cancel 'xclip -in -selection clipboard'
  bind-key -T copy-mode-vi Enter send -X copy-pipe-and-cancel 'xclip -in -selection clipboard'
}

If uname returns “Darwin,” we run the settings in the first set of braces. If not, we run the second set.

Note: This is on tmux 3.0a (Linux) and tmux 3.1b (macOS). I’m not sure if this will work on other versions of tmux. You can get your tmux version by running tmux -V.

5 Responses

  1. Jordan Mandel says:

    I’ve found that this works in iterm but not Kitty.

    • Rob Warner says:

      Interesting. Since writing this post, I switched to Kitty and its windowing instead of tmux on Linux. I’m still on iTerm + tmux on MacOS, but I plan to switch there, too, once I get around to it.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.