Jacky Liu's Blog

Vim 的补全模式加速器,轻松玩转全部 15 种自动补全模式

---- 这是两年前写的一个小工具,是为了学习掌握 Vim 的补全模式,也是为了用起来方便。在那之前,我对 Vim 的补全功能还只是稍微了解,从没用过,因为补全功能默认的按键都是 emacs 式的,太蛋疼了,觉得这样还不如直接手敲。但是后来开始越来越多地写代码(我不是程序员,之前没写过多少),就觉得必须要熟悉 Vim 的补全功能,于是写了这个东东。它主要做两件事:

1: 把 Vim 的 15 种补全模式分成 5 组,映射到 <M-a> 到 <M-g> 5 个按键上,方便使用。好处有两个,一是不用去记 15 个按键组合(我是记不住),二是可以摆脱默认的那种 emacs 式的按键。

2: 在状态栏里做了一个补全模式状态显示器(可选,如下图),可以实时地显示补全模式的状态。不想要的话可以关闭,它就不会显示在状态栏里。

所以,就像是在众多 RPG 游戏里的“腰带”或“快速物品栏”一样,平时把常用的物品放在里面,需要时按一个键就能使用。这个工具自身并没有实质的补全功能,它等于是给 Vim 的补全模式添加了一个“快速物品栏”,里面各种补全模式的分组和相对位置都可以自己设置,可以把最常用的补全模式放在顺手的位置,需要时按一个键就能启动。Vim 提供的 15 种补全模式已经很厉害了,这个工具如同给它们再装上一个加速器,使它们用起来更顺手,当只按很少几个键就能自动补全很复杂的文本之时,编辑速度自然会进一步提高。

 

1. 关于 Vim 补全模式

    ---- Vim 一共提供了 15 种自动补全的模式(:help ins-completion)。其中有两种的补全列表内容与另外两种相同,只是排序不同,这 15 种模式:

 

1.1 文字编辑用的 3 种:

    ---- 文字编辑显然是不用 Vim 的,所以这三种模式比较悲催,我从没用过:

    K 模式    (Vim 默认: CTRL-X CTRL-K) -- 字典补全,查找字典文件中的匹配单词,组成补全列表
    H 模式    (Vim 默认: CTRL-X CTRL-T) -- 分类补全,查找分类文件(thesaurus 文件)中的匹配单词,组成补全列表
    S 模式    (Vim 默认: CTRL-X s)        -- 拼写建议

 

1.2 Vim 牛人用的两种:

    ---- 自定义的,我也没用过:

    O 模式    (Vim 默认: CTRL-X CTRL-O) -- 全能补全,由一个自定义函数生成补全列表
    U 模式    (Vim 默认: CTRL-X CTRL-U) -- 自定义补全,也是由自定义函数生成补全列表

 

1.3 所有人都喜欢的四种:

    ---- 我用来应付 99% 的情况:

    n 模式    (Vim 默认: CTRL-N)        -- 关键字补全,查找 'complete' 选项指定文件中的匹配单词,组成补全列表
    N 模式    (Vim 默认: CTRL-X CTRL-N) -- 关键字补全,查找当前 buffer 里的匹配单词,组成补全列表

    另外两种: p 模式与 P 模式,分别与 n 模式和 N 模式相同,只是补全列表中候选词的排序相反。

 

1.4 程序员用的三种:

    ---- 我不是程序员,也没用过(悲催了,当初干嘛要写这个 :(...):

    T 模式    (Vim 默认: CTRL-X CTRL-]) -- tag 补全,查找 tag 中的匹配单词,组成补全列表
    I 模式    (Vim 默认: CTRL-X CTRL-I) -- 头文件补全,查找当前 buffer 和 include file 中的匹配单词,组成补全列表
    D 模式    (Vim 默认: CTRL-X CTRL-D) -- 定义补全,查找当前 buffer 与 include file 中匹配的名称定义,组成补全列表

 

1.5 特殊语境下专用的三种:

    ---- 还好,偶尔用一用 ...

    V 模式    (Vim 默认: CTRL-X CTRL-V) -- Vim 补全,查找 Vim 的命令名, 函数名等等,组成补全列表
    F 模式    (Vim 默认: CTRL-X CTRL-F) -- 文件名补全,查找匹配的路径或文件名,组成补全列表
    L 模式    (Vim 默认: CTRL-X CTRL-L) -- 整行补全,查找 'complete' 选项指定文件中匹配的整行内容,组成补全列表

 

2. 使用:

 

2.1 显示器里状态显示的含义

    ---- 按 '\b' 可以切换补全状态显示器的开启和关闭。按下 '\b' 后显示器就会出现在状态栏里,再按 '\b' 显示器从状态栏里消失。下图显示的是 normal 模式下,补全模式未启用时的状态。状态显示器中黑色的字符是按键提示符,其它的是补全模式提示符。可以看到 15 种补全模式被分成 5 组,映射到 5 个按键上。带下划线的是对应分组里最近使用的模式,白色带下划线的是所有分组里最近使用的模式。进入 insert 模式后,按键提示符会“点亮”,开启某种补全模式后,相应的补全模式提示符的显示也会跟着调整。

 



2.2 使用常用的补全模式

    ---- 进入 insert 模式后,显示器里的按键提示符会“点亮”,提示这些按键可用,如下图。此时按相应的按键,就可以开启对应分组里的第一种补全模式。比如在 insert 模式下按 <M-d> 可以开启 p 模式,按 <M-g> 可以开启 V 模式。也就是说,一共有 5 种模式是只需要按一次键就能开启的。

 



