案例分析:grep操作符,第三部分

我们新的“grep操作符”运行的很好,但还是要想办法让你的用户在编写 Vimscript 时感觉轻松惬意。 我们可以再优化两点,使这操作符可以更好的在 Vim 生态中发挥作用。

保存寄存器

如果复制文本到无名寄存器,那我们就把之前寄存在那的内容给清除了。 更进一步的,使用我们的操作符并移动,再可视化选择文本并复制,这样也会清除上次可视化选择的文本。

这对我们的用户不是很友好,所以在这种情况下需要避免使用可视化选择,并且在任何需要复制文本的时候, 把无名寄存器中的内容保存起来,这样在处理完成之后,就可以恢复了。 修改代码成如下:

nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>

function! GrepOperator(type)
    let saved_unnamed_register = @@

    if a:type ==# 'v'
        normal! `<v`>y
    elseif a:type ==# 'char'
        normal! `[y`]
    else
        return
    endif

    silent execute "grep! -R " . shellescape(@@) . " ."
    copen

    let @@ = saved_unnamed_register
endfunction

我们在函数的顶部和底部分别添加了两行 let 语句。 第一行,把 @@ 的内容保存到一个变量中,然后第二行恢复它。 此外,在我们的操作符应用到一个移动命令时,我们用复制替换可视化选择。

保存并载入执行文件。为了确保它能正常运行,我们先试着复制一些问文本,然后按下 <leader>giw 来运行我们的操作符, 然后按下 p 粘贴出来,并检查是不是之前复制的文本。

当编写 Vim 插件是,你应该总是力求保存和恢复任何代码会修改的设置或寄存器,这样才能不让你的用户感到诧异和困惑。

命名空间

我们的脚本在全局命名空间中创建了一个名为 GrepOperator 的函数。 这可能不是一个大问题,但是当你编写 Vimscript 时,安全肯定远胜于道歉。

我们可以通过微调几行代码来避免污染全局命名空间。 把文件编辑成如下:

nnoremap <leader>g :set operatorfunc=<SID>GrepOperator<cr>g@
vnoremap <leader>g :<c-u>call <SID>GrepOperator(visualmode())<cr>

function! s:GrepOperator(type)
    let saved_unnamed_register = @@

    if a:type ==# 'v'
        normal! `<v`>y
    elseif a:type ==# 'char'
        normal! `[v`]y
    else
        return
    endif

    silent execute "grep! -R " . shellescape(@@) . " ."
    copen

    let @@ = saved_unnamed_register
endfunction

最上面三行代码被修改了。首先,我们在函数名前添加了个 s:,这会让它处于当前脚本的命名空间内。

我们也修改了映射,在 GrepOperator 函数前面加上了 <SID>,这样就能找到函数了。 如果我们不加,那它们就会在全局命名空间中找,而这是找不到的。

恭喜,我们的 grep-operator.vim 脚本不只是有用而已了,而是一个完整的 Vimscript 成员了!

练习

阅读 :help <SID>

奖赏自己一份甜点吧。这是你应得的!

原文地址:http://learnvimscriptthehardway.stevelosh.com/chapters/34.html