53

我想在当前在 vim 中打开的所有文件中搜索文本,并将所有结果显示在一个地方。有两个问题,我猜:

  • 我无法将打开文件列表传递给:grep/ :vim,尤其是不在磁盘上的文件的名称;
  • 的结果:grep -C 1 text在 quickfix 窗口中看起来不太好。

这是 Sublime Text 2 中多文件搜索的一个很好的例子:在此处输入图像描述

有任何想法吗?

4

6 回答 6

57

或者

:bufdo vimgrepadd threading % | copen

quickfix 窗口可能看起来不适合您,但它比 ST2 的“结果面板”功能强大得多,因为您可以在跳转到位置时保持它打开和可见,如果它不存在则与之交互。

于 2012-08-15T19:47:54.283 回答
8

ackAck.vim 很好地处理了这个问题。您也可以使用:help :vimgrep. 例如:

:bufdo AckAdd -n threading

将创建一个不错的快速修复窗口,让您跳到光标位置。

于 2012-08-15T18:47:10.133 回答
4

就像 Waz 的回答一样,我为此编写了自定义命令,并发布在我的GrepCommands 插件中。它允许搜索缓冲区 ( :BufGrep)、可见窗口 ( :WinGrep)、选项卡和参数。

(但像所有其他答案一样,它还没有处理未命名的缓冲区。)

于 2012-08-16T07:42:48.517 回答
2

我很久以前就做了这个功能,我猜它可能不是最干净的解决方案,但它对我很有用:

" Looks for a pattern in the open buffers.
" If list == 'c' then put results in the quickfix list.
" If list == 'l' then put results in the location list.
function! GrepBuffers(pattern, list)
    let str = ''

    if (a:list == 'l')
        let str = 'l'
    endif

    let str = str . 'vimgrep /' . a:pattern . '/'

    for i in range(1, bufnr('$'))
        let str = str . ' ' . fnameescape(bufname(i))
    endfor

    execute str
    execute a:list . 'w'
endfunction

" :GrepBuffers('pattern') puts results into the quickfix list
command! -nargs=1 GrepBuffers call GrepBuffers(<args>, 'c')

" :GrepBuffersL('pattern') puts results into the location list
command! -nargs=1 GrepBuffersL call GrepBuffers(<args>, 'l')
于 2012-08-15T22:49:34.757 回答
2

我真的很喜欢 romainl 的回答,但是有一些粘性边缘使它在实践中使用起来很尴尬。

您的 .vimrc 文件中的以下内容介绍了一个用户命令Gall(Grep all),它解决了我发现令人讨厌的问题。

funct! GallFunction(re)
  cexpr []
  execute 'silent! noautocmd bufdo vimgrepadd /' . a:re . '/j %'
  cw  
endfunct

command! -nargs=1 Gall call GallFunction(<q-args>)

这将允许像这样区分大小写的搜索:

:Gall Error\C

并且不区分大小写:

:Gall error

并带有空格:

:Gall fn run

优点

  • 它只会打开 Quickfix 窗口,没有别的。
  • 它将首先清除 Quickfix 窗口,然后再vimgrepadd从每个缓冲区获取结果。
  • Quickfix 窗口将包含整个打开缓冲区中所有匹配项的位置,而不仅仅是最后一次访问的位置。
  • 重复使用 :Gall,在通话之间无需任何特殊的内务处理。
  • 不等待错误并立即显示结果。
  • 不允许任何 autocmd 运行,从而加快整体操作。

矛盾的特征

  • 不会抢先跳转到列表中的任何位置。:cn获得第二个结果或CTRL-w b <enter>直接获得第一个结果。

缺点

  • 如果只有一个结果,您必须使用 手动导航到它CTRL-w b <enter>

要快速导航到任何缓冲区中的结果:

:[count]cn

或者

:[count]cp

例如:6cn,跳过列表中的 6 个结果,并在“主”窗口中导航到正确的缓冲区和行。

显然,窗口导航是必不可少的:

