这是关于using multi-line regex in Vim的问题的后续跟踪。
快速解释:我的文本块标有#tags
,并用空行分隔。我想过滤掉包含特定标签的所有块。我在这里得到了正则表达式的帮助(谢谢!),所以我构造了以下命令:
command -nargs=1 TagSearch g/^\(.\+\n\)\{-}.*#<args>.*/y a | vnew | put a | %s/^#.*<args>.*\n/&\r
因此,做一个:TagSearch tag
应该:
#tag
,Q1 :当我单独执行每个步骤时,一切正常。但是多命令仅将第一个匹配的文本块粘贴到新缓冲区中。为什么呢?
Q2 :如何让命令接受多个参数(如果我想一次搜索多个#tags
)?谢谢!
答案 0 :(得分:1)
我有一个很好的老玩法,并在这个过程中学到了很多东西!看起来这里有一些问题。
以下是我如何使其工作,尽管由于vim有很多方法,但某种方式可能会更加整洁。
g命令的格式为g / pattern / command。我认为发生的事情是你的原始形式,| vnew |放一个| %s ...命令的一部分是使用g命令逐行执行的,而不是TagSearch命令的一部分。我将g命令更改为'执行'而不是解决问题 - 我有兴趣知道是否有一种方法来指定管道适用于什么而不使用执行,我无法使其工作(括号不起作用例如)。这就是为什么你只获得第一线的原因。这给了我们(修复'%s'命令中的拼写错误):
command! -nargs=1 TagSearch execute 'g/^\(.\+\n\)\{-}.*#<args>.*/y a' | vnew | put a | %s/^.*#<args>.*\n/&\r
这似乎可以解决问题,现在我们只得到新缓冲区中的最后一行。 g命令的另一个问题是,当你执行/ y a时,它每次都会覆盖一个寄存器。有一种方法可以使用大写的寄存器名称(/ y A)将vim附加到寄存器(请参阅: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函数或其他东西,否则可能会很难维护!您可以将文本块抓取到漂亮的列表中,并且可以更轻松地处理它们,而不必像在实际键入时那样执行所有操作。看看:可用的东西的帮助功能(虽然在其他地方的vimscript帮助中可能有一个更好的起点)。
答案 1 :(得分: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