防止 Vim 在退出时清空剪贴板

54

当我从终端打开Vim,将一些文本复制到系统剪贴板中,然后退出Vim时,系统剪贴板会被清空。

如何保留已复制的文本在剪贴板中?


4
请阅读常见问题解答,要求关闭问题的人。"程序员常用的软件工具"不是离题的内容。 - Karl Bielefeldt
7
@TLP 必须是 Linux。如果我没记错,过程如下:1. 你复制文本。2. Vim 告诉 X 它有剪贴板数据(“告诉它有数据”,而不是“将数据放入剪贴板”)。3. 你退出 vim。4. 现在 X 不知道在哪里可以获取剪贴板数据:剪贴板被“清空”了。 - ZyX
因此,解决方法可能是创建一个守护进程,当某个东西告诉X它(某个东西)有剪贴板数据时,它将获取这些数据,并依次告诉X它(守护进程)拥有这些数据。在这种情况下,当某个东西退出时,守护进程仍然存在并能够提供这些数据。在您的存储库中搜索“剪贴板管理器”,它应该可以解决此问题。 - ZyX
在我的OS X上没有发生这种情况。即使退出vim,我仍然可以访问剪贴板中数据的内容。你确定你正在使用“+”寄存器进行复制吗? - user616736
@yoda。它必须使用*寄存器可再现,并且在某些更新后,它开始以+寄存器的方式工作(如果我没有弄错,那应该是X更新)。 - ZyX
显示剩余4条评论
7个回答

49

superuser综合答案,只需将以下内容添加到您的.vimrc文件中即可:

autocmd VimLeave * call system("xsel -ib", getreg('+'))

3
它并不完全符合 TS 的要求:它会将默认寄存器的值保存到剪贴板,而不是剪贴板寄存器。你应该使用 getreg('+') - ZyX
4
感谢Matt和ZyX提供的解决方法。不过需要安装“xsel”。我使用了“getreg('+')”。 - Thanos
1
@Mike,你找到gvim的解决方案了吗?我也遇到了同样的问题。 - DmitMedv
@dmitmedv 不,我还没有。我不知道为什么这对vim有效,但对gvim无效。 - MichalH
1
我只想从我的经验中添加几行。请记住,如果您使用sudo进行复制粘贴,则只能在具有sudo访问权限的应用程序中使用。花了我一个小时才意识到为什么我无法在终端中粘贴我已经以sudo打开的内容。 - Dexter
显示剩余3条评论

10

2
我不明白为什么人们会对这个答案投反对票。它表明问题不仅仅是因为Vim的行为方式,而且影响了许多应用程序。链接展示了如何修复所有受影响的应用程序的问题。你还想要什么? - Jonathan Hartley
有些人,比如我自己,实际上并不想要一个完整的剪贴板管理器,因为我们希望剪贴板在不再需要时立即消失(例如,因为它包含敏感数据)。幸运的是,Parcellite提供了一种守护进程模式,在这种模式下,它将“只是”保持剪贴板的安全。 - Kevin
我发现Parcelite似乎会干扰剪贴板,总体来说不够可靠。 - Leo Ufimtsev

9

根据马特的回答,以下代码使用xclip代替xsel

autocmd VimLeave * call system('echo ' . shellescape(getreg('+')) . 
            \ ' | xclip -selection clipboard')

这对我大部分起作用,但每一行复制后粘贴回来时都包含一个尾随的反斜杠。其他人有这个问题吗/有人知道解决方法吗? - evanrmurphy
1
将其改为 echo -n,这样它就不会向您的剪贴板添加新行 ;) - DarkWiiPlayer
3
哦,编辑完另一个答案后才看到这个回答。不过,使用 xclip 解决方案可能更少出错,可以这样做:system("xclip -selection clipboard -i", getreg('+')) - Charlie Gorichanaz

4

我遇到了这个问题,以及一个相关的问题,即使用ctrl-z挂起vim也会清除剪贴板。我已经扩展了Matt的解决方案来解决这两个问题:

set clipboard=unnamedplus

if executable("xsel")

  function! PreserveClipboard()
    call system("xsel -ib", getreg('+'))
  endfunction

  function! PreserveClipboadAndSuspend()
    call PreserveClipboard()
    suspend
  endfunction

  autocmd VimLeave * call PreserveClipboard()
  nnoremap <silent> <c-z> :call PreserveClipboadAndSuspend()<cr>
  vnoremap <silent> <c-z> :<c-u>call PreserveClipboadAndSuspend()<cr>

endif

if executable("xsel")的保护是为了避免在未安装xsel的情况下出现错误。 nnoremap映射可以在从正常模式挂起时保留剪贴板,而vnoremap映射则处理从可视或选择模式挂起。

我已确认此方法适用于vim 7.4和8.0。


谢谢您的帖子!它很有效。但是,如果我使用 xclip 像这样 call system('echo ' . shellescape(getreg('+')) . \ ' | xclip -selection clipboard')。当我使用 ctrl+shift+v 时,会在使用 <c-z> 暂停 vim 后冻结我的终端一分钟。 - roachsinai

3
使用NeoVim,它默认不会在退出时清除剪贴板。你仍需要set clipboard=unnamedplus(通常在~/.config/nvim/init.vim中)并安装xselxclip工具。

请记住,一些其他默认设置也是不同的。


谢谢!添加 clipboard=unnamedplus 对我很有帮助。它甚至解决了剪贴板在不同标签页之间无法传递的问题。 - Misguided Chunk
谢谢!添加 clipboard=unnamedplus 对我很有帮助。它甚至解决了剪贴板在标签页之间无法传递的问题。 - Misguided Chunk

1

基于 Matt的答案

当使用他的方法复制多行时,粘贴时会在行末添加反斜杠。

这应该可以解决这个问题。

autocmd VimLeave * exe ":!echo " . shellescape(getreg('+')) . " | xclip -selection clipboard"

当我在使用“shellescape”和“system”时,换行符会被转义。但是当我使用exe时,这种情况并未发生。
不知道原因,但这个方法可行。

0

如果我理解没错的话,Vim 的一些特点是:
1)Vim 使用寄存器而不是剪贴板来存储复制/剪切数据。
2)这些寄存器在退出 Vim 时会被保存到状态文件中,但除非您手动打开文件并检查其内容,否则无法在运行进程之外访问它们。
3)在 Vim 运行时将内容保存到 + 寄存器中,可以将其粘贴到其他应用程序中。
4)通过暂停 Vim(CTRL-Z)而不是关闭它,这些寄存器仍然可以访问。

这是否有所帮助?


1
当Vim仍在运行时,我能够将其粘贴到其他窗口/终端。使用Ctrl + Z挂起Vim会清除已复制的文本,就像退出一样。 - Thanos
再次说明,我的经验非常有限,因为我通常通过 PuTTY 终端使用 vi。我能够学到的要点是,程序在运行时使用本地寄存器来存储数据到剪贴板,一旦应用程序终止,寄存器就会被清除,数据将无法访问,只能保存在关闭时写入的缓存文件中。如果这也影响了挂起状态,我就无法提出其他建议了。祝你好运:D - Grambot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接