【发布时间】:2011-08-06 20:54:18
【问题描述】:
到目前为止,我一直使用 EasyGrep 来替换多个文件中的文本。不幸的是,当项目变得更大时,它会很慢。似乎非常快的一件事是 fugitive.vim 的 Ggrep,它只搜索我的版本控制文件。所有结果也存储在 quickfix 列表中。
如何使用 Ggrep 的结果对所有找到的文件进行简单替换?是否有可能在快速修复列表中的所有文件上使用%s/foo/bar/cg,或者有更好的方法吗?
【问题讨论】:
到目前为止,我一直使用 EasyGrep 来替换多个文件中的文本。不幸的是,当项目变得更大时,它会很慢。似乎非常快的一件事是 fugitive.vim 的 Ggrep,它只搜索我的版本控制文件。所有结果也存储在 quickfix 列表中。
如何使用 Ggrep 的结果对所有找到的文件进行简单替换?是否有可能在快速修复列表中的所有文件上使用%s/foo/bar/cg,或者有更好的方法吗?
【问题讨论】:
更新:
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
Qargdo,但作为 Qdo 以减少命令完成冲突:github.com/henrik/vim-qargs
cdo 命令现已添加! grep 后,您可以使用cdo 对您的快速修复列表中的每个术语执行给定的命令:
cdo %s/<search term>/<replace term>/cg
(查看git commit 和vim developers google group discussion,了解有关cdo 的更多信息以及添加它的动机。)
【讨论】:
% 以防止替换所选列表之外的行。如果替换不是幂等的,也可能导致意外结果。
cdo 还为更灵活的操作提供了惊人的选项。例如cdo norm capMy new paragraph 这个例子在每次出现搜索词时运行normal,将搜索词周围的整个段落更改为“我的新段落”。惊人的强大。
:cdo %s/<search term>/<replace term>/gc | update
nelstrom 的回答相当全面,反映了他对 vimdom 的杰出贡献。它也有点超出了这里的严格要求;可以省略快速修复步骤,以便使用 shell 命令的结果填充 args:
:args `git grep -l findme`
:argdo %s/findme/replacement/gc
:argdo update
应该是你所需要的。
编辑:正如 Domon 所说, :set hidden 如果尚未设置,则必须先完成!
【讨论】:
vim `git grep -l findme`
:argo ... 之前 :set hidden 否则 Vim 会因为未保存的更改而出错。
(使用 grepprg、grepformat 就像在 makeprg/errorformat 中一样;如果 grepprg=='internal' 这与 internal grep 相同)
:grep fopen *.c
:copen
:cnext
:vimgrep /\<myVimregexp\>/ **/*.c
:copen
:cnext
等等
:lvimgrep /\<myVimregexp\>/ **/*.c
:lopen
:lnext
等等
:silent bufdo grepadd fstream %
:copen
:cnext
等等
:silent argdo grepadd fstream %
:copen
:cnext
【讨论】:
使用quickfix-reflector.vim,您可以在快速修复窗口中编辑您的搜索结果。然后write 命令会将更改保存到您的文件中。
:copen
:%s/foo/bar/cg
:write
【讨论】:
有一个补丁可以将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
【讨论】: