Is there a way to use :lvimgrep and to limit the results to one match per file, so that each file with a match only appears once in the location list?

1 Answer 1


According to the help you can use :1lvimgrep pattern to have only a single match per file added to the quickfix list. I have never tried that however and so I am not sure how well that works.

Update Okay, I have apparently misunderstood the problem as mentioned in the comments.

So there does not seem to exist an easy way to do what you want. That leaves us with those alternatives:

  • Use an external grep like tool

grep supports the -l flag, which makes it stop on the first match per file. Same is true for git-grep. This has the additional advantage that it might be a lot faster and you can use standard perl like regexps as this is often a complaint for many users about the leaning toothpick syndrom. And you can use it with a custom :help 'grepprg' so the result will be available in the quickfixlist. However this might be a problem, if you depend on vim like regular expressions, as this will become impossible.

  • Filter the vimgrep result

Use the getloclist() or getqflist() functions to post-process the result from lvimgrep and only get a single match per file. However, this has the disadvantage, that vimgrep still processes the complete file (so has no performance benefit if it would stop on the first match) and you will also add additional costs to filter the result.

Something like this should work:

function! FilterLocList()
  let a=getloclist(0)
  let file={}
  let result=[]
  for entry in a
    if !has_key(file, entry.bufnr)
      call add(result, entry)
      let file[entry.bufnr]=1
  if !empty(result)
    call setloclist(0, result, 'r')

com! -nargs=0 FilterLocList :call FilterLocList()

So after doing a :lvimgrep command, you call :FilterLocList and the location list for the current window will only contain the first match.

  • Make use of :lnf and :lpf commands

You can use the :help :lnf and :help :lpf

You simply do not care, how many entries the location list has and you jump directly to the next file in the location list using the :lnf command. You can jump to the previous file using the :lpf command. Similar commands exist for the quickfix list (:cnf and :cpf) - Use a custom command

Another alternative would be to create a custom command, that does what you want. Something like this:

function! LVimgrepOnce(pattern, argspat)
  let args=glob(a:argspat, 1, 1)
  if empty(args)
    echo "No matching files found"
  " clear location list
  lexpr []
  for file in args
      exe "1lvimgrepadd /". a:pattern. '/j' file
  let w:quickfix_title='vimgrep '. a:pattern. ' '. a:argspat

:com! -nargs=+ Lvimgrep :call LVimgrepOnce(<f-args>)

This will call a simple :1vimgrepadd command for each file specified and gather the result in the quickfix list (or more specifically in the location list).

  • From the help: When a number is put before the command this is used as the maximum number of matches to find. It gives only the first match of all matches in all files, not the first match in each file. Just tested it.
    – Andreas
    Feb 13, 2018 at 13:26
  • ah sorry, I totally misunderstood that then. You could probably script around that like this: :1lvimgrep /pattern/ file1 | 1lvimgrep /pattern/ file2 | ... (do that for all files) Feb 13, 2018 at 14:03
  • There are roughly 200 files I want to make the search in, all in the same directory. Could this be easily scripted? Currently what I do is to cd into the directory and do :lv /pattern/ *, but as mentioned I want to avoid multiple matches from the same file.
    – Andreas
    Feb 13, 2018 at 20:22
  • @Andreas mentioned workarounds and scripts Feb 14, 2018 at 11:52
  • Many thanks for the answer. I used the filter alternative so it solves my problem. It would be much quicker to use the external grep though. However, when I set grepprg=grep\ -lHn and then do :lgrep pattern files, the results polulate the location list but I cannot jump from the list to the hits in files.
    – Andreas
    Feb 16, 2018 at 13:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.