tl;dr

if-shell -b 'test -n "$WSLENV"' 'bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel clip.exe'
if-shell -b 'test -n "$WSLENV"' 'bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel clip.exe'

I have been using the Windows Subsystem for Linux (WSL) for approximately 2 years and it has tremendously affected my daily workflow in the most positive of ways. Having access to a Unix shell and the Gnu core utilities opened up ways to process data and complete my engineering work that was not possible before.

With that said, since it is not the common environment that many of the tools were developed in, certain tasks need some tweaking in order to get working correctly. One of those things is copying text to the clipboard from within tmux.

tmux has a built in ‘copy mode’. However, that support expects that an X server is running in the background, which is not the case for most of the distributions available through the WSL. Fortunately, newer versions of tmux have the ability to specify a command to pipe the data through.

The command in tmux is copy-pipe (and variants) and has the following syntax, check the man page for exact commands in your version.

copy-pipe <command> [<prefix>]
copy-pipe-no-clear <command> [<prefix>]
copy-pipe-and-cancel <command> [<prefix>]

If we were in a Linux distribution, we’d probably have xclip or xsel available for us. This is not the case in Windows. What we do have is clip.exe. This a Windows executable, but it does what we need: Take data piped into it and copy it to the clipboard.

You can do this in cmd.exe like

echo hello | clip.exe

You can run Windows executables in the WSL. So we’ll want to rebind the Enter key press when in copy mode (I use the vi copy mode bindings, if you are strange and want to use emacs mode, this would just be ‘copy-mode’ instead of ‘copy-mode-vi’). This looks like:

bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel clip.exe

That is a lot and it works, but there’s more to be done.

My tmux configuration is shared between many computers that are running various OS’s. At the time of writing, we have two work computers running Windows, one Manjaro, and one Arch Linux. I don’t want to mess us the default settings for my Linux systems.

Again, newer versions of tmux have a way to handle that. There is the if-shell command that allows you to execute commands based on the exit code of a shell command. So I wanted to test whether I was in a WSL environment before running the new bind-key command.

There are different ways to do this, but I did a printenv to see if there were any environment variables that were related to the WSL. It turns out there was. There was an environment variable called WSLENV, and it doesn’t matter what it is or what it does, just that it was there.

So we then use a test command (the command used to branch should be POSIX, so no Bash-isms) to check for this variable. The -n checks for a non-zero length string. Notice that you quote the entire commands.

This ends up looking like

if-shell -b 'test -n "$WSLENV"' 'bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel clip.exe'

On Windows, I have been using the Windows Terminal. I have liked it, and they are making great progress towards a 1.0 release.

One of the features they just recently implemented was mouse support. So now, I can turn on the mouse functionality in tmux with

set -g mouse on

and I can copy to clipboard using the mouse drag by just changing the ‘key’ from my previous bind-key command to MouseDragEnd1Pane.

So in all, it looked like:

if-shell -b 'test -n "$WSLENV"' 'bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel clip.exe'
if-shell -b 'test -n "$WSLENV"' 'bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel clip.exe'