当前位置:K88软件开发文章中心编程工具Vim → 文章内容

Vimscript 实例研究:Grep运算符(Operator),第二部分

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-24 10:53:56

由 Loen 创建, 最后一次修改 2016-02-24 目前为止,我们已经完成了一个原型,是时候扩充它,让它更加强大。记住:我们初始目标是创建"grep运算符"。我们还需要做一大堆新的东西来达成目标, 但要像前一章的过程一样:从简单的东西开始,并逐步改进直到它满足我们的需求。在开始之前,注释掉~/.vimrc中在前一章创建的映射。我们还要用同样的快捷键来映射新的运算符。新建一个文件创建一个新的运算符需要许多命令,把它们手工打出来将很快变成一种折磨。 你可以把它附加到~/.vimrc,但让我们为这个运算符创建一个独立的文件。我们有足够的必要这么做。首先,找到你的Vimplugin文件夹。在Linux或OS X,这将会是~/.vim/plugin。 如果你是Windows用户,它将位于你的主目录下的vimfiles文件夹。(如果你找不到,在Vim里使用`:echo $HOME命令) 如果这个文件夹不存在,创建一个。在plugin/下新建文件grep-operator.vim。这就是你放置新运算符的代码的地方。 一旦文件被修改,你可以执行:source %来重新加载代码。 每次你打开Vim,这个文件也会被重新加载,就像~/.vimrc。不要忘了,在你source之前,你_必须_先保存文件,这样才能看到变化!骨架(Skeleton)要创建一个新的Vim运算符,你需要从两个组件开始:一个函数还有一个映射。 先添加下面的代码到grep-operator.vim:nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@function! GrepOperator(type) echom "Test"endfunction保存文件并用:source %source它。尝试通过按下<leader>giw来执行"grep整个词"。 Vim将在接受iw动作(motion)后,输出Test,意味着我们已经搭起了骨架。函数部分是简单的,没有什么是我们没讲过的。不过映射部分比较复杂。 我们首先对函数设置了operatorfunc选项,然后执行g@来以运算符的方式调用这个函数。 看起来这有点绕,不过这就是Vim工作的原理。暂时把这个映射看作黑魔法吧。稍后你可以到文档里一探究竟。可视模式我们已经在normal模式下加入了这个运算符,但还想要在visual模式下用到它。 在之前的映射下面添加多一个:vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>保存并source文件。现在在visual模式下选择一些东西并按下<leader>g。 什么也没发生,但Vim确实输出了Test,所以我们的函数已经运行了。之前我们就见过<c-u>,但是还没有解释它是做什么的。试一下在可视模式下选中一些文本并按下:。 Vim将打开一个命令行就像平时按下了:一样,但是命令行的开头自动添加了'<,'>!Vim为了提高效率,插入了这些文本来让你的命令在被选择的范围内执行。 但是这次,我们不需要它添倒忙。我们用<c-u>来执行"从光标所在处删除到行首的内容",移除多余文本。 最后剩下一个孤零零的:,为调用call命令作准备。我们传递过去的visualMode()参数还没有讲过呢。 这个函数是Vim的内置函数,它返回一个单字符的字符串来表示visual模式的类型:?"v"代表字符宽度(characterwise),"V"代表行宽度(linewise),Ctrl-v代表块宽度(blockwise)。动作类型我们定义的函数接受一个type参数。我们知道在visual模式下它将会是visualmode()的返回值, 但是在normal模式下呢?编辑函数体部分,让代码像这样:nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>function! GrepOperator(type) echom a:typeendfunctionSource文件,然后继续并用多种的方式测试它。你可能会得到类似下面的结果:按下viw<leader>g显示v,因为我们处于字符宽度的visual模式。按下Vjj<leader>g显示V,因为我们处于行宽度的visual模式。按下<leader>giw显示char,因为我们在字符宽度的动作(characterwise motion)中使用该运算符。按下<leader>gG显示line,因为我们在行宽度的动作(linewise motion)中使用该运算符。现在我们已经知道怎么区分不同种类的动作,这对于我们选择需要搜索的词是很重要的。复制文本我们的函数将需要获取用户想要搜索的文本,而这样做最简单的方法就是复制它。 把函数修改成这样:nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>function! GrepOperator(type) if a:type ==# 'v' execute "normal! `<v`>y" elseif a:type ==# 'char' execute "normal! `[v`]y" else return endif echom @@endfunction哇。好多新的东西啊。试试按下<leader>giw,<leader>g2e和vi(<leader>g看看。 每次Vim都会输出动作所包括的文本,显然我们已经走上正道了!让我们把这段代码一步步分开来看。首先我们用if语句检查a:type参数。如果是'v', 它就是使用在字符宽度的visual模式下,所以我们复制了可视模式下的选中文本。注意我们使用大小写敏感比较==#。如果我们只用了==而用户设置ignorecase,?"V"也会是匹配的,结果_不会_如我们所愿。重视防御性编程!if语句的第二个分支则会拦住normal模式下使用字符宽度的动作。剩下的情况只是默默地退出。我们直接忽略行宽度/块宽度的visual模式和对应的动作类型。 Grep默认情况下不会搜索多行文本,所以在搜索内容中夹杂着换行符是毫无意义的。我们每一个if分支都会执行normal!命令来做两件事:在可视状态下选中我们想要的文本范围:先移动到范围开头,并标记进入字符宽度的visual模式移动到范围结尾的标记复制可视状态下选中的文本。先不要纠结于特殊标记方式。你将会在完成本章结尾的练习时学到为什么它们会不一样。函数的最后一行输出变量@@。不要忘了以@开头的变量是寄存器。@@是"未命名"(unnamed)寄存器: 如果你在删除或复制文本时没有指定一个寄存器,Vim就会把文本放在这里。简明扼要地说:我们选中要搜索的文本,复制它,然后输出被复制的文本。转义搜索文本既然得到了Vim字符串形式的需要的文本,我们可以像前一章一样将它转义。修改echom命令成这样:nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>function! GrepOperator(type) if a:type ==# 'v' normal! `<v`>y elseif a:type ==# 'char' normal! `[v`]y els

[1] [2]  下一页


Vimscript 实例研究:Grep运算符(Operator),第二部分