tmux + vim的复制配置
做嵌入式的同学,大多在Linux环境下开发。现在也有很多同学用OSX开发。其实他们都是类Unix系统。作为一个开发者,效率很重要。有很多重复琐碎的动作,如果能提高一点效率,多次累积起来,节省的时间和精力也是可观的。在提升效率的同时,做一个很有效率,而避免琐碎重复的动作,也很有助于心情的愉悦。所以,但凡有机会,我都会给别人安利一些好用的工具,例如tmux,vim,fish啊,等等。
有人称tmux, zsh, vim是文本处理的三剑客。这三个工具用好了确实好用。我目前的开发环境使用的是fish + tmux + vim。fish的作用和zsh差不多。本文想着重介绍的是困扰我很多年的tmux + vim的剪贴板问题。
tmux下的复制
在毕业后的若干年内,我一直在Windows下,使用putty + ssh +tmux连接远端的Linux服务器做开发。好处是,tmux可以做session管理,即便putty ssh关闭,任务不会中断。只要服务器不关闭,下次打开仍然可以快速恢复工作现场。
tmux分屏模式下的文本选中
tmux中的panel在多任务的情况下非常好用。但带来的问题是,当tmux有横向分屏的时候,复制好困难。文本的选中会跨越panel边界(图截不出来,相信使用tmux的新手同学,应该都遇到过这个问题)。解决的办法是,打开tmux的鼠标模式:
set-option -g mouse on
此时,如果通过鼠标选中,就不会跨越分屏边界。怎么复制,对于新手来说,又是一个问题。
vim用:vsplit命令分屏的时候,也有同样的问题,解决方法如出一辙,使能鼠标模式,set mouse=a。
tmux复制模式下的复制
tmux的所有操作都是通过bind-key实现的。本身有一套默认的bind-key table,当然也可以自定义,tmux插件也可以帮你定义。所以有什么不清楚的,可以直接自行查bind-key table。方法是:
- 通过
ctrl + [:
进入tmux命令模式 - 执行
list-keys
命令就可以了
这里需要注意的是较新的tmux 中的bind-key table较老版本的完全不同。例如笔者当前使用的最新release版tmux2.8,而Ubuntu 16.04 LTS版本源中自带的是tmux 2.1。据说tmux中间进行过重构,导致很多功能其实并不兼容老版本。所以推荐使用新版本。
Ubuntu 16.04 LTS版本的源中自带的tmux是2.1的。这会导致很多功能没法使用
# tmux 2.8 list-keys bind-key -T copy-mode C-Space send-keys -X begin-selection bind-key -T copy-mode C-a send-keys -X start-of-line bind-key -T copy-mode C-b send-keys -X cursor-left bind-key -T copy-mode C-c send-keys -X cancel bind-key -T copy-mode C-e send-keys -X end-of-line bind-key -T copy-mode C-f send-keys -X cursor-right bind-key -T copy-mode C-g send-keys -X clear-selection bind-key -T copy-mode C-k send-keys -X copy-end-of-line bind-key -T copy-mode C-n send-keys -X cursor-down bind-key -T copy-mode C-p send-keys -X cursor-up # tmux 2.1 list-keys bind-key C-b send-prefix bind-key C-o rotate-window bind-key C-z suspend-client bind-key Space next-layout bind-key ! break-pane bind-key " split-window bind-key # list-buffers bind-key $ command-prompt -I #S "rename-session '%%'" bind-key % split-window -h bind-key & confirm-before -p "kill-window #W? (y/n)" kill-window
是不是很不一样?请自行忽略2.1版本。
2.8中的每一行其实运行的是一个bind-key命令,具体参数可以参考tmux man page
- -T: 指定表格
- -r: 指定该按键可以repeat。例如调整panel大小,你不想每放大缩小一次都要按prefix吧,那会抓狂的。
copy-mode就是一个具体table,在你按下
ctrl + [
进入复制模式时生效。同理还有个叫prefix的table,也就是普通模式下的按键表。
话说这么多,到底怎么复制?搜索这个表格的是否有copy-selection
就可以了。所以通常Enter
会被映射成send-keys -X copy-selection-and-cancel
。也就是按下Enter,选中的文字会被复制到tmux剪贴板。
tmux下复制到Windows剪贴板
这个才是本篇想说的话题。因为我花了好些年才找到答案。所以可见经验的传承是多么重要。下面先说怎么做,再说为什么。
如何做?
首先单纯靠putty是没办法的,因为putty只是单纯的terminal emulator。而Linux的剪贴板管理是需要X-Window支持的。所以你需要的是一个完整的X11 forwarding的环境。X11 forwarding有很多途径可以做到,可以自行google,笔者选择了一个turn key solution,就是安装MobaXTerm。默认的配置就已经使能X11 server和X11 forwarding了。
接下来,要做的就是:
- 确定你的Linux系统里有X11界面,如果没有请自行google安装
- 确定你的Linux系统里有xclip, xsel或xclipboard三者之一
- 如果你的DISPLAY变量在tmux下不正常,可以在.tmux.conf下添加
set -g update-environment "\
DISPLAY \
"
- bind-key -T copy-mode y send-keys -X copy-pipe-and-cancel "xsel -i --clipboard"
最后一步更优雅的解决方法是安装tmux-yank插件。
为什么要这么做?
Linux的桌面系统管理了一个剪贴板,这个剪贴板依赖于X Window系统,由前述的几种app管理,类似于Windows下的clip.exe。当在Windows下用ssh连接Linux的时候,如果未设置X11 forwarding,则在Windows下是无法使用到xsel,xclip或者xclipboard的,所以无法访问Linux的剪贴板内容。如果设置好了X11 forwarding,则在Windows下就能访问Linux剪贴板。
tmux本身也管理了一个剪贴板,称为buffer。tmux的命令copy-selection, paste-buffer, list-buffers就是针对tmux自身的剪贴板的操作。tmux原生支持,通过空格选中,Enter复制,ctrl + ] 粘贴。
如果想tmux下将终端显示内容复制到Windows剪贴板要做的就是把tmux剪贴板发送到X11的剪贴板中。tmux-yank插件做的就是这件事。当然你也可以通过在copy-mode-vi表格里绑定任何按键来做这件事情。
vim复制到Windows剪贴板
没有运行在tmux下的vim或是gvim要复制到Windows剪贴板,或者说是系统剪贴板,依赖的是vim的寄存器操作。可以自行google。系统剪贴板对应的vim寄存器是"+。所以在vim下如果想复制到系统剪贴板,你可以用"+y来取代平时常用的y。例如:
- "+yy:复制当前行到系统剪贴板
- "+yw:复制当前的单词到系统剪贴板
如果vim运行在tmux下,因为tmux自带的剪贴板就有点麻烦了。这时候有一个插件就比较有用了——vim-tmux-clipboard。他依赖于另一个vim插件vim-tmux-focus-events。装好这两个插件,在.tmux.conf中添加
set -g focus-events on
大功告成。现在在vim下,直接使用yank快捷键,不用指定寄存器,就可以直接复制内容到tmux剪贴板,同时因为tmux-yank的存在,文本也会被复制到系统剪贴板。