Example:
search:
/lastword\s*\n\zs\(\s*\n\)\{6}\ze\s*startword
This search searches 6 empty lines between a line ending with "lastword" and a line starting with "startword"
I would like to catch the linenumbers of the empty lines matching this search.
Is there a way to do this in vim?
You can use :g
and :number
(or :#
for short) to print out the lines with line numbers.
:g/lastword\s*\n\zs\(\s*\n\)\{6}\ze\s*startword/#
To capture this content you have to use :redir
to redirect the output to somewhere else. In this case below we redirect it to the unamed register (@"
)
:redir @"|execute 'g/pattern/#'|redir END
Note: Must use :execute
with :g
otherwise redir END
will be executed on each matching line with the :g
command.
Now as it is this is going to print via :#
the starting line which is not what we want (we want the empty lines between foo
and bar
). We can use a range with the :#
command to accomplish this.
:redir @"|execute 'g/foo\_.*bar/+,/bar/-#'|redir END
The range is now +,/bar/-
which translate to start the next line (+
) and the search for bar
(/bar/
) then subtract one line (-
). We can probably simplify this some as we know the number of empty lines should be 6.
:redir @"|execute 'g/foo\_.*bar/+#6'|redir END
We can take this further by putting the content into a new buffer and remove the extra lines.
:redir @"|exe 'g/pattern/+#6'|redir END|new|pu|%s/\d\+\zs.*//|%le|g/^$/d
There is a lot going on here, but the idea is we capture the output, open a new buffer, paste the content, and then clean up the output.
Alternatively awk might make this a bit easier. Run the following on the current Vim buffer:
:%!awk '/lastword\s*$/,/^\s*startword/ { if($0 ~ /^\s*$/) { print NR} }'
For more help see:
:h :g
:h :redir
:h :exe
:h :range
:h :new
:h :pu
:h /\zs
:h :le
:h :d