史上巨坑: vim的"set foldmethod=syntax"设置竟然是导致ctrl+p(ctrl+n)补全在文件稍大时光标位于中间位置补全效率变慢的元凶!

时间:2021-05-03 06:08:50

  最近我的vim又让我闹心了. 问题出现在supertab的补全速度上, 有时候按下tab键半天才弹出补全列表, 即便是弹出了列表在列表上下移动也变得的相当缓慢, 这让我的很是蛋疼. 在完全无法接受这个问题之后决定再一次踏上折腾vim之路(已经没有折腾vim好长一段时间了). 之前有一次vim出现tab补全的卡死问题折腾了好几个小时才把原因找到, 这次这个更加诡异, 没有折腾之前就觉得一定不简单. 后来果然应验, 这个问题足足花掉了我一整天的时间!

  首先是缩小问题的范围, supertab在我这里是为了实现就近补全而用的, 也就是指supertab这里充当了ctrl+p的映射的功能. 这个推测很快得到结果是问题和supertab本身没有关系, 因为即在vunder中将supertab关闭掉.ctrl+p补全依然会出现同样的问题. 接着需要锁定问题出现的场合, 经过多次测试,发现ctrl+p补全在文件末尾总是非常的快速, 即便文件很大也是如此, 但如果将光标移到文件的中间位置, 这个时候再触发ctrl+p补全响应就变得龟速, 而且在文件中间不同的位置往往会出现可以感觉到的速度差别. 到这里其实还是没有任何线索, 反而让问题变得更加诡异. 想了半天无果, 开始怀疑是否是别的插件产生的问题, 使用vunder便捷的批量注释插件来慢慢的缩小范围,这样做高效而准确, 我觉得这是vunder带来最大的好处之一. 经过插件的禁用测试, 最终发现当关闭indentLine这个插件的时候补全速度得到提升. 这时我很自信的认为是indentLine带来的问题. 第一反应是放弃indentLine用类似的插件代替, 百度了半天发现只有一个indent-guide插件可以实现indentLine的缩进线, 可惜的是indent-guide使用的是高亮来实现缩进线, 以前就试过,因为不习惯它那很粗的缩进线(最细只能降低到一个英文字符宽度)而放弃, 更加要命的是我现在使用了externtab设置来让空格直接取代tab, 这样一来indent-guide直接完全无法使用了.

   没办法放弃indentLine只能通过修改indentLine的源码来砰砰运气了. 找到源码打开一看, 我来个去. 整个插件源码加起来不到100行, 这么精简的插件怎么会对vim有这么大的影响呢? 对着这个百来行vim脚本修改了半天发现indentLine是通过vim7.3才引入的conceal特性来实现缩进线高亮的. indentLine也只是简单的添加了一个Conceal高亮规则. 只要这个Conceal高亮规则一打开ctrl+p在文件中间位置补全就变得很慢!难道这是vim本身的一个漏洞???7.3都发布好几年了, 没道理这个漏洞网路上没有记录阿, 重点是我现在已经将vim升级到了最新的7.4版本这个版本作者不是说做1000多项的修改和修改, 怎么可能这么大的效率问题没有堵上? 胡思乱想了半天虽然觉得奇怪但也没有其他办法, 最终还是将indentLine关闭放弃使用Conceal特性.

  之后的几个小时我在没有indentLine提供的缩进线带来的各种不习惯下使用vim编码.很快新的问题被察觉, 虽然在没有了Conceal之后ctrl+p补全的速度有明显的提升, 但在代码中间位置的补全速度还是和文件尾有所差别. 实际上到这里我反而觉得一个好兆头, 因为这里证明了真正的原因可能不是Conceal带来的. 也就是指indentLine可能会保留下来.

  再次寻找原因的第一步直接来个狠的, 将.vimrc移动到别的地方, 直接禁止所有配置, 打开vim, 定位到文件中间位置发现ctrl+p的反应速到完全没有问题. 也就是指问题不在插件而是vimrc中其他地方的配置中. 现在的vimrc中有效的配置长度有500行以上. 在这么多配置的定位问题以前就干过, 那真的是利用注释来二分查找阿! 实在不想这么大动干戈, 本能的再次救助网络, 之前在百度上用中文搜索基本上没有资料, 这次决定找找谷歌大大, 搜索了一会最后通过"vim ctrl+n   slow"做关键此找到到了下面这个链接

http://*.com/questions/2916887/setting-syntax-on-in-vim-with-large-c-file-makes-complete-very-slow

还好自己的英文能勉强看外网(注意这个网址是外网, 你懂的), 这里的作者说大文件的ctrl+n很慢是因为:set syntax on :set foldmethod=syntax这两句配置导致, 后来又说的它发现自己的vim是测试版, 所以不知道是否应该保留这个问题的结论以供后来人参考. 在贴子的回复中最后作者还提及导致ctrl+n变慢的根本原因是:set foldmethod=syntax这个配置.  这个配置我的确是有的, 在很久以前就加上去了, 主要是设置vim该怎样折叠. 折叠风格怎么会和ctrl+n/ctrl+p的效率产生关系呢? 真的是打死也想不到阿. 报着试试看的心理将自己vimrc中这一行注释掉. 我来个擦!...真的见证奇迹的时刻阿... ctrl+p那犀利的速度就这么回来了. 打开indentLine试试, 完全没有问题! oooh, mygod! 巨坑阿有木有, 折叠竟然和补全真的有关系阿有木有!

  到这里一切就水落石出了,虽然花掉了我一整天的时间, 不过结果还是值得庆幸的. 不仅解决了supertab的效率问题, 还保住了indentLine插件.

为了让vim的折叠功能可以继续使用, 这里的将flodmethod设置indent, 即:

set foldmethod=indent