微软官方已经停止了WSL1的支持,所以以下文章的WSL皆指代WSL2
这是开头
我平常在我常用的Fedora系统的笔记本上的nvim的快捷键设置为<C-c>
映射到"+y
,nvim访问剪切板的后端使用的是wl-clipboard
。这个命令是可以正常运行的。但是在WSL中"+y
不能正常工作。我也没时间研究如何修复,况且我也想直接复制到Windows的剪切板中,这个方式不一定能按照预期工作。
恰巧前几天正在做一个相关项目,并在Windows上实现了一个类似于wl-clipboard
和xclip
的程序:win-clip。它实现了通过命令行访问Windows的系统剪切板,可以查看仓库主页了解更多。
WSL支持“直接执行”Windows应用
WSL看起来支持“直接执行”Windows应用,例如
1 |
|
其中wget.exe
是busybox-w32
项目的busybox.exe
硬链接到的wget.exe
,且将其目录添加到Windows的PATH
环境变量下。
经过简单的测试,我们可以发现:WSL实际上并不是使用类似于Wine等的兼容层实现执行Windows程序的能力。更像是在检测到PE程序时,将程序交由Windows系统的程序装载器来进行处理并执行。下文我会说明为什么我会得出这个结果。
将我搓出来的win-clip
和WSL支持运行Windows可执行程序的特性结合,就得出了一个神奇的组合:我们可以在vim中调用win-clip.exe
来访问Windows的系统剪切板!
实际上,我只配置了复制到Windows系统剪切板的行为,因为在终端选中直接选中来复制会产生多余的字符,因而不得不实现vim进行复制的操作。对于粘贴行为,我用Windows Terminal的快捷键替代
在releases中下载win-clip
,将其目录添加进PATH中,在cmd或者powershell中执行win-clip.exe -h
验证是否能通过PATH
在全局执行win-clip
1 |
|
可以正常执行win-clip。
接下来,在WSL中再次尝试运行
1 |
|
可以看到,我们成功在WSL中执行添加到Windows的PATH
的Windows的可执行程序(默认配置下,Windows的PATH
会在WSL启动时添加到WSL的PATH
中)。
可以试试执行win-clip.exe paste
来从Windows的剪切板中粘贴最新的记录。如果此记录正是上次复制的内容,则应该能说明此程序是在Windows系统上被执行的,因为即使微软实现了一个类似Wine
的兼容层,最终获取的剪切板仍位于Linux上而不是从Windows中获取剪切板数据。况且遇到Windows可以执行的程序就让Windows进行装载执行显而易见这是兼容性更强的写法,Windows又不用规避版权。
以上操作是在WSL上复制文本到Windows剪切板的核心,接下来配置vim快捷键。
配置vim快捷键
1 |
|
由于在块选择模式下,按下:
会显示出选择块范围:'<,'>
,但是光标在最后,所以需要按下Home按键移动到开头来在靠头输入slient
静默执行,随后按下End按键重新跳转回最后,输入 w !win-clip.exe copy
按下回车来将文本输入到win-clip
的STDIN中。另外win-clip copy
子命令会在不指定参数时读取STDIN的数据并复制到Windows剪切板。
这个命令相信熟练使用vim的人都能理解。保存vimscript后打开新的文本,块选择文本并按下Ctrl+C
,发现文本已经成功复制到剪切板中。
非英文字符支持
在复制非英文文本时,例如中文,你可能发现Windows剪切版的内容变成了乱码,这主要是Windows平台和Linux平台字符编码不统一导致的。
由于Windows的默认编码格式为ANSI(大陆地区为GBK),而win-clip
的目标是通过管道来接入到项目中,为了通用性需要考虑UTF-8编码,因此了实现Windows平台的ANSI编码和UTF-8的编码之间的相互转换。
win-clip
通过-u
参数支持UTF-8编码格式的输入输出。
- 输入时读取并转换UTF-8编码格式的文本到ANSI再复制到剪切板
- 输出时从剪切板读取数据,将ANSI编码的文本转换为UTF-8
因此,更新脚本,添加-u
参数
1 |
|
再复制中文时就能不乱码了。
碎碎念
借助WSL能直接调用windows程序的能力,应该能做很多种神奇的融合两个系统的程序!
这篇文章有点水,但是发现这个需求能被最近正在写的项目完美解决是有一点快感在里边的(