phi_st
phi_st

Reputation: 55

Vimgrep before any empty line

I have a lot of files which starts with some tags I defined.

Example:

=Title
@context
!todo
#topic
#subject
#etc

And some text (notice the blank line just before this text).

Foo
Bar

I'd like to write a Vim search command (with vimgrep) to match something before an empty line.

How do I grep only in the lines before the first blank line? Will it make quicker grep action? Please, no need to mention :grep and binary like Ag - silver search.

I know \_.* to match everything including EOL. I know the negation [^foo]. I succeed to match everything but empty lines with /[^^$]. But I didn't manage to compose my :vimgrep command. Thank you for your help!

Upvotes: 2

Views: 627

Answers (3)

romainl
romainl

Reputation: 196476

AFAIK the most you can do with :vimgrep is use the \%<XXl atom to search below a specific line number:

:vim /\%<20lfunction/ *.vim

That command will find all instances of function above line 20 in the given files.

See :help \%l.

Upvotes: 0

If you want a general solution which works for any content of file let me tell you that AFAK, you can't with that form of text. You may ask why ?


  • Explanation:


vimgrep requires a pattern argument to do the search line by line which behaves exactly as the :global cmd.

For your case we need to get the first part preceding the first blank line. (It can be extended to: Get the first non blank text)

Let's call:

  • A :Every block of text not containing any single blank line inside

  • x :Blank lines

With these only 5 forms of content file you can get the first A block with vimgrep(case 2,4,5 are obvious):

1 | 2 | 3 | 4 | 5


x | x | A | x | A

A | A | x | A | x

x | x | A

A |

Looking to your file, it is having this form:

A

x

A

x

A

the middle block causes a problem that's why you cannot split the first A unless you delimit it by some known UNIQUE text.


So the only solution that I can come up for the only 5 cases is:

:vimgrep /\_.\{-}\(\(\n\s*\n\)\+\)\@=/ %

Upvotes: 0

melpomene
melpomene

Reputation: 85757

[...] always matches a single character. [^^$] matches a character that is not ^ or $. This is not what you want.


One of the things you can do is:

/\%^\%(.\+\n\)\{-}.\{-}\zsfoo/

This matches

  • \%^ - the beginning of the file
  • \%( \) - a non-capturing group
  • \{-} - ... repeated 0 or more times (as few as possible)
  • .\+ - 1 or more non-newline characters
  • \n - a newline
  • .\{-} - 0 or more non-newline characters (as few as possible)
  • \zs - the official start of the match

This will find the first occurrence of foo, starting from the beginning of the file, searching only non-empty lines. But that's all it does: You can't use it to find multiple matches.


Alternatively:

/\%(^\n\_.*\)\@<!foo/
  • \%( \) - a non-capturing group
  • \@<! - not-preceded-by modifier
  • ^ - beginning of line
  • \n - newline
  • \_.* - 0 or more of any character

This matches every occurrence of foo that is not preceded anywhere by an empty line (i.e. a beginning-of-line / newline combo).

Upvotes: -1

Related Questions