Reputation: 22685
I was wondering if there is some way in Vim to navigate through search results by block, where a block is a span of lines, each having an occurrence of the search pattern.
Say, the contents of a buffer is as follows:
Line 1: Pattern
Line 2: Pattern
Line 3: Pattern
Line 4:
Line 5: Pattern
---- No Pattern here ----
Line n+1: Pattern
Line n+2:
Line n+3:
Line n+4: Pattern
Line n+5: Pattern
Then, the command should navigate from Line 1, to Line 5, Line n+1, Line n+4, and so on. It should ignore matches happening in consecutive lines (i.e., within a block) and jump to the next block.
Upvotes: 4
Views: 939
Reputation: 28934
One can use two different strategies to translate your definition of a block into a Vim regexp. Firstly, it can be designed to match the first line of a block, i.e., the line that does match the pattern but is not preceded by a line matching that same pattern.
/\%(\1\n\)\@<!\(pattern\)
Secondly, one can search for several subsequent lines, all matching the pattern, but, in order to skip a whole block to find the next occurrence, the cursor is put at the end of the block on matching.
/\(pattern\)\%(\n\1\)*/e
Personally, I prefer the former solution.
Upvotes: 0
Reputation: 392893
You could you folding for that.
To fold blocks of contiguous lines containing the last searched pattern:
:se fdm=expr foldenable foldexpr=getline(v:lnum)=~@/
Now you can use regular fold navigation
zj move one fold down, zk move one fold up
zcdd yank the current block into the default register
Upvotes: 1
Reputation: 4416
Right off hand, I can't remember if vim has the capability of doing multi-line matching. If it does, you can specify newlines in the search pattern. In Perl, this would look something like this (I've whipped this out quickly without looking up the multi line regex, so I may have some of the syntax wrong, but it's close enough to act as an example).
/(pattern)(\n(pattern)*){4}/m
This will look for 'pattern', then 4 lines which may or may not contain 'pattern'.
The problem with this is that if you have two blocks which overlap, I think that this search will get confused.
The other thing that you could do is define a vim macro which will search, then move down by 5 lines.
A macro is defined using +q+, then executed using +@+. So for your 'search for pattern block' example, using 't' as , you'd do something like this:
<esc>qt # start macro 't'
/pattern # search for 'pattern'
5j # move down 5 lines
<esc>q # end macro
Then, you'd start at the top of your document and repeatedly press '@t'
Upvotes: 0