【发布时间】:2017-07-27 17:25:59
【问题描述】:
我有一个 Vim 映射,它覆盖了默认的n 命令,将光标移动到下一个匹配项上,同时显示搜索寄存器的匹配项数,以及光标下匹配项的索引.
它可以工作,除了当模式变得有点复杂和/或有很多匹配时,脚本可能会花费很多时间(几秒钟)。结果被缓存了,所以在最初的n之后,只要缓冲区没有改变,连续的n不会导致任何减速。
在分析脚本后,我发现到目前为止最耗时的命令是:
let output = execute(a:range.'s///gen')
我在function 中使用它来计算任意范围内的匹配数:
fu! s:matches_in_range(range) abort
let output = execute(a:range.'s///gen')
return str2nr(matchstr(output, '\d\+'))
endfu
为了解决这个问题,我有两个想法,但他们都有问题。
我可以尝试猜测该命令是否会花费太多时间,方法是先计算初始范围的一个小子范围的匹配数,然后再计算其余行。
但大多数匹配可能超出此子范围,因此测试可能无法检测到总体上会花费太多时间。
或者,我可以重构函数,使用while 循环和search() 函数。每次迭代后,我可以测试从开始到现在已经过去了多少时间,并在超过一定限制时取消。另一个好处是第四个可选参数{timeout},它可以传递给search()。如果模式真的太复杂,甚至循环的第一次迭代花费太多时间,这个参数可能会停止函数。下面是它的样子(没有超时参数):
fu! Total_matches() abort
let view = winsaveview()
let total = 0
let matchline = search(@/, 'cW')
let time = reltime()
call cursor(1, 1)
while matchline && total <= 9999
if reltimefloat(reltime(time)) > 1
echo 'too many matches'
call winrestview(view)
return
endif
let total += 1
let matchline = search(@/, 'W')
endwhile
call winrestview(view)
echo @/.' ['.total.']'
endfu
nno cd :call Total_matches()<cr>
但是,在我有限的测试中(我只在几千行的单个文件中搜索the 或foobar 等简单模式),似乎while 循环通常比s///gen 慢.有时只是一点点,有时更多(例如 8 倍)。
在一般情况下,或至少在这种特定情况下,如何防止 Vim Ex 命令花费太多时间?
【问题讨论】:
标签: vim