0

The context

Given a {pattern}, I can list the ocurrences of {pattern} in all files from a {directory}, in the quickfix window with the following command

:chdir {directory}
:vimgrep /{pattern}/ **/*
:cwindow

The question

Given a set of patterns, I want to list the ocurrences of these patterns in those files that contain all the patterns of the set of patterns in the quickfix window.

I really need to list the ocurrences in the quickfix window because thus I can jump exactly to position of the ocurrences.

In other words, it would be like executing vimgrep for each pattern but instead of searching through all files just limit the search to the files present in the quickfix window. Recall that the fact that they were in the quickfix window shows that they contained the previous pattern which accomplishes the same.

Additional context

The current workaround

I will explain how I would do this by using grep and vim as a pager. The problem with this approach is

  • it doesn't fill the quickfix window which implies that I have to repeteadly press n and N instead of having the ocurrences listed in an order manner in the quickfix window.
  • the output only shows the name of the files that contain the set of patterns but doesn't show in which line the pattern occurs.

Consider the set of patterns \<main\> and \<c and the following directoryj

$ mkdir cpp && echo main.cpp > cpp/main.cpp
$ mkdir c && echo main.c > c/main.c
$ mkdir py && echo main.py > py/main.py

Executing the following command will display the name of the files that contain all the patterns in a buffer which implies that I can use <c-w>f to jump to those files.

$ find -type f | xargs grep -l '\<main\>' | xargs grep -l '\<c' | vim -

This would be the result in the vim buffer. Note that main.py file is not present because it didn't contain the \<c pattern. The set of patterns in this scenario were \<main\> and \<c.

1| ./cpp/main.cpp
2| ./c/main.c
  • 1
    Is your question « given a quickfix list, search every file in it with a different pattern to fill a quickfix list »? – D. Ben Knoble May 27 at 12:29
  • No, given a set of patterns $s = {p_1, p_2, \ldots, p_n}$. List ocurrences of $p_1, p_2, \ldots, p_n$ in those files whose content contains $p_1$ and $p_2$ and $\ldots$ and $p_n$. That is, if file contains $p_1$ but not $p_2$, then ocurrences of $p_1$ in that specific file must not be shown in the quickfix list. – gfe May 27 at 15:07
0

NOTE I just realized that this still won't accomplish what the OP is after. My function would give entries from files containing any of the multiple patterns, while OP wants entries from files containing all of the patterns. Concats (\&) might help, but I'm not sure.


If you don't mind leaving the original quickfix list prepended to the new one, you want to be able to do

cfdo vimgrepadd /pattern/ %

But because of the command line processing % too early, it won't actually search each file (and I haven't yet found a way around this).

However, you can use the following function (which is similar to an unrolled cfdo):

function! AddQuickfix(pattern) abort
  const files = getqflist()->map({ _, item -> bufname(item.bufnr) })
  " clear quickfix
  cexpr []
  for file in files
    execute 'vimgrepadd' a:pattern file
  endfor
endfunction

Then OP can do

  1. :vimgrep /pattern/ **/*
  2. :call AddQuickfix('pattern')

Notes

  1. If you want to keep the original quickfix at the top of the new ones, remove the :cexpr [] line.
  2. You can improve the ergonomics with :command -nargs=1 QfAdd call AddQuickix(<q-args>); in both versions, any form of pattern that :vimgrep accepts is allowed, but the function argument must be quoted.
  3. If you want to add matches for multiple patterns, you can use branches \| or concats \&.
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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