【问题标题】:How to prevent a Vim Ex command from taking too much time?如何防止 Vim Ex 命令花费太多时间?
【发布时间】: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>

但是,在我有限的测试中(我只在几千行的单个文件中搜索thefoobar 等简单模式),似乎while 循环通常比s///gen 慢.有时只是一点点,有时更多(例如 8 倍)。

在一般情况下,或至少在这种特定情况下,如何防止 Vim Ex 命令花费太多时间?

【问题讨论】:

    标签: vim


    【解决方案1】:

    您已经概述了显而易见的方法:

    • search() 这样的一些低级函数采用{timeout} 值,以避免它们阻塞用户操作太久。不幸的是,它不是 100% 等效于 :%s///gn,因此您需要额外的代码(此处:Vimscript 中的较慢循环)。

    • 您可以实施启发式方法来估计调用是否会很慢,然后不要这样做。这永远不会是完美的,需要付出很多努力,但也许已经足够了。

    推荐

    这些附加(搜索摘要)信息对用户有多重要?通常,可能不是必需的,但在某些情况下,用户可能愿意为此多等几秒钟。

    我会确保主函数(这里:跳转到下一个匹配项的n 命令)将始终(首先)执行,并且可以通过按&lt;C-C&gt;(可能多次,打破:%s,然后退出你的功能)。基本上,这意味着:catching Vim:Interrupt,见:help catch-interrupt

    我的方法

    我写了SearchPosition plugin 来显示这些摘要信息按需。它不与n 集成,并且始终必须单独触发。 (默认映射是&lt;A-n&gt;,因此它可以与n 命令一起快速触发。)这增加了一个额外的映射,并将责任推给了用户,但至少对我来说,我很少需要摘要,并不总是与跳转到匹配项一起使用。

    【讨论】:

      猜你喜欢
      • 2017-06-01
      • 2016-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多