Vim 剪贴板内容丢失问题的解决办法

在以前的一篇博文中曾经提到利用 "+ 寄存器使用系统剪贴板拷贝粘帖内容。在使用中你或许会碰到这样一个问题:用 vim 打开一个文件,复制其中的一段包含中文的内容(用 "+ 寄存器),然后关闭 vim ,然后在另一个打开的 vim 中粘帖,此时,中文都变成了乱码。

如果你使用其他编辑器,比如 Emacs,同样存在这种问题。实际上,程序退出后丢失剪贴板内容是 Linux 系统上大多数软件普遍存在的一个“bug”。

原因

在用户进行“选择”或“复制”动作的时候,Xorg 并没有拷贝真正的数据,而只是拷贝了一份原始数据的引用。这样在当前程序退出后,原始数据被释放,而 Xorg (确切的说是 Xorg 的剪贴板管理器)并没有原始数据的拷贝,导致用户“选择”或“复制”的内容丢失。

可以使用如下命令观察一下剪贴板内容的变化:

$xsel -b

那这是 Xorg 的 bug 么? 与其说是 bug,不如说是一种特性。Xorg 这样做,是为了减少不必要的数据拷贝,从而提高性能。

Freedesktop 的“剪贴板管理器规格说明(Clipboard Manager Specification)”中规定,剪贴板的当前拥有者,比如前面提到的 vim,在退出时应该向剪贴板管理器发送请求,请求其接管剪贴板。剪贴板管理器在收到此种请求时再根据情况拷贝原始数据,并提供给后来的粘帖操作使用。

实际情况是,很少有软件遵从以上规定。这也就是大部分软件都存在丢失剪贴板内容的问题的原因。不幸的是,我们最常用的 vim 也在此列。

还有个问题是,为什么 vim 复制的英文内容没丢失呢?或者说,为什么 vim 复制的内容没丢失而只是中文变成了乱码呢?这个我就只能靠猜测了。因为,vim 内部使用了自己的寄存器,而我们把默认的寄存器映射到系统剪贴板。当我们再次打开 vim 时,vim 发现默认的寄存器里有数据,它就认为系统剪贴板里也有相同的数据(其实不是)。那它在粘帖时就使用了错误的数据了,而那块存放原始数据的内存刚好没有被清零,但格式编码等信息都已经丢失了。

解决办法

安装一个新的剪贴板管理器。推荐 Parcellite。这是一个轻量级、但功能丰富的剪贴板管理器。

Debian 系的发行版可以直接安装:

$ sudo apt-get install parcellite

当然,Linux 下永远都不会只有一个选择。同样功能的软件,还有针对 Gnome 平台的 glipper、针对 KDE 平台的 klipper 以及针对 XFCE 平台的 Clipman 等。

这些剪贴板管理器除了能解决本文提到的问题之外,还有保持“选择”或“复制”历史的功能。套用一位用户的话:“你想重用几小时前甚至昨天复制的内容么?Klipper 帮你实现。”

参考资料

  1. http://askubuntu.com/questions/143659/gedit-clears-contents-of-clipboard-on-exit-how-to-keep-it
  2. https://wiki.ubuntu.com/ClipboardPersistence
  3. http://freedesktop.org/wiki/ClipboardManager
Creative Commons License Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license .