Ctrl-w w "next window (you'll need this at a bare minimum)
Ctrl-w t Ctrl-w o "go to the top window then close everything else
Ctrl-w c "close the current window, i.e. usually the Quickfix window
:ccl "close Quickfix window

如果您关闭 Quickfix 窗口,然后再次需要结果,只需使用:

:cw

或者

:copen

把它拿回来。

于 2020-09-20T02:57:17.807 回答
0

可以在下面找到 Waz 答案的改进(类固醇)版本,具有更好的缓冲区搜索和特殊情况处理(版主不再让我更新 Waz 的答案:D)。可以在此处找到更充实的版本,其中包含用于导航 QuickFix 列表和 F3 以关闭 QuickFix 窗口的箭头键绑定:https ://pastebin.com/5AfbY8sm (当我想弄清楚如何制作插件时)我会更新这个答案。我现在想加快分享它)

" Looks for a pattern in the buffers.
" Usage :GrepBuffers [pattern] [matchCase] [matchWholeWord] [prefix]
" If pattern is not specified then usage instructions will get printed.
" If matchCase = '1' then exclude matches that do not have the same case. If matchCase = '0' then ignore case.
" If prefix == 'c' then put results in the QuickFix list. If prefix == 'l' then put results in the location list for the current window.
function! s:GrepBuffers(...)
    if a:0 > 4
        throw "Too many arguments"
    endif

    if a:0 >= 1
        let l:pattern = a:1
    else
        echo 'Usage :GrepBuffers [pattern] [matchCase] [matchWholeWord] [prefix]'
        return
    endif

    let l:matchCase = 0
    if a:0 >= 2
        if a:2 !~ '^\d\+$' || a:2 > 1 || a:2 < 0
            throw "ArgumentException: matchCase value '" . a:2 . "' is not in the bounds [0,1]."
        endif
        let l:matchCase = a:2
    endif

    let l:matchWholeWord = 0
    if a:0 >= 3
        if a:3 !~ '^\d\+$' || a:3 > 1 || a:3 < 0
            throw "ArgumentException: matchWholeWord value '" . a:3 . "' is not in the bounds [0,1]."
        endif
        let l:matchWholeWord = a:3
    endif

    let l:prefix = 'c'
    if a:0 >= 4
        if a:4 != 'c' && a:4 != 'l'
            throw "ArgumentException: prefix value '" . a:4 . "' is not 'c' or 'l'."
        endif
        let l:prefix = a:4
    endif

    let ignorecase = &ignorecase
    let &ignorecase = l:matchCase == 0
    try
        if l:prefix == 'c'
            let l:vimgrep = 'vimgrep'
        elseif l:prefix == 'l'
            let l:vimgrep = 'lvimgrep'
        endif

        if l:matchWholeWord
            let l:pattern = '\<' . l:pattern . '\>'
        endif

        let str = 'silent ' . l:vimgrep . ' /' . l:pattern . '/'

        for buf in getbufinfo()
            if buflisted(buf.bufnr) " Skips unlisted buffers because they are not used for normal editing
                if !bufexists(buf.bufnr)
                    throw 'Buffer does not exist: "' . buf.bufnr . '"'
                elseif empty(bufname(buf.bufnr)) && getbufvar(buf.bufnr, '&buftype') != 'quickfix'
                    if len(getbufline(buf.bufnr, '2')) != 0 || strlen(getbufline(buf.bufnr, '1')[0]) != 0
                        echohl warningmsg | echomsg 'Skipping unnamed buffer: [' . buf.bufnr . ']' | echohl normal
                    endif
                else
                    let str = str . ' ' . fnameescape(bufname(buf.bufnr))
                endif
            endif
        endfor

        try
            execute str
        catch /^Vim\%((\a\+)\)\=:E\%(683\|480\):/ "E683: File name missing or invalid pattern --- E480: No match:
            " How do you want to handle this exception?
            echoerr v:exception
            return
        endtry

        execute l:prefix . 'window'
    "catch /.*/
    finally
        let &ignorecase = ignorecase
    endtry
endfunction
于 2017-08-09T00:21:43.480 回答