Linux我用 Linux

WSL 中的 VIM 与 Windwos 剪切板通信

2019-05-28  本文已影响6人  mbinary

title: WSL 中的 VIM 与 Windwos 剪切板通信
date: 2019-05-28 13:52
categories: linux
tags: [vim,操作系统]
keywords:
mathjax: false
description:
WSL(Windows Subsystem for Linux)真香,然而还是存在一些瑕疵。比如 WSL不是使用的系统剪切板,与系统剪切板通信,进行复制粘贴,是一个很棘手的问题。本文谈谈解决这个问题的一些方法。


WSL(Windows Subsystem for Linux)真香,然而还是存在一些瑕疵。比如 WSL不是使用的系统剪切板,与系统剪切板通信,进行复制粘贴,是一个很棘手的问题。本文谈谈解决这个问题的一些方法。

说明

环境如下

说明

前言

在网上看到最新的 Windows 版本支持用 ctrl+shift+c/v 进行复制粘贴, 或者有的可以在 shell 窗口>属性>选项中开启这个功能。
我这个不行。

而且 vim --version | grep clipboard 没有 加号(系统)寄存器, 再加之懒得重新编译 vim(开启 featured) . 所以我只有另寻解决办法.

在命令行下,已经有很好的解决方法: 可以右击进行复制(先选中)和粘贴
另外 也可以使用 ctrl+c 复制(有两个功能,分别是中断和复制)

vim 下就比较麻烦了。我尝试了很多种方法,从操作的舒适程度,以及实现效果来选择出最终最优的解决方法: 通过运行 windows 的 paste.exe, clip.exe程序进行复制粘贴

复制

从 VIM 中 复制文本到 Windoes 剪切板。

寄存器

通过 VIM 寄存器实现: 将 visual 模式下选中的文本复制到 vim 寄存器,然后将寄存器内容通过 shell 处理进入到剪切板。

首先选中(在 visual 模式下),用"ay将内容保存到 a寄存器,然后在命令行模式下 !echo <c-r>a \| /mnt/c/Windows/System32/clip.exe(执行 shell 命令。 a 寄存器的内容直接 作为参数文本传递(命令行模式下, <c-r>再接寄存器名字,可以将寄存器内容拷贝过来)

然而拷贝的文本很可能不能直接在shell 下作为参数,有特殊字符,比如",$等等。
所以要进行转义,用 vim 的 escape函数 (我试了shellescape, 效果不怎么好)

把上面的操作映射到按键下, 我映射的是 ;y, 就得到如下的 vim 键盘映射
在 visual 模式下选中,依次按下 ;y即可复制

map ;y "ay: let @a="'".escape(@a,"\\'\"")."'" <cr>:!echo <c-r>a \|"/mnt/c/Windows/System32/clip.exe"<cr>

然而在复制多行时,寄存器中会包含换行控制字符^J^@,^M,这在传递到shell 中时执行会截断这个参数(在参数还没有输入完全按下 enter 回车),所以有时不会成功。
而且有些字符 escape 也很难转换为 shell 的原文本参数

所以,这个方法行不通

新建文件

由于寄存器难以传到 shell 作为参数, 我就想到可以把寄存器的内容复制到一个新的 文件 buffer 中, 然后将文件内容拷贝到剪切板,然后删除文件。
如下,每个 <cr> 分隔开 两条 命令,

在 visual 模式下选中,依次按下 ;y即可复制

map ;y "ay: vs vim-copy<cr>"aP:wq<cr>:call system("/mnt/c/Windows/System32/clip.exe < vim-copy && rm vim-copy")<cr><cr>

各部分解释如下

这个办法可以很好地复制, 唯一的缺点就是打开新buffer 窗口,再关闭,屏幕画面变化大,看着不舒服:astonished:

write命令

write 命令缩写为 w, 直接使用就是 保存缓冲区

他后面可以接shell 命令与 shell 交互


:w !echo

这是对于整个文件,也可以选择一部分,
而进入 visual 模式下选中,再按下:, 则进入命令行且将选择的位置也输入进命令行
这是可以 直接 传递给 clip.exe 程序。 执行后,选中的部分备剪切掉了,可以按 u恢复

在 visual 模式下选中,依次按下 ;y即可复制
map ;y : !/mnt/c/Windows/System32/clip.exe<cr>u
这也是最优的方法了,如果你有更好的方法,欢迎赐教。

粘贴

从 Windows 剪切板 粘贴到 VIM

pastetoggle

如果 VIM 没有设置set mouse=a, 那么可以直接右击粘贴,设置了之后要按住 shift再右击粘贴

然而这样存在问题,就是 vim 设置了autoindent,它会错误的将粘贴进的文本进行缩进, 而不是粘贴原文。

这个办法可以 set pasteset nopaste解决,设置了paste 后,就可以原文粘贴,

而这样输入命令切换很麻烦, 可以set pastetoggle=<f12>,或者其他按键,这样按一次就可以切换 paste 状态。

这样比平常的 paste 动作 要多一个pastetoggle 操作,所以不好

windows paste 程序

在 了解到上面 复制时使用的 clip.exe程序,我就在想是不是 windows 有也专门paste的程序 (这个程序是和 cmd 交互的,加之, wsl 也可以执行 exe程序)

很遗憾,windows 没有

但是令人高兴的是,一个网站上有,点击这里下载, 然后解压放到 C:Windows/System32目录下
使用 vim 的 read 命令进行与 shell 的交互, 即将 shell命令执行的输出 读到当前 buffer

映射如下

在任何模式下按下 ;p 即可粘贴

map ;p :read !/mnt/c/Windows/System32/paste.exe <cr>i<bs><esc>l
map! ;p <esc>:read !/mnt/c/Windows/System32/paste.exe <cr>i<bs><esc>l

后面的 i<bs><esc>l执行退格操作,以便接着当前的行 粘贴。不然会 paste 到新的一行.

综上所述,最终解决方案为:
点击这里下载, 然后解压放到 C:Windows/System32目录下

再在 .vimrc文件中增加如下映射

map ;y : !/mnt/c/Windows/System32/clip.exe<cr>u
map ;p :read !/mnt/c/Windows/System32/paste.exe <cr>i<bs><esc>l
map! ;p <esc>:read !/mnt/c/Windows/System32/paste.exe <cr>i<bs><esc>l

WSL 真香,强烈推荐入坑 :grimacing:
还想起一个 瑕疵, WSL 不支持32 位的程序, 不过可以安装 qemu 等解决。

另外 windows terminal 在今年 6月中旬也会来到,值得期待。

参考

上一篇下一篇

猜你喜欢

热点阅读