I have the file tmp.git.log in my $HOME:

commit 07f5bbb6a3a112f7b601d6cd1f72ec3f20112920
Author: me
Date:   2024 

    some

    comit

    messages



diff --git path/file.end
index e969a7691b..0bf58bcb94 100644
--- removed
+++ added
@@ -1,7 +1,7 @@
  
    
      
-      removed
+      added
       :key="index"
       label
       :color="color"
@@ -10,11 +10,13 @@
       :class="fontWeight"

etc.

I wanted to fill my quickfix list with the beginnings and endings of the changes, marked here by @@ at the line start. I tried to execute

:vimgrep /^@@ ~/tmp.git.log

And Nvim answered with

E682 invalid search pattern or separator

What is wrong with the above vimgrep command?

Also: Can I :vimgrep in buffers which aren't written, e.g. non-files?

I want to :read !git show <git-hash> into nvim to see changes done in my repo by certain commits, I don't need the files persisted. I know, there are plugins, but I want to understand what vanilla nvim can do here.

I want to read the result of git show <git-gash> within Neovim, and populate the quickfix list with vimgrep.

Vimgrep fails to accept my search

:vimgrep /^@@ ~/tmp.git.log

with E682.

How do I accomplish to fill my quickfix list with the added/removed file chunk positions for faster navigation?

Ideally without saving the git show result to a temporary file first.

1

There are 1 best solutions below

0
On BEST ANSWER
:vimgrep /^@@ ~/tmp.git.log

What is wrong with the above vimgrep command?

You must enclose your pattern with / and / (or a pair of another character), as per :help :vimgrep:

:vimgrep /^@@/ ~/tmp.git.log
             ^ you forgot this slash

Also: Can I :vimgrep in buffers which aren't written, e.g. non-files?

No. Both :grep and :vimgrep can only be used to search through files.

The mechanisms for searching in a file and searching in a buffer can't really be identical because the two tasks sit at different abstraction levels. You have very old and simple commands like :vimgrep for the former but, sadly, only low-level stuff for the latter.

I came up with this monstrous one-liner years ago because I wanted to use the quickfix for buffer-level search but it only works for named buffers. I guess one could use the same basic logic (filter the lines from current buffer) but use :help setqflist()/:help setloclist() instead.

--- EDIT ---

FWIW, I just wrote this more versatile version of the linked snippet that makes use of the location list:

function! Global(pat, bang) range
    " reverse operation if we have a bang
    let operator = a:bang == '!' ? '!~' : '=~'

    " padding is needed if range starts after line 1
    let padding_top = a:firstline > 1 ? a:firstline - 1 : 0

    " one call is better than many
    let bufnr = bufnr()

    " build the range for a clean quickfix title
    let qf_title_range = a:firstline == 1 && a:lastline == line('$') ? '%' : a:firstline .. ',' .. a:lastline
    
    " 1. get all lines in range into list
    " 2. transform each item into syntactically valid qf item
    " 3. keep items that match/don't match given pattern
    let qf_list = getline(a:firstline, a:lastline)
                \ ->map({ idx, val -> { 'bufnr': bufnr, 'lnum': idx + 1 + padding_top, 'text': val, 'valid': 1 } })
                \ ->filter({ idx, val -> eval("val.text " .. operator .. "'.*' . a:pat . '.*'") })

    " if possible…
    " 1. set location list with list of items and proper title
    " 2. open location list
    " 3. jump to first location
    if qf_list->empty() == 0
        call setloclist(win_getid(), [], ' ', { 'title': ':' .. qf_title_range .. 'Global ' .. a:pat, 'items': qf_list })
        lwindow
        lfirst
    endif
endfunction

" custom Ex command :Global calls custom function Global()
command! -bang -nargs=1 -range=% Global <line1>,<line2>call Global(<q-args>, expand('<bang>'))

which seems to work fine with everything I threw at it, named buffer or not.

Usage, populate location list with matching lines in given range:

:Global @@
:%Global foo
:3,21Global bar

Usage, populate location list with non-matching lines in given range:

:Global! @@
:%Global! foo
:3,21Global! bar