18

I have started learning Vim word-search using * and # while the cursor is over the current word. But this search is limited to the current file buffer.

Is there a command or a shortcut to extend this search to:

  1. all opened tabs?
  2. all opened buffers?
2

4 Answers 4

10

It's actually the default behaviour although it may be hard to notice: try * then change to another tab and use n ans N in command mode to jump forward and backward between search hits.

This may make more sense if first you turn highlighting on for all hits:

:set hlsearch
4
  • 1
    +1 only because of hlsearch that I didn't know, and which I would have search for one day or another :-). However, by default I have tried * #, n and N, and it doesn't jump to other file buffers... Jan 3, 2013 at 15:10
  • 1
    No, n and N do not jump buffers (they wrap around), but the term they target is searched for in all tabs; hit * with the highlighting on then cycle thru your tabs -- they will all be highlighted with the same term, so you can use n and N locally there without a fresh search.
    – goldilocks
    Jan 3, 2013 at 15:28
  • 2
    The whole point is NOT to have to cycle through your tabs to find all the matches.
    – Magnus
    Jun 26, 2014 at 18:16
  • 1
    @Magnus While that may be preferable, it's actually not explicitly stated in the question, which asks how to "extend this search to...all buffers" -> it is extended across all buffers. The point of my answer was to make this clear, since it might not be, especially if you do not have hlsearch set.
    – goldilocks
    Jun 26, 2014 at 18:33
6

I don't have an exact solution for your problem, hopefully a better answer than mine will come up. But this is how I tackled the problem of finding a word in all buffers.

" enables to search in all open buffers with :Search <pattern>
command! -nargs=1 Search call setqflist([]) | silent bufdo grepadd! <args> %

nnoremap <left>  :cprev<cr>zvzz
nnoremap <right> :cnext<cr>zvzz

The first line creates a command Search with the search pattern as argument, which writes the results in a quickfix list. The two other lines map the (at least for me) useless arrow keys to something useful; they are mapped to jump to the next/previous Search or to the next/previous compile error, etc., they simply step throu the quickfix list. You can use this as follows:

:Search foobar
<right>
<right>
…
2
  • I love this command, but added a few things so it will escape search terms better, and force a redraw. (using silent with splits can cause vim ui to bug out). command! -nargs=1 Search call setqflist([]) | silent execute "bufdo grepadd! '<args>' %" | redraw!
    – Igorio
    Jul 21, 2014 at 4:30
  • you can also just type :cn or :cp to switch to the next document.
    – phyatt
    Apr 10, 2017 at 20:36
6
 :bufdo vimgrepadd yoursearchterm % | copen
1

As I've found myself frequently doing this I mashed up an (improvable) script.

You or someone else might find it useful.


Short explanation:

Basically it searches buffer list and show result in quickfix-window.

Two basic commands is added.

  1. Search <pattern> : Search all buffers for <pattern>.
  2. Search1 <pattern> : Search all buffers for <pattern>, but only show first result for each buffer. Typically useful for listing all buffers where function, variable foo is used, (or what ever).

Use bang (:Search! foo) to append to results.

Additionally GSearch and GSearch1 is added where difference is that with Search the script add regex delimiter, e.g.:

foo -> /foo/

Where as GSearch expect it to be enclosed.

The j flag is always added to prevent jump.


Code:

There are some hacks to prevent error listing while at the same time keeping the code short. try / catch was a bit cumbersome on bufdo.

let s:not_idents = split("/!#$%&\"`´¨'¯()*+,-.:;<=>?¿@[\]^{|}µ¶·¸~±×÷®©«»¬­ª°º¹²³¼½¾", '\zs')
" Create a delimited pattern. "
fun! s:Parse_pat(pat)
    for c in s:not_idents
        if stridx(a:pat, c) == -1
            return c . a:pat . c
        endif
    endfor
    echohl Error
    echom "Could not delimit pattern '". a:pat ."'"
    echohl None
    return ''
endfun

fun! s:AllBufSearch(pat, bang, uno, isg)
    if a:isg
        let pat = a:pat
    else
        let pat = s:Parse_pat(a:pat)
    endif
    if pat == ''
        return
    endif
    cclose
    let [_buf, _view] = [bufnr("%"), winsaveview()]
    let _foldenable = &foldenable
    set nofoldenable

    " Copy of current qflist. "
    let qfc = getqflist()
    " Hack to prevent error if no matches. "
    call setqflist([{}])
    silent execute "bufdo vimgrepadd! " . pat . "j %"
    " Restore "
    exec "buffer " . _buf
    let &foldenable = _foldenable
    call winrestview(_view)
    " Fix "
    let qf = getqflist()
    call remove(qf, 0)
    " Only one listing per buffer. "
    if a:uno
        let bn = {}
        let i  = 0
        for m in qf
            if has_key(bn, m["bufnr"])
                call remove(qf, i)
            else
                let bn[m["bufnr"]] = 1
                call remove(qf[i], "valid")
                let i += 1
            endif
        endfor
    endif
    if a:bang == "!"
        let qf = qfc + qf
    endif
    " If any matches, copen. "
    if len(qf)
        call setqflist(qf)
        copen
    endif
endfun

command! -nargs=1 -bang Search   call s:AllBufSearch(<q-args>, "<bang>", 0, 0)
command! -nargs=1 -bang Search1  call s:AllBufSearch(<q-args>, "<bang>", 1, 0)
command! -nargs=1 -bang GSearch  call s:AllBufSearch(<q-args>, "<bang>", 0, 1)
command! -nargs=1 -bang GSearch1 call s:AllBufSearch(<q-args>, "<bang>", 1, 1)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .