System Clipboard With tmux

By
  • tmux
  • osx
  • cygwin
  • linux
  • emacs

Using tmux is huge win while working in a terminal, help make it better by adding support for your system clipboard.

The Problem

Although tmux does provide a built-in clipboard, the contents of this clipboard are not synchronized with the system clipboard. Lucky for us, this problem can be solved (and in a way that will allow us to share our tmux config across multiple platforms).

The Solution

Thanks to the way tmux is designed we are able to script it via the shell. If we bind shell commands to the default copy/paste keychords in ~/.tmux.conf we can take full control of what happens when we copy and paste.

Here is an example of what what you would put in your ~/.tmux.conf :

# copy:
bind-key -n -t emacs-copy M-w copy-pipe "my_copy_command"
# paste:
bind ] run "my_paste_command | tmux load-buffer - ; tmux paste-buffer"
  • copy-pipe : runs the command you specify and passes the tmux clipboard buffer via stdin.
  • run : executes a shell command.
  • load-buffer : load text into the tmux buffer (will load via stdin when followed by a single ‘-’).
  • paste-buffer : paste the tmux buffer into the active tmux pane.

By mixing the above example with the if_shell command we can specify different behavior for individual platforms:

if_shell '<shell_command>' '<tmux_success_command>' '<tmux_failure_command>'

Example:

# Mac OS X
if-shell "uname | grep -qi Darwin" "run 'echo Running on OS X'"
# Linux
if-shell "uname | grep -qi Linux" "run 'echo Running on Linux'"
# Cygwin
if-shell "uname | grep -qi Cygwin" "run 'echo Running on Windows'"

The Platforms

Mac OS X

In order to use the clipboard on OS X with tmux you will need to install reattach-to-user-namespace. (e.g. of installing with homebrew.)

~/ ❯ brew install reattach-to-user-namespace

The reattach-to-user-namespace command will be used as a wrapper around the pbcopy and pbpaste commands.

# copy
if-shell 'uname | grep -qi Darwin && which reattach-to-user-namespace > /dev/null' 'bind-key -n -t emacs-copy M-w copy-pipe "reattach-to-user-namespace pbcopy"'
# paste
if-shell 'uname | grep -qi Darwin && which reattach-to-user-namespace > /dev/null' 'bind ] run "reattach-to-user-namespace pbpaste | tmux load-buffer - ; tmux paste-buffer"'

Linux

On Linux we can use the xclip command to handle clipboard synchronization.

# copy
if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind-key -n -t emacs-copy M-w copy-pipe "xclip -i -sel p -f | xclip -i -sel c "'
# paste:
if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind-key -n C-y run "xclip -o | tmux load-buffer - ; tmux paste-buffer"'

Cygwin

The clipboard on cygwin is available via /dev/clipboard.

# copy
if-shell 'uname | grep -qi Cygwin' 'bind-key -n -t emacs-copy M-w copy-pipe "cat > /dev/clipboard"'
# paste:
if-shell 'uname | grep -qi Cygwin' 'bind ] run "cat /dev/clipboard | tmux load-buffer - ; tmux paste-buffer"'

Putting It All Together

Place the following in ~/.tmux.clipboard.conf

# Mac OX X
if-shell 'uname | grep -qi Darwin && which reattach-to-user-namespace > /dev/null' 'bind-key -n -t emacs-copy M-w copy-pipe "reattach-to-user-namespace pbcopy"'
if-shell 'uname | grep -qi Darwin && which reattach-to-user-namespace > /dev/null' 'bind ] run "reattach-to-user-namespace pbpaste | tmux load-buffer - ; tmux paste-buffer"'

# Linux
if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind-key -n -t emacs-copy M-w copy-pipe "xclip -i -sel p -f | xclip -i -sel c "'
if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind-key -n C-y run "xclip -o | tmux load-buffer - ; tmux paste-buffer"'

# Cygwin
if-shell 'uname | grep -qi Cygwin' 'bind-key -n -t emacs-copy M-w copy-pipe "cat > /dev/clipboard"'
if-shell 'uname | grep -qi Cygwin' 'bind ] run "cat /dev/clipboard | tmux load-buffer - ; tmux paste-buffer"'

Next add a new line to ~/.tmux.conf

# System clipboard support
source-file ~/.tmux.clipboard.conf

Running tmux Outside of a Window Manager

Chances are that if you are running tmux without a window manager you won’t want any of the custom clipboard configuration. Because we split the clipboard config into a separate file we can use the if-shell tmux command to limit when the .tmux.clipboard.conf file is sourced.

# Clipboard support when a display is detected
if-shell '[[ -n $DISPLAY ]]' 'source-file ~/.tmux.clipboard.conf'

Bonus Round: Emacs in tmux on OS X

Running Emacs inside of tmux on OS X is pretty straightforward; add the following code to your .emacs config file to allow copy/paste with the system clipboard.

(when (eq system-type 'darwin)
  ;; terminal clipboard while inside tmux
  (unless (display-graphic-p)
    (when (and (> (length (getenv "TMUX")) 0) (executable-find "reattach-to-user-namespace"))

    (defun paste-from-osx ()
      (shell-command-to-string "reattach-to-user-namespace pbpaste") )

    (defun cut-to-osx (text &optional push)
      (let ((process-connection-type nil))
        (let ((proc (start-process "pbcopy" "*Messages*" "reattach-to-user-namespace" "pbcopy") ))
          (process-send-string proc text)
          (process-send-eof proc))))

      (setq interprogram-cut-function 'cut-to-osx)
      (setq interprogram-paste-function 'paste-from-osx)
    )
  )
)
Thank you for reading.