2.3 使用其它补全模式

    ---- 要使用其它补全模式,先进入对应的分组然后按 <M-w> 或 <M-r> 往两边切换。比如,要使用 F 模式,就先按 <M-g> 进入 V 模式,再按 <M-r> 往右切换,此时就会先退出 V 模式再开启 F 模式,显示器里的状态显示也会跟着更新。要使用 L 模式时就再按一次 <M-r>,或者在 V 模式下直接按 <M-w> 也行。要使用 D 模式,就在 insert 模式下 <M-f><M-w> 或者 <M-f><M-r><M-r>。

 

2.4 选择候选单词,接受当前单词或退出

    ---- 当成功开启了某个补全模式,补全列表就会出现(即使只有一个匹配也会),此时按 i 和 k 可在列表中上下移动,选择候选单词,按空格接受当前选中的单词并留在 insert 模式下继续输入,按 <Esc> 拒绝候选单词,退出补全模式并留在 insert 模式下,再按一次 <Esc> 才会退出 insert 模式,回到 normal 模式。如果启用补全模式失败(没找到候选单词,或者相关选项没设置),就不会出现补全列表,但是显示器里显示的最近使用的模式仍会相应地更新。

    ---- 另外,如果补全列表比较长,也可以按 <C-f> 和 <C-b> 往前/往后翻动,以便快速定位到目标单词上面,这些操作与 normal 模式下的含义接近,用起来最顺手。

    ---- 选择 i 和 k 作为按键映射稍微限制了补全模式的功能,因为本来开启了补全模式以后按这些键是可以继续输入文本的,Vim 会根据新输入的内容即时查找匹配并不断调整补全列表的内容。但是对我来说,实时匹配功能不重要。如果对补全列表的内容不满意,我会先 <Esc> 退出补全模式,修改输入以后再重新开启。相比之下,按键用着方便对我来说最重要。

 

2.5 <M-e> 键

    ---- 这个键有两个功能。当进入 insert 模式还未启用补全的时候,按 <M-e> 会再次启用上次使用的补全模式(显示器中以白色显示)。当已经开启某个补全模式的时候(补全列表已显示),按 <M-e> 会先接受当前的候选单词,然后再次启用同样的补全模式,如下图:
 



    图中显示了在 F 模式下,连续使用 <M-e> 键来依次补全各级目录名的情况。遇到多个选项就按 i 或 k 选择,然后再按 <M-e> 补全,一直到达要找的那个节点。

 

2.6 <Tab> 键

    ---- 按照 Vim 的设置,进入某些补全模式后再次按同样的按键可以启用一些后续的特殊补全行为模式,比如按 'C-x C-l' 进入 L 模式以后再按 'C-x C-l',还有按 'C-x C-p' 进入 p 模式后,再按 'C-x C-p' 或者 'C-x C-n',等等。在这个工具里,这些进入补全模式以后的后续按键都被映射到 <Tab> 上。也就是说,进入 L 模式后按 <Tab>,就相当于按 'C-x C-l'; 进入 p 模式后按 <Tab>,就相当于按 'C-x C-p',等等。

    ---- 当启用某种补全模式以后,如果显示器里的 <Tab> 按键提示符也点亮,就说明这种补全模式下 <Tab> 键可用。至于这种模式下 <Tab> 是什么含义,详细解释在文档里,一般就是 "连续补全" 或 "差异补全" 两种后续的补全方法。

    ---- "连续补全" 是指接受某个文本单元以后,继续把那个文本单元前期出现时相邻的下一个文本单元(一个单词或一行)作为新的补全列表,这样连续按 <Tab> 就可以连续补全前面出现过的内容,直到把一整段都复制到当前的位置来。而 "差异补全"(文档里所说的 "other context")是指输入了 'se' 以后,想要的补全列表不是 ['self', 'sex', 'select'],而是 ['se:xxx', 'se.yyy', 'se#zzz'] 这种。

    ---- 下图两个图显示了在 p 模式下的连续补全和差异补全:
 

 


    连续补全: p 模式下连续按 <Tab>,可以把前面的一整段内容抄过来。

 

           


    差异补全: p 模式下不选中任何候选词然后按 <Tab> 进入差异补全子模式,新出现的候选词与一般情况下不一样,其中后面几个都不是一般的词,前面两个 "正常" 的词是因为它们出现在其它 buffer 里却没出现在当前 buffer 里,这些都是故意要这样的,所以才叫 "差异补全"。
 

 

    ---- 所以。。。看明白了吧?基本上都是噱头。



2.7 关于补全模式的分组

    ---- 跟“快速物品栏”一样,15 种模式怎么分组,每组怎么排序,哪些模式放在每组的第一位,这些都可以在代码里设置。

 

3. 局限

    ---- 开启一种补全模式会牵涉到一系列后台操作,主要是扫描文件并生成补全列表,过程可能有些延迟(如果候选词列表较长),也有可能失败(比如相关的 Vim 选项没有设置)。如果出现这些情况,Vim 会“发呆”一段时间,期间有可能会“吃掉”一些输入字符。所以,如果在 Vim“发呆”的时候就迫不及待地连续按这些被映射过的按键,那结果可能不是想要的。这不是什么严重问题,最多导致一些不想要的文本被输入,按 'u' 可以取消,但是最好避免这种麻烦,等 Vim 有了反应,比如补全列表出现或者显示出了 error message 以后再做下一步操作。使用 Vim 默认的按键是不会有这个问题的,因为按那种 emacs 式的组合按键不可能按得这么快(emacs 的好处体现出来了)。

 

4. 代码

    ---- 代码现在分散在不同文件里,需要整理。等有空把它们整理好我就贴上来。




 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee