在 Vim 中使用 quickfix 列表搜索和替换
Posted
技术标签:
【中文标题】在 Vim 中使用 quickfix 列表搜索和替换【英文标题】:Search & replace using quickfix list in Vim 【发布时间】:2011-08-06 20:54:18 【问题描述】:到目前为止,我一直使用 EasyGrep 来替换多个文件中的文本。不幸的是,当项目变得更大时,它会很慢。似乎非常快的一件事是 fugitive.vim 的 Ggrep,它只搜索我的版本控制文件。所有结果也存储在 quickfix 列表中。
如何使用 Ggrep 的结果对所有找到的文件进行简单替换?是否有可能在快速修复列表中的所有文件上使用%s/foo/bar/cg
,或者有更好的方法吗?
【问题讨论】:
【参考方案1】:更新:
Vim 现在有cdo
,见Sid's answer。
原答案:
Vim 有bufdo
、windo
、tabdo
和argdo
,可以让你在参数列表中所有打开的缓冲区、窗口或文件中执行相同的命令。我们真正需要的是像quickfixdo
这样的东西,它会在quickfix 列表中的每个文件上调用一个命令。遗憾的是,Vim 缺少该功能,但 here's a solution by Al 提供了一个自制的解决方案。使用它,可以运行:
:QFDo %s/foo/bar/gc
这将在 quickfix 列表中的所有文件上运行 foo/bar 替换。
bufdo
、windo
、tabdo
和 argdo
命令有一些共同的行为。例如,如果当前文件不能被放弃,那么所有这些命令都会失败。我不确定上面引用的QFDo
命令是否遵循相同的约定。
我已经修改了Al's solution 来创建一个名为Qargs
的命令。运行此命令会使用 quickfix 列表中列出的所有文件填充参数列表:
command! -nargs=0 -bar Qargs execute 'args ' . QuickfixFilenames()
function! QuickfixFilenames()
" Building a hash ensures we get each buffer only once
let buffer_numbers =
for quickfix_item in getqflist()
let buffer_numbers[quickfix_item['bufnr']] = bufname(quickfix_item['bufnr'])
endfor
return join(values(buffer_numbers))
endfunction
使用它,您可以按照以下步骤进行项目范围的搜索和替换:
:Ggrep findme
:Qargs
:argdo %s/findme/replacement/gc
:argdo update
编辑:(向 Peter Rincker 致敬)
或者您可以将最后 3 个命令合并到一行中:
:Ggrep findme
:Qargs | argdo %s/findme/replacement/gc | update
【讨论】:
我相信你应该在你的Qargs
命令中使用-nargs=0
和-bar
。
使用args
和argdo
是个好主意!我认为将Qargs
和argdo
命令合二为一会更好(也更方便):command! -nargs=1 -complete=command -bang Qargdo exe 'args '.QuickfixFilenames() | argdo<bang> <args>
我创建了一个简单的插件来包装:Qargs
命令:github.com/nelstrom/vim-qargs
@ib。谢谢你(当然还有@nelstrom)。分叉 @nelstrom 的插件以添加您的 Qargdo
,但作为 Qdo
以减少命令完成冲突:github.com/henrik/vim-qargs
一个补丁 was submitted 将 :cdo 和 :ldo 命令添加到 Vim。【参考方案2】:
cdo
命令现已添加! grep 后,您可以使用cdo
对您的快速修复列表中的每个术语执行给定的命令:
cdo %s/<search term>/<replace term>/cg
(查看git commit 和vim developers google group discussion,了解有关cdo
的更多信息以及添加它的动机。)
【讨论】:
我认为 replace 命令不应包含%
以防止替换所选列表之外的行。如果替换不是幂等的,也可能导致意外结果。
使用cdo
还为更灵活的操作提供了惊人的选项。例如cdo norm capMy new paragraph
这个例子在每次出现搜索词时运行normal
,将搜索词周围的整个段落更改为“我的新段落”。惊人的强大。
我还需要将上面的内容传递给“update”命令,否则 vim 不想移动到下一个文件,因为缓冲区已被编辑但未保存。命令:cdo %s/<search term>/<replace term>/gc | update
【参考方案3】:
nelstrom 的回答相当全面,反映了他对 vimdom 的杰出贡献。它也有点超出了这里的严格要求;可以省略快速修复步骤,以便使用 shell 命令的结果填充 args:
:args `git grep -l findme`
:argdo %s/findme/replacement/gc
:argdo update
应该是你所需要的。
编辑:正如 Domon 所说, :set hidden 如果尚未设置,则必须先完成!
【讨论】:
+1 务实的解决方案。基于此,您还可以在启动 vim 时填充 arglist:vim `git grep -l findme`
这对我有用。但是,我必须在 :argo ...
之前 :set hidden
否则 Vim 会因为未保存的更改而出错。【参考方案4】:
外部grep
(使用 grepprg、grepformat 就像在 makeprg/errorformat 中一样;如果 grepprg=='internal' 这与 internal grep 相同)
:grep fopen *.c
:copen
:cnext
内部grep
:vimgrep /\<myVimregexp\>/ **/*.c
:copen
:cnext
等等
位置列表内部 grep
:lvimgrep /\<myVimregexp\>/ **/*.c
:lopen
:lnext
等等
奖励:为加载的缓冲区执行外部 grep:
:silent bufdo grepadd fstream %
:copen
:cnext
等等
所有参数的外部参数:
:silent argdo grepadd fstream %
:copen
:cnext
【讨论】:
不确定您要通过这些示例指出什么。我知道如何使用 grep 和 vimgrep。我不明白这个答案如何适合这个问题。 (a) 向您展示一些减少 vim 中 grep 范围的方法 (b) 向您展示如何为外部 grep 做这些事情。如果有点无聊,我很抱歉,但它对我有用:)【参考方案5】:使用quickfix-reflector.vim,您可以在快速修复窗口中编辑您的搜索结果。然后write
命令会将更改保存到您的文件中。
:copen
:%s/foo/bar/cg
:write
【讨论】:
【参考方案6】:有一个补丁可以将cdo(Quickfix do)命令添加到vim,但是还没有拉出来(截至2015-03-25):
https://groups.google.com/forum/#!topic/vim_dev/dfyt-G6SMec
你可能想自己给 vim 打补丁来获得这个补丁:
brew install hg # install mercurial, e.g. with homebrew
hg clone https://vim.googlecode.com/hg/ vim
cd vim
# copy/download patch to . folder
patch -b -p1 < cdo.diff
./configure
make && make install
【讨论】:
以上是关于在 Vim 中使用 quickfix 列表搜索和替换的主要内容,如果未能解决你的问题,请参考以下文章
使用 ninja 和 clang++ 时 vim 中的快速修复列表
在 Visual Studio 2010 (utility.obj) 中使用带有 VC++ 的 QuickFix 时出错