vim与系统剪切板之间的复制粘贴

1. 背景

vim各种快捷建溜得飞起,然而与系统剪切板之间的复制粘贴一直都是我的痛。

每次需要从vim中拷贝些文字去浏览器搜索,都需要用鼠标选中vim的文字后,Ctrl+cCtrl+v,硬生生掐断了纯键盘的流畅感

而且,vim中的块选择多爽,如果只想要拷贝某一个块的数据,鼠标操作就完全没辙了

忍无可忍,无需再忍,今天就彻底解决这个问题

2. vim与系统剪切板之间的交互

2.1 vim支持clipboard特性

本章参考自 NearXDU的博客

确认vim编辑器是否支持clipboard特性

[GMPY@16:33 ~]$ vim --version| grep "clipboard"

支持这特性的检索结果应该包含 +clipboard,而不支持则会是 -clipboard

如果不支持怎么办?安装新的vim吧。可以参考这边文章 从源码安装vim

2.2 vim的寄存器

本章参考自 rainysia的博客

vim会有一些存储空间来暂存内容,vim中将这些存储空间叫寄存器。此寄存器非我们硬件所说的寄存器,可以理解为是一种cache。

例如我们在vim中y操作复制的内容,实际就是暂存到寄存器中。

怎么查看寄存器内容呢?在vim中执行

:reg

在vim中,这些寄存器也有好几个

表示符号 名称 作用
"" 无名(unnamed)寄存器 缓存最后一次操作内容
"0"9 数字(numbered)寄存器 缓存最近操作内容,复制与删除有别,"0寄存器缓存最近一次复制的内容,"1-"9缓存最近9次删除内容
"- 行内删除(small delete)寄存器 缓存行内删除内容
“a"z"A - ”Z 具名(named)寄存器 可用于主动指定
":, "., "%, "# 只读(read-only)寄存器 分别缓存最近命令、最近插入文本、当前文件名、当前交替文件名
"= 表达式(expression)寄存器 用于执行表达式命令
"*, "+, "~ 选择及拖拽(selection and drop)寄存器 存取GUI选择文本,可用于与外部应用交互
"_ 黑洞(black hole)寄存器 不缓存操作内容(干净删除)
"/ 模式寄存器(last search pattern) 缓存最近的搜索模式

为了要与系统的剪切板交互,我们着重关注"*"+

在vim中进入visual视图后使用"Ny(N表示特定寄存器编好),将内容复制到特定的剪切板

因此,如果要把数据从vim拷贝到系统剪切板,我们只需要在visual模式下执行

"+y

注意的是,是 双引号 + 加号寄存器 + y。通过这命令copy后就可以去浏览器Ctrl+v啦

如果从浏览器Ctrl+c后,要粘贴到vim中,则需要

"+p

"*"+有什么差别呢?

"* 是在系统剪切板中表示选择的内容
"+ 是在系统剪切板中表示选择后Ctrl+c复制的内容

3. 使用快捷键

"+y"+p的输入挺麻烦的,我们直接为他们创建个快捷键吧

vim创建快捷键的原理可以看 jalused的博客

我使用的快捷键如下

" 支持在Visual模式下,通过C-y复制到系统剪切板
vnoremap <C-y> "+y
" 支持在normal模式下,通过C-p粘贴系统剪切板
nnoremap <C-p> "*p

将上面的内容copy到~/.vimrc中即可生效,效果就是:

  1. 在vim的visual模式下选中了要复制的内容,再用Ctrl + y复制到系统剪切板,直接去其他窗口中Ctrl + v粘贴
  2. 在其他窗口中选择之后(不一定要Ctrl + c),可直接在vim中用Ctrl + p来粘贴

4. ssh远程复制

实现ssh远程复制到系统剪切板,此处用到 clipper,下图是其原理,简单来说就是远程通过socket/网络发到本地,本地再设置到系统剪切板。

clipper: https://github.com/wincent/clipper

image

