• vim之补全1(完全个人定制版)


      关于vim的补全最初的感觉是蛋疼, 真正的蛋疼! 由于在接触linux之前曾经在windows下面学过一段时间软件开发, 那时使用的是vs2010, 现在看来虽然vs启动相当的慢, 编辑器的定制和配置能力有限. 但vs在编程环境上的操作便捷性的确是一个优点, 毕竟我们都是普通的程序员, 达到使用记事本也照样写代码的大牛级水平, 这辈子估计希望都不大. 所以虽然我知道vim原始操作上的原子特性如果熟练之后将具备最为灵活的编辑能力, 我还是的选择的将vim配置的向IDE靠近. 关于vs现在留给我印象最深的是他的VAX插件. 这个有tomato公司出品的第三方补全插件, 让VS拥有了相当高效的补全能力. 用它来编辑代码你再也不害怕那些超长的函数名和宏定义.

      所谓好日子一旦过上了, 你将很难适应较之不好的日子. 我们可以说这是人类积极向上的本能, 也可以说这是我们贪图享乐的劣性. 无论怎么看待它, 我们似乎都逃脱不了这个规律.
    既 然无法逃脱, 我只能去找到实现好日子的办法. 从知道vim也能补全的那天起我就开始惦记这个怎么样才能让vim拥有真正可以的VAX想匹敌的补全能力. 其实网络上有相当多和vim补全相关的教程的讨论. 这些资源是我可以优化自己vim的动力之源. 没有前辈们开辟的道路, 估计我在vim布满荆欹的道路早已连方向都找不到了.  不过即便有这么多的资源可供使用, 在上个星期之前我依然一直没有找到真正让我的满意的补全方案. 这其中的原因下面会一一道明.

      从我在记忆的感知中可以得到一些对VAX 使用的总结, 首先, VAX的补全使用多种算法来让补全变得更加精确. 比如单词的出现的频率以及单词在上下文中离光标位置的远近等. 无论算法是什么, 高效的补全总是离不开一个特性:较高的命中率(这里的命中率指的是在补全列表中我们想要的补全单词出现在更加靠前位置的概率). 这是一个很重要的问题, 比如vim本身是支持tags补全的, vim默认的tags补全快捷键是<c-x><c-]>, 利用tags补全的插件也有几个,比如最初的ommpcommplete和后来的neocomplcache都有使用tags补全, 可是tags补全有诸多问题, 首先的tags补全依赖于tags, 如果没有tags或者即便有tags可是补全的内容并没被更新到tags里面都将导致无法补全. 我之前的<<vim之tags>>文章中最后将tags的更新集成在了f12键上, 这在一定程度上解决了tags补全需要及时更新的问题,
    (只要在编辑代码时不时的通过f12键更新tags即可), 这同时对有效的tags跳转也起到了更加高效的帮助. 第二个tags补全的问题是, tags中记录项对补全来说是没有算法可言的,     tags产生的补全列表完全按照关键字在tags中被搜索到的顺序来定. 这个问题首先导致了tags补全在补全列表中的命中率是不变的, 如果一个在你当前编码中需要经常用到的关键字很不幸的存在于关键字列表的中间或靠后的位置, 如果你需要在补全列表弹出之后不停的按<tab>(也可以是<c-n>或<down>键,他们在补全列表弹出之后都 表示下一个选项之意) 10次才能到达你想要的选择的单词, 那么你将会发现每次你通过相同的单词触发补全这个相同的补全时都几乎都要下翻10次(当然, 你可以通过多写几个单词来减少补全列表里的关键词数量)! 我想这样的补全不出几次你将会来一句: 靠, 还不如手工写! tags补全的第三个问题在于他的速度, 这个问题在我们的tags低于10M的时候不太明显. tags的检索速度本身还是相当快速的, 100M的tags检索一次只需要不到10秒的时间, 同时超出10M的tags在普通的项目中很很少能出现. 可是如果你对一个linux内核做tags索引, 你将发现产生的tags可以达到100M以上. tags的内容也在百万行的级别. 如果你想在包含这样的tags的vim中的使用tags补全的话将会是一个很头疼的问题, 因为你每次补全都需要等好几秒的时间.

      说了tags补全这么多的缺点. 难道tags就没有优点不能用吗? 非也. 我们常规的项目开发大多是建立的别人的基础上开发或者是使用一些自己私有的或第三方的库作为开发基础.

    这 个时候tags补全还是很好用的,  只要项目不是超级大, 对整个项目(包含个人库)建立tags后,当我们需要使用别人代码中关键字和库的中的关键字的时候(大多是第一次使用的时候)触发tags补全, 你将发现还是很有效的. 由于tags可以随着项目的变化而变化, 同时建立速度又很快, 因此应对那些因项目不同而不同的关键字和容易改动的个人库很合适.

      说完tags补全下面的再说说老牌的supertab, 这个插件估计使用vim的没几个不知道吧. 这个插件普及率个人感觉和taglist差不多, supertab的功能其实比较简单, 只是将vim默认的一些补全快捷键整合到了tab键上. 这个插件从一开始就跟着我, 经过几次的分分合合最终到现在成了补全中的主力军. 有人可能会笑话我supertab根本就没有诸如neocomplcache和YouCompleteMe强大, 还用这个真老土. 不过这个小小的supertab看似简单的被后蕴含的东西可不是那么简单. 如果你有耐心将这篇文章看完, 相信你会理解我为何留下了这名老将. 

       和supertab相关的vimrc配置中第一个要提及的是complete选择. 这个选择在vim中控制的是默认的ctrl+n和carl+p补全的列表索引顺序. 由于supertab在默认情况下触发的是ctrl+n补全, 因此complete也控制了supertab的补全列表. complete的默认值是". , w , b , u , U , t , i"意思是补全列表会先搜索当前文件(.) 再搜索其他窗口(w) , 再搜索其他buffer(b) , 再搜索已经卸载的buffer(u), 再搜索不再buffer列表中的buffer(U), 再搜索tags(t), 最后搜索源码中通过#include包含进来的头文件. 上面提及的tags补全在默认情况下也会被ctrl+n和supertab使用. 明显这是一个重复. u和U对我们来说几乎是没有用的,因此可以不用.  如果你有在vim中开多个tab窗口的习惯, 那么可以保留w,如果你和我一样在多文件编辑方面只使用buffer缓冲区机制, 那么这里w也可以省去. 至于"i"代表的#include头文件, 这里我也将其省去了. 因为一般的源文件会包含很多系统的头文件. 这些头文件很可能会比较大(因为这些头文件也会包含别的头文件). 这会影响supertab的搜索速度, 同时会导致检索出来的内容包含很多无用的选择. 如果我们知道某个很长的关键字存在与某个头文件中, 我们可以通过<c-x><c-i>的方式手动触发专门的头文件检索补全(你可能会觉得这些组合键即冗余又难按, 好吧, 君子所见略同, 请耐心看下去, 后面会有解决办法的). 其实如果你通过:help complete 在vim查看complete选择的帮助选项的话, 你将发现complete还一个比较重要的选项"k" , 他表示扫描一个指定文件中的内容(我们称这个文件叫做字典), 这个功能给了我们在补全中一个相当实用的功能. 这里我称之为字典补全. 关于字典补全, 下面会有专门的段落来表述. 好了, 总结上面的分析, 我们的complete选项的最终值只有两个:"." 和"b". 因此, 我在我的vimrc中最后写下了下面的配置(cpt是complete的缩写):

    set cpt=.,b

      这样设置之后的 supertab在每次补全时只会搜索当前文件的上下文和其他你打开了的缓冲区.  为何留下这种补全? 请听分解: 在文章之初我曾提及VAX中使用了很多算法来提高补全结果的命中率. 实际上我们编辑任何文件的时候有一个最为简单但又相当有效的补全算法: 就近补全. 我们在编辑文件的时候大多时候某些单词会重复书写, 当前我们第一次写下的时候没有什么, 但当我们第二此书写同一个单词的时候这将变成一个重复的劳动, 因为我们曾经写过这个单词, 而且就在当前文件中. 我们对这个单词的记忆深刻. 所以我们知道在什么时候希望补全并且希望这里的补全一次性命中. 因为补全的内容就在眼前. 这种需求在编辑代码时更加的突出, 因为一个变量或一个函数在被我们定义之后剩下的肯定是不停的调用他.这样的编码规律会导致有超过一半的时间里我们希望补全的内容其实就在我们的文件之 中.  vim自带的ctrl+n中对当前文件的检索规律是:从当前光标所在位置向文件首检索, 完毕之后再从当前光标的位置向文件尾检索. 这种检索被我称为就近检索. 产生的补全结果自然是离光标越近的关键字出现在越靠前的位置.  因此这种补全被我叫做就进补全. 这是一个相当有效的补全方式, 因为我们首先是知道什么需要这种补全(不止一次的书写过同一个关键词的时候), 我们同时可以预测出补全的结果是什么样子的, 大多时候后如果补全的内容离我们不远, 我们可以不加思索的判断出补全结果的第一个内容就是的我们的想要的结果. 这种补全结果可以被我们预测到的能力可以实现盲补(我自己发明的词, 就是指不需要选择就可以直接断定补全结果是我希望的内容的补全方式). 盲补可是说是补全中最快最快的方式了, 这就像输入法中的五笔的原理, 因为结果是已知和唯一的, 所以可以很快.  即便补全的内容离我们不是很近.只要文件不是超过万行的超级源码,补全结果也是很精确的, 因为的我们这里之设置了搜索当前文件和其他打开的buffer. 这也可以提高补全列表的建立速度和我们的选择速度. vim的ctrl+p补全方式. 正好和ctrl+n相反. 因此补全列表中越是靠近文件头和文件尾的内容越是靠前. 其实这两种的补全方式vim在检索的时候都是用同一套方式完成的(从文件的头和文件尾向光处检索), 只是搜索的结果建立后, ctrl+n从最后一个结果向第一个结果选择. ctrl+p从第一个开始.

      综上所述: 我保留了supertab插件来代替vim默认的ctrl+n(因为tab键比ctrl+n要好按很多, 也习惯很多), 同时将其配置成了补全命中率相当高的就近补全.
    (实践中证明我的补全百分之五十左右用的都是tab键, 不愧是主力啊.)

      注意:请不要在vimrc中配置如下的形式的组合:

       set cpt=k,b,.  我曾经希望将字典补全也被tab接管,于是设置了set cpt=.,b,k 可是在默认的配置下ctrl+n在检索完字典文件之后如果检索结果全部在字典文件中, 那么坑爹的事情就发生了,补全的第一选项竟然不是倒数第一个, 也不知道vim用了什么算法, 反正补全的默认结果竟然落在了列表的中间某个选项上, 这种结果将直接导致字典补全无法实现盲补(因为你无法预测补全结果的第一个是什么). 为了这个问题,我曾经试着将supertab的出发键设置为ctrl+p, 这样设置之后, 补全结果的首选虽然总是乖乖的落在了列表的第一个选项上, 但同时就近补全的能力被剥夺了. 于是乎我就想到了将补全列表完全到过来检索就想到了将set cpt=k,b,. 这样的设置. 在我配置成这样之后更加肯爹的事情发生了. vim每次补全都卡死在搜索字典文件的位置. 重点是这个问题很难找到了, 因为这个时候在我将cpt恢复到".,b,k"之后之前编辑过的文件依然会卡死在补全上. 因为这个问题我花去了几乎整天的时间来查找原因. 最终发现原因在于vim在退出时保存我最后一次正常退出时的一些与文件相关的信息(这些信息的保存需求在vim中添加配置, 同时他们保存在~/.vim/view文件夹中), 这些信息中就包括了补全顺序. 由于每次卡死后无法正常保存. 因此,即便cpt恢复到了".,b,k"的状态, 每次打开之前编辑过的文件加载的保存信息还是最后一次的"k,b,.", 因此问题总是存在. 解决办法是清空view文件中的所有保存记录.这里顺便也提醒一下, 如果你的vim开启了文件的view信息保存功能(大多时候这个功能很有用), 同时你遇到了一些很古怪的灵异问题, 记得清空这个view文件夹试试. 同时如果你做了新的配置. 在测试这个配置之前清空这个view文件夹也是有必要的. 切记, 切记!

      好了, supertab说完了, 下面要上场的是可以和supertab共用了同一个tab键的大将:UltiSnips. 注意的这里我用了可以这个次, 他的潜在含义是可能是不可以的, 网络上大多数字资料中提及容易和supertab和平相处的代码块补全工具(如果你对代码块补全和ultisnips不了解,可以先百度一下)是 snipMate, 这个插件和UltiSnips的功能类似, 都是代码块补全插件. 他们同类功能中最著名的是mac中的txtMates所以带有的snippts功能(堪称神器一般的存在). 最初我接触到的也是snipMate, 这个插件的确可以和supertab比较和谐的共处,只需要修改一个地方就可以实现这个功能(具体修改方法可以在网络上找到). 可是snipMate首先是功能上不够完善, 这其实还是小问题, 因为正常的代码块补全能正常用就可以了. 可是一个致命的问题在于当触发了snipMate补全之后tab键将会被snipMate键接管并用作跳转到下一个代码块中可修改位置上去. 尼玛, 肯爹啊有木有, 每次进入代码块补全区tab键总是按错有木有, 有的补全块还很大, 半天不能用tab补全了有木有, 找遍了网络看玩了帮助文档, 找不到修改跳转到snipMate下一个修改区功能键的方法有木有. 最终我还是受不了了, 在网络中一顿海搜之后遇到了救星UltiSnips.

      其实网络上我并没有找到UltiSnips和supertab共用tab的方法. 最初也的确发现他们不能共用tab键. 可是在一次偶然的修改中我竟然找到方法. 这是一个相当邪门的方法.

      首先要是说的是不能使用的方法.如果你用vender管理插件(关于vunder的用法网络上资源相当丰富.请百度自行了解). 在vimrc中写下如下两句:

    Bundle 'ervandew/supertab'
    Bundle 'vim-scripts/UltiSnips'

      这 两句的意思是到git托管的地方去下载supertab和UltiSnips,其中supertab是由ervandew管理的因此在他的目录下. 而UltiSnips由于没有找到git上的维护着因此直接在vim-scripts的目录找到并且这里的插件大多是vim.org的插件库的一个简单镜 像. 不管在那里, 当你这样设置了supertab和UltiSnips的来源之后并按照vunder的管理方式下载到supertab和UltiSnips之后, 你将发现默认设置下supertab原有的功能会被UltiSnips覆盖.你将永远永用不到可爱的supertab了.我曾尝试过很多设置方法. 均以失败告终.

      一次偶然的机会我发现在vim.rog官网上发布的supertab最新的2.0中使用的.vmb文件格式打包. 下载下来安装之后发现supertab竟然可以和UltiSnips共同使用了.  我找到~/.vim/plugin下面的supertab.vim和vunder中安装的supertab.vim比较之后发现,原来通过vunder安装的supertab比较vim.org官网上发布的最新版还要新(作者应该在之后更新过,但没有向vim.org上发布), 其中添加了很多额外的代码. 很明显这些额外的新内容导致了supertab和UltiSnips的不兼容.至此,supertab和UltiSnips公用tab键的问题解决. 这里我将vim官网的supertab下载链接记录如下:

    http://www.vim.org/scripts/script.php?script_id=1643

    下载页面中下载supertab.vmb的2.0版本即可.你可以继续使用vunder管理supertab, 只需要在安装一次supertab.vmb(安装方法是用vim打开supertab.vmb然后:so %)之后到~/.vim/plugin下将这里的supertab.vim剪切覆盖掉vunder目录下安装的supertab.vim(一般在~/.vim/vunder/supertab/plugin/目录下)即可. 另外, UltiSnips默认也是通过tab来跳转到下一个块可修改区的,不过UltiSnips提供了接口可以设置这个按键. 因此, 我们只需要在vimrc中添加修改设置即可, 这里我将向后跳转块修改区设置为"ii"键触发, 跳转到之前的块修改区设置为"II"键触发(vim在插入模式下可以使用双单词做为快捷键的, 这也是vim最为神奇的功能之一哦.它让我们的快捷键定制能力变得更加灵活好用.):

    "UltiSnips插件设置
    let g:UltiSnipsJumpForwardTrigger="ii"
    let g:UltiSnipsJumpBackwardTrigger="II"

    到这里, 你将发现tab键变得相当好用, 当你写一个触发词时,如果UltiSnips中映射了这个词作为块补全触发从词, 将会优先触发块补全功能. 在块补全功能触发之后通过ii和II键来向前和向后跳转块可编辑区.此时tab可以正常实现就近补全功能.  如果触发词在UltiSnips的映射文件(如果你用vunder管理插件,该文件存在与~/.vim/vunder/UltiSnips/UltiSnips目录下, 你应该学习UltiSnips的用法, 并且经常到这里来定制直接的代码块补全)中不存在当前触发词的映射, 那么supertab将会继续触发就近补全. 这中共用tab的方式最大限度的提高了补全的便捷性. 唯一需要的付出的代价是你需要记住UltiSnips中定义的一些代码块补全触发词, 在tab补全的时候注意多写或少些一个单词来避免在需要就近补全的时候触发了块补全功能.

      

  • 相关阅读:
    acm课程练习2--1002
    acm课程练习2--1001
    SDAU课程练习--problemQ(1016)
    SDAU课程练习--problemG(1006)
    SDAU课程练习--problemO(1014)
    SDAU课程练习--problemB(1001)
    SDAU课程练习--problemA(1000)
    SDAU课程练习--problemC
    SDAU课程练习--problemE
    不安全函数(转)
  • 原文地址:https://www.cnblogs.com/pangchol/p/3471941.html
Copyright © 2020-2023  润新知