我有一个Vim映射,它覆盖默认的n
命令,在下一个匹配上移动游标,还可以显示搜索寄存器的匹配数,以及光标下的匹配索引。
它可以工作,只是当模式变得有点复杂和/或有许多匹配时,脚本可能会花费很长的时间(几秒钟)。结果是缓存的,所以在初始n
之后,只要缓冲区没有改变,连续的n
就不会造成任何减速。
在对脚本进行分析之后,我发现到目前为止所用时间最多的命令是:
let output = execute(a:range.'s///gen')
我在函数中使用它来计算任意范围内的匹配数:
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命令占用太多时间?
发布于 2017-07-27 01:25:59
您已经概述了显而易见的方法:
search()
这样的低级函数使用一个{timeout}
值,以避免它们阻塞用户操作太长时间。不幸的是,它并不等同于:%s///gn
,因此您需要额外的代码(此处:Vimscript中的一个较慢的循环)。推荐
这些额外的(搜索摘要)信息对用户来说有多重要?通常情况下,可能并不重要,但在某些情况下,用户可能愿意再等待几秒钟。
我将确保主函数(此处:跳转到下一次匹配的n
命令)始终执行(首先),并且可以通过按<C-C>
(可能多次按:%s
,然后退出函数)来中止摘要生成。基本上,这意味着:catch
ing Vim:Interrupt
,参见:help catch-interrupt
。
我的方法
我已经写了SearchPosition插件,以显示这样的摘要信息的需求。它不与n
集成,必须始终单独触发。(默认映射是<A-n>
,因此它可以与n
命令一起快速触发。)这增加了一个额外的映射,并使用户承担责任,但至少对我来说,我不需要摘要,而不是总是与跳转到匹配。
https://stackoverflow.com/questions/45345774
复制相似问题