Copying text out of a tmux pane on the WSL host corrupts every non-ASCII character. An em dash arrives on the Windows clipboard as —, an ellipsis as ….
tmuxPlugins.yank autodetects WSL and pipes the selection to clip.exe, which decodes its stdin using the console OEM codepage (CP850 here) rather than UTF-8. The three bytes E2 80 94 are read as three separate single-byte characters.
Nothing on the Linux side is at fault - locale is en_GB.UTF-8, tmux reports client_utf8=1, and the text renders correctly in the pane. Only the clipboard hand-off is broken.
Fix
Override tmux-yank's copy command to route through tmux's own buffer:
set -g @override_copy_command 'tmux load-buffer -w -'
With set-clipboard on (already set) and TERM=xterm-256color matching tmux's built-in xterm*:clipboard feature, load-buffer -w emits OSC 52. The terminal receives UTF-8 directly and no Windows binary is involved. Verified against the running Windows Terminal client before committing.
Overriding rather than dropping the plugin keeps its other bindings - ! (copy without newlines), M-y (copy and paste), and the mouse-drag binding.
Why guarded, and why on the plugin
home/shell.nix is shared by all six hosts. iTerm2 rejects OSC 52 unless "Applications in terminal may access clipboard" is enabled, so an unconditional override would break copy on the Darwin machines. The if-shell test on /proc/version fails cleanly where /proc does not exist, leaving pbcopy/xsel in place.
It goes in the plugin's extraConfig rather than the shared block because yank.tmux resolves the copy command and bakes it into its key bindings when it loads. Home-manager emits plugin extraConfig before the corresponding run-shell, which is the ordering this needs. Confirmed in the generated tmux.conf - the option is set at line 50, the plugin loads at line 52.
Validation
nix fmt clean, nix flake check passes.
nixosConfigurations.emmathorpe-edaas evaluates.
Applied to the live tmux server and confirmed clip.exe is gone from every copy binding, replaced by tmux load-buffer -w -.
## Problem
Copying text out of a tmux pane on the WSL host corrupts every non-ASCII character. An em dash arrives on the Windows clipboard as `—`, an ellipsis as `…`.
`tmuxPlugins.yank` autodetects WSL and pipes the selection to `clip.exe`, which decodes its stdin using the console OEM codepage (CP850 here) rather than UTF-8. The three bytes `E2 80 94` are read as three separate single-byte characters.
Nothing on the Linux side is at fault - locale is `en_GB.UTF-8`, tmux reports `client_utf8=1`, and the text renders correctly in the pane. Only the clipboard hand-off is broken.
## Fix
Override tmux-yank's copy command to route through tmux's own buffer:
```
set -g @override_copy_command 'tmux load-buffer -w -'
```
With `set-clipboard on` (already set) and `TERM=xterm-256color` matching tmux's built-in `xterm*:clipboard` feature, `load-buffer -w` emits OSC 52. The terminal receives UTF-8 directly and no Windows binary is involved. Verified against the running Windows Terminal client before committing.
Overriding rather than dropping the plugin keeps its other bindings - `!` (copy without newlines), `M-y` (copy and paste), and the mouse-drag binding.
## Why guarded, and why on the plugin
`home/shell.nix` is shared by all six hosts. iTerm2 rejects OSC 52 unless "Applications in terminal may access clipboard" is enabled, so an unconditional override would break copy on the Darwin machines. The `if-shell` test on `/proc/version` fails cleanly where `/proc` does not exist, leaving `pbcopy`/`xsel` in place.
It goes in the plugin's `extraConfig` rather than the shared block because `yank.tmux` resolves the copy command and bakes it into its key bindings when it loads. Home-manager emits plugin `extraConfig` before the corresponding `run-shell`, which is the ordering this needs. Confirmed in the generated `tmux.conf` - the option is set at line 50, the plugin loads at line 52.
## Validation
- `nix fmt` clean, `nix flake check` passes.
- `nixosConfigurations.emmathorpe-edaas` evaluates.
- Applied to the live tmux server and confirmed `clip.exe` is gone from every copy binding, replaced by `tmux load-buffer -w -`.
tmux-yank autodetects WSL and pipes the selection to clip.exe, which
decodes its stdin as the console OEM codepage rather than UTF-8. Copying
an em dash out of a pane put "ΓÇö" on the Windows clipboard; the same
applies to every non-ASCII character.
Override the copy command to route through tmux's own buffer. With
set-clipboard on, that emits OSC 52 and the terminal receives UTF-8
directly, with no Windows-side helper in the path. Windows Terminal
honours OSC 52; verified against the running client.
Guarded on /proc/version so only WSL is affected. iTerm2 does not accept
OSC 52 by default, so the Darwin hosts keep pbcopy.
Set in the plugin's extraConfig rather than the shared block because
yank.tmux bakes the copy command into its key bindings at load time, and
home-manager emits plugin extraConfig before the run-shell.
lyrathorpe
scheduled this pull request to auto merge when all checks succeed 2026-08-24 13:29:57 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
Copying text out of a tmux pane on the WSL host corrupts every non-ASCII character. An em dash arrives on the Windows clipboard as
—, an ellipsis as….tmuxPlugins.yankautodetects WSL and pipes the selection toclip.exe, which decodes its stdin using the console OEM codepage (CP850 here) rather than UTF-8. The three bytesE2 80 94are read as three separate single-byte characters.Nothing on the Linux side is at fault - locale is
en_GB.UTF-8, tmux reportsclient_utf8=1, and the text renders correctly in the pane. Only the clipboard hand-off is broken.Fix
Override tmux-yank's copy command to route through tmux's own buffer:
With
set-clipboard on(already set) andTERM=xterm-256colormatching tmux's built-inxterm*:clipboardfeature,load-buffer -wemits OSC 52. The terminal receives UTF-8 directly and no Windows binary is involved. Verified against the running Windows Terminal client before committing.Overriding rather than dropping the plugin keeps its other bindings -
!(copy without newlines),M-y(copy and paste), and the mouse-drag binding.Why guarded, and why on the plugin
home/shell.nixis shared by all six hosts. iTerm2 rejects OSC 52 unless "Applications in terminal may access clipboard" is enabled, so an unconditional override would break copy on the Darwin machines. Theif-shelltest on/proc/versionfails cleanly where/procdoes not exist, leavingpbcopy/xselin place.It goes in the plugin's
extraConfigrather than the shared block becauseyank.tmuxresolves the copy command and bakes it into its key bindings when it loads. Home-manager emits pluginextraConfigbefore the correspondingrun-shell, which is the ordering this needs. Confirmed in the generatedtmux.conf- the option is set at line 50, the plugin loads at line 52.Validation
nix fmtclean,nix flake checkpasses.nixosConfigurations.emmathorpe-edaasevaluates.clip.exeis gone from every copy binding, replaced bytmux load-buffer -w -.