This is a follow-up to my question about using multi-line regex in Vim.
A quick explanation: I have blocks of text tagged with #tags
and separated by a blank line. I want to filter out all blocks that include a specific tag. I was helped with regex here (thanks!), so I constructed the following command:
command -nargs=1 TagSearch g/^\(.\+\n\)\{-}.*#<args>.*/y a | vnew | put a | %s/^#.*<args>.*\n/&\r
Hence, doing a :TagSearch tag
should:
- Search for the
#tag
, - paste all corresponding Text Blocks into a new vertical buffer,
- Add a blank line between the Text Blocks in the new buffer.
Q1: When I do each step separately, everything works. But the multi-command only pastes the first matching text block into the new buffer. Why?
Q2: How could I make the command accept multiple arguments (in case I want to search for many #tags
at a time)? Thanks!
I had a good old play around with this and learnt quite a bit in the process! Looks like there are a few problems going on here.
Here's how I worked through to get it working, although as there are so many approaches with vim there is probably a tidier way somehow.
The g command is of the form g/pattern/command. What I think was happening was in your original form, the | vnew | put a | %s... part of the command was being executed linewise with the g command, rather than once as part of the TagSearch command. I changed the g command to being 'executed' instead which solves the problem - I'd be interested to know if there is a way to specify what the pipe applies to without using execute, I couldnt get it working (brackets don't work for example). This would have been why you were only getting the first line. This gives us (fixing a typo in your '%s' command):
This seems to reverse the problem though, and we now only get the last line in the new buffer. The other problem with the g command, is that when you do /y a, it overwrites the a register each time. There is a way to get vim to append to a register instead, using the capitalized register name (/y A) (see :help quotea). Doing it this way we need to initialize the register to blank first, using let. That gives us this:
Finally to get it to execture with multiple tags, I just fiddled with the
<args>
a bit (calling TagSearch tag1 tag2, args would literally be the string 'tag1 tag2') to get it to fit in the regex as below:If you add any more features to this you might want to try playing around with a little vimscript function or something instead, otherwise it might get pretty hard to maintain! You'd be able to grab your text blocks into nice lists and potentially process them a bit more easily rather than having to do everything as if you were actually typing. Take a look at :help functions for things that are available (although there may be a better starting point in the help for vimscript somewhere else).
One can use the following implementation.