1

这是我关于在 Vim 中使用多行正则表达式的问题的后续。

一个简单的解释:我有一些用#tags空行标记和分隔的文本块。我想过滤掉所有包含特定标签的块。我在这里得到了正则表达式的帮助(谢谢!),所以我构建了以下命令:

command -nargs=1 TagSearch g/^\(.\+\n\)\{-}.*#<args>.*/y a | vnew | put a | %s/^#.*<args>.*\n/&\r 

因此,做一个:TagSearch tag应该:

  1. 搜索#tag.
  2. 将所有相应的文本块粘贴到新的垂直缓冲区中。
  3. 在新缓冲区中的文本块之间添加一个空行。

Q1:当我分别执行每个步骤时,一切正常。但是多命令仅将第一个匹配的文本块粘贴到新缓冲区中。为什么?

Q2:如何让命令接受多个参数(如果我想#tags一次搜索多个)?谢谢!

4

2 回答 2

1

我在这方面玩得很开心,在这个过程中学到了很多东西!看起来这里有一些问题。

这是我如何使其工作的方法,尽管由于 vim 有很多方法,因此可能有一种更整洁的方法。

g 命令的格式为 g/pattern/command。我认为发生的事情是你原来的形式,| 新 | 放一个| %s... 该命令的一部分是使用 g 命令逐行执行的,而不是作为 TagSearch 命令的一部分执行一次。我将 g 命令更改为“执行”而不是解决问题 - 我很想知道是否有一种方法可以在不使用执行的情况下指定管道适用的内容,我无法让它工作(括号不起作用例如)。这就是为什么你只得到第一行的原因。这给了我们(修正你的 '%s' 命令中的错字):

command! -nargs=1 TagSearch execute 'g/^\(.\+\n\)\{-}.*#<args>.*/y a' | vnew | put a | %s/^.*#<args>.*\n/&\r

不过,这似乎扭转了问题,我们现在只得到新缓冲区中的最后一行。g 命令的另一个问题是,当您执行 /ya 时,它每次都会覆盖 a 寄存器。有一种方法可以让 vim 使用大写的寄存器名称 (/y A) 代替附加到寄存器(参见 :help quotea)。这样做我们需要先使用 let 将寄存器初始化为空白。这给了我们这个:

command! -nargs=1 TagSearch let @a='' | execute 'g/^\(.\+\n\)\{-}.*#<args>.*/y A' | vnew | put a | %s/^.*#<args>.*\n/&\r

最后,为了让它使用多个标签执行,我只是摆弄<args>了一下(调用 TagSearch tag1 tag2,args 实际上是字符串'tag1 tag2')以使其适合正则表达式,如下所示:

command! -nargs=* TagSearch let @a='' | execute 'g/^\(.\+\n\)\{-}.*#\(' . substitute('<args>', ' ', '\\|', 'g') . '\).*/y A' | vnew | put a | execute '%s/^.*#\(' . substitute('<args>', ' ', '\\|', 'g') . '\).*\n/&\r'

如果您为此添加更多功能,您可能想尝试使用一些 vimscript 函数或其他东西,否则可能很难维护!您将能够将文本块抓取到漂亮的列表中,并可能更轻松地处理它们,而不必像实际打字一样做所有事情。查看 :help 功能,了解可用的东西(尽管其他地方的 vimscript 帮助可能有更好的起点)。

于 2012-05-15T09:12:57.380 回答
1

可以使用以下实现。

command! -nargs=* -bar TagSearch call CollectParagraphs([<f-args>])

function! CollectParagraphs(tags) range
    let tags = len(a:tags) > 0 ? a:tags : [expand('<cword>')]
    let pats = map(copy(tags), '"\\.\\*#" . escape(v:val, "\\")')

    let v = winsaveview()
    let [sr, @/; lines] = [@/, '\V' . join(pats, '\&')]
    g//call extend(lines, getline(search('\n\n\zs', 'bnW'), line("'}")))
    let @/ = sr
    call winrestview(v)

    exe 'vnew' escape(join(tags), ' %#|\')
    set buftype=nofile bufhidden=hide noswapfile
    call setline(1, lines)
endfunction
于 2012-05-15T11:43:55.687 回答