1

I would like to put in the quickfix the files not matching a pattern. That it, these files don't have any line matching the search pattern.

I know that for finding files whose content match a pattern I may use the :vimgrep command, that alongside with :cnext or :cnf makes the possibility of navigate through the matches.

  • I think you could do it with some combination of :vglobal and setqflist() – D. Ben Knoble Dec 30 '19 at 17:35
2

One way to do it would be to:

  1. use :args to populate the arglist with all the files in which you're interested
  2. use search() to check whether your pattern can be found in each file, and if it does not, add its path to a list
  3. give that list to getqflist() to transform it into a quickfix list, and invoke setqflist() to add it onto the stack of quickfix lists

For example, if you're looking for all the files matching the glob /etc/*.conf, but not containing the pattern network, you could execute these 3 lines:

args /etc/*.conf
let lines = [] | sil argdo if ! search('network', 'nW') | let lines += [expand('%:p')] | endif
call setqflist(getqflist({'lines': lines, 'efm': '%f'}).items) | cw

To make this easier, you could wrap the code inside a function and call it from a custom Ex command:

com -nargs=* Vimgrepv call s:vimgrepv(<q-args>)
fu s:vimgrepv(args) abort
    let usage =<< trim END
        Vimgrepv /some pattern/ file ...
        Vimgrepv pattern file ...
    END
    let pat = '^\(\i\@!.\)\(.\{-}\)\1\s\+\(.*\)'
    let g = [2, 3]
    if match(a:args, pat) == -1
        let pat = '\(\S\+\)\s\+\(.*\)'
        let g = [1, 2]
    endif
    try
        let [pat, files] = matchlist(a:args, pat)[g[0]:g[1]]
    catch /^Vim\%((\a\+)\)\=:E688:/
        echo join(usage, "\n") | return
    endtry
    arglocal | let curbuf = bufnr('%')
    exe 'args '..files
    let lines = []
    sil argdo if ! search(pat, 'nW') | let lines += [expand('%:p')] | endif
    argglobal | exe 'b '..curbuf
    call setqflist(getqflist({'lines': lines, 'efm': '%f'}).items) | cw
    call setqflist([], 'a', {'title': printf('files in %s NOT containing %s', files, pat)})
endfu

It installs the custom command Vimgrepv, which you could use like this:

:Vimgrepv /some pattern/ file ...

or like this:

:Vimgrepv pattern file ...

For more info, see:

:h :args
:h :argdo
:h search()
:h getqflist()
:h setqflist()
| improve this answer | |
  • Nice answer. Since answers are intended to be informative and precise, I prefer to see code use the full forms of all commands and functions (ie no abbreviations). I think they have their place interactively, but in maintainable code less-so. – D. Ben Knoble Dec 30 '19 at 23:42
  • Always learn something from your answer, didn't know the arglocal trick, +1. – dedowsdi Dec 31 '19 at 0:07
1

I believe using an external tool is much easier in this case.

Let's suppose your set grepprg=/usr/bin/grep\ -n is GNU grep (i.e. it supports grep -L).

Then

:set gfm=%f
:silent grep -L 'pattern' files
:set gfm&
:copen

does it. See also :h :grep, :h 'grepprg' and :h 'grepformat'.

If you do this often, you may want to pack it into a user-command.

| 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.