根据上述原理,有以下要求:

  • 本地需要有方法实现设置系统剪切板
  • 本地需要有个常驻服务来接受远程传输的文本
  • 远程与本地通过socket或者指定某个端口进行通信
  • 远程通过某个操作触发数据传输

README中有更详细说明,以下是我的操作过程。

操作环境:
本地:Mac Book (clipper 也支持linux)
远程:ubuntu 服务器版本,不含GUI

4.1 本地安装

本质只是添加了 clipper 的可执行程序,不涉及任何库,除此之外,不同系统拷贝到剪切板的命令不同,请确保本地支持此命令:

  • Mac: pbcopy
  • Linux: xclip 或者 xsel

《Windows/Mac/Linux 如何将内容输出到剪贴板》:https://segmentfault.com/a/1190000024579429

4.1.1 For Mac

使用以下命令直接安装:

brew install clipper

4.1.2 For Linux

不支持常规的 apt/yum,可以考虑用源码安装:

git clone git://git.wincent.com/clipper.git
cd clipper
go build
sudo cp clipper /usr/local/bin

4.2 本地设置常驻服务

4.2.1 For Mac

~/Library/LaunchAgents/ 创建文件 com.wincent.clipper.plist,添加以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.wincent.clipper</string>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/local/bin/clipper</string>
	</array>
	<key>EnvironmentVariables</key>
	<dict>
		<key>LANG</key>
		<string>en_US.UTF-8</string>
	</dict>
	<key>KeepAlive</key>
	<true/>
	<key>LimitLoadToSessionType</key>
	<string>Aqua</string>
</dict>
</plist>

然后执行:

launchctl load -w -S Aqua ~/Library/LaunchAgents/com.wincent.clipper.plist

验证是否正常运行:

$ ps aux | grep clipper
...
xxxx             45041   0.0  0.0 34979812   3300   ??  S     3:59下午   0:00.44 /usr/local/bin/clipper

4.2.2 For Linux

根据 Linux 发行版的不同,可能有点不一样。由于缺少环境验证,可以问问度娘。

其实拉起常驻服务的本质是运行 clipper ,采用默认的配置(端口:8377),我们甚至可以粗暴的跑个后台:

$ nohup clipper &>/dev/null &

clipper 的各个参数可以参考 clipper --help,大多数情况下使用默认的即可。

4.3 映射本地与远程的端口

由于我并不擅长网络,此处沿用 clipper 作者推荐的做法,在 ssh 连接时绑定端口

ssh -R localhost:8377:localhost:8377 user@host.example.org

当然,我们可以配置 ssh,省去每次 ssh 连接的 -R xxxx 选项。

$ cat ~/.ssh/config
Host host.example.org
  RemoteForward 8377 localhost:8377

4.4 远程触发传输

触发的本质是使用 nc 命令向本地的 8377 端口发送数据,例如以下命令发送 test 文本。

echo -n test | nc -N localhost 8377
  • Ubuntu 要使用 -N 参数,否则会无法退出,其他环境请自行验证

4.4.1 vim 触发

我们只需要配置 .vimrc,设置个按键映射就可以了。

nnoremap <C-y> :call system('nc localhost 8377', @0)<CR>

上述的意思是,normal 模式下执行 Ctrl + y 触发传输,通过调用函数 system 执行 nc 命令,把寄存器0的内容通过端口8377发送出去。使用寄存器0意味着,我需要传输必须先 y 拷贝后,再执行 Ctrl + y 传输。

由于我远程的ubuntu是服务器版本,vim不带GUI,导致vim不支持 */+ 寄存器,因此无法实现 Virtual 模式下直接复制,有条件的同学可以试试

4.4.2 tmux 触发

配置 ~/.tmux.conf,添加以下内容:

# Bind "Enter" in copy mode to both copy and forward to Clipper:
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "nc -N localhost 8377"

在tmux的copy模式,绑定 Enter 按键实现拷贝和传输 Clipper

posted @ 2019-07-12 18:13  广漠飘羽  阅读(27016)  评论(2编辑  收藏  举报