【问题标题】:How do I search the open buffers in Vim?如何在 Vim 中搜索打开的缓冲区?
【发布时间】:2012-08-12 02:16:35
【问题描述】:

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

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

这是在 Sublime Text 2 中进行多文件搜索的一个很好的例子:

有什么想法吗?

【问题讨论】:

标签: search vim


【解决方案1】:

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

:bufdo AckAdd -n threading

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

【讨论】:

  • 如何在不打开所有缓冲区的情况下使其正常工作?
【解决方案2】:

或者

:bufdo vimgrepadd threading % | copen

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

【讨论】:

  • 非常好的解决方案。我不知道 vimgrepadd 命令。但是,该命令对我不起作用,必须这样做::bufdo vimgrepadd pattern % 后跟 :copen 或 :cw,甚至更好 :botright cw
  • 您对% 的看法是对的,我完全忘记了。无需发出:copen之后,将其放在管道之后,快速修复会自动打开。答案已编辑。
  • 谢谢,这或多或少是我想要的。 :bufdo grepadd -C 1 threading % 或多或少地产生了我想要的东西。通过对 vim 如何解释结果的一些调整,它可能会变得漂亮可爱。顺便说一句,如果需要,您可以轻松地在 ST2 中拆分窗口并将结果与​​其他文件一起显示。所以——
  • 通过执行以下操作显着加快搜索速度:autocmd 通过执行:noautocmd bufdo grepadd threading %
  • /threading/j 不打开新标签。在这样做之前能够清除快速修复会很好:stackoverflow.com/questions/27385970/…
【解决方案3】:

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

" 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')

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 我认为 vimgrep 不会搜索未命名缓冲区的原因是它无法在没有名称的 QuickFix 窗口中显示匹配项。例如匹配看起来像这样“HillarysEmails.txt|4 col 6|I am Russia.”。如果你这样做 :file HillarysEmails 那么你可以 grep 未保存的缓冲区。
    【解决方案5】:

    可以在下面找到 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
    

    【讨论】:

      【解决方案6】:

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

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

      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 窗口,不会打开其他任何内容。
      • 它会在每个缓冲区产生vimgrepadd-ing 之前先清除 Quickfix 窗口。
      • Quickfix 窗口将包含整个打开缓冲区中所有匹配项的位置,而不仅仅是最后一次访问的位置。
      • 使用 :Gall 重复使用,通话之间无需任何特殊的内务处理。
      • 不等待错误并立即显示结果。
      • 不允许任何 autocmd 运行,从而加快整体运行速度。

      矛盾特征

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

      缺点

      • 如果只有一个结果,您必须使用 CTRL-w b &lt;enter&gt; 手动导航到该结果。

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

      :[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
      

      把它拿回来。

      【讨论】:

      • 我挖了它,但由于某种原因,它将当前缓冲区更改为我缓冲区列表中的最后一个缓冲区。知道为什么吗?
      • 不,我不知道。以上是用vim 测试的。您可能正在使用neovim
      猜你喜欢
      • 2011-07-05
      • 1970-01-01
      • 2021-09-03
      • 1970-01-01
      • 2017-07-28
      • 1970-01-01
      • 2011-06-02
      • 2011-04-17
      相关资源
      最近更新 更多