我如何将 Vim 寄存器的内容传递给外部脚本?

我如何将 Vim 寄存器的内容传递给外部脚本?

本质上,我想在 Vim 脚本中创建一个操作符,将选定的文本发送到外部 (Python) 脚本。它的行为应该与通常期望的操作符一样,无论是在可视模式下还是使用移动来选择文本。事实证明,这对我来说比我预期的要困难,一个有趣的限制是,操作符需要在 Vim 6.3 到 7.0 版本上工作。我使用的是 Vim 的控制台版本,而不是 GVim,因为它更适合我的个人工作流程。

我的动机:我想将文本从 Vim 复制到系统剪贴板(不使用鼠标),以便可以将其粘贴到另一个终端选项卡中。令人沮丧的是,在我使用的系统上,Vim 编译时不支持剪贴板,因此“+”和“*”寄存器对我没用。编写一个快速的 Python 脚本将任意文本放入剪贴板很容易,但麻烦的是将文本从 Vim 传递给脚本。

我尝试过的:我的第一个想法是提取文本,创建一个新的缓冲区,将文本放入其中,将其保存为 /tmp 中的文件,然后从函数中执行类似“cat /tmp/stuff | clipboard.py”的命令。更具体地说:我曾经let scratchFile = system("mktemp")创建一个临时文件,badd将文件添加为缓冲区,然后buffer切换到新缓冲区。然后,我将正在操作的文本放入缓冲区,写入,然后执行 do 操作,silent execute "!cat % | clipboard.py"然后bd删除缓冲区。这实际上不起作用。(它搞砸了 Vim 在屏幕上绘制原始文件内容的方式,以至于我必须在可视模式下突出显示文件才能再次显示文本。:redraw不能解决问题。)

有没有更好的方法来解决这个问题?

编辑以添加我正在编写的脚本:

nnoremap <C-y> :set operatorfunc=<SID>CopyClipboard<cr>g@
vnoremap <C-y> :<c-u>call <SID>CopyClipboard(visualmode())<cr>

function! s:CopyClipboard(type)
    let saved_register = @@

    if a:type ==? 'v'
        normal! `<v`>y
        let scratchFile = system("mktemp")
        execute "badd " . scratchFile
        execute "buffer " . scratchFile
        normal! P
        write
        silent execute "!cat % | clipboard.py"
        execute "bd! " . scratchFile
    elseif a:type ==# 'char'
        normal! `[v`]y
    else
        return
    endif

    let @@ = saved_register
endfunction

答案1

:buffer将打开新的临时文件而不是当前缓冲区。请使用writefile()函数。它也可能有助于解决重绘问题。

答案2

我想说,实现这一目标的方法不止一种,但您的步骤可能会简化,这取决于您的实施方式。

首先,您可以直接将一段文本写入文件,而无需 :badd。如果您已直观地选择了文本,只需按 :,它就会自动为您插入适当的范围。继续输入“ w somefile”。Vim 将只将范围指定的行写入文件(如果需要,会创建文件)。然后,您可以继续将文本发送到外部程序。

其次,您甚至可以使用“ ”将文本直接写入管道,而不是写入文件然后调用命令:w !command。(必要时,请不要忘记您的范围。)

但是,这两个选项在 Vim 处理 :-命令行中可能遇到的整行(而不是部分行)范围时会出现问题,而且它无法(轻易)涵盖您明示和暗示的所有用例,因此我认为您的原始方法可能更合适。在没有看到您的实际实现的情况下,我无法想出一个确切的理由来解释为什么它会弄乱 Vim 的显示——我有想法,但它们很难抽象地解释,而不是有例子可供参考。

相关内容