I’m in ~/src. I can do git grep _pattern_ and get a list of all *.cpp or *.hpp files that match this pattern.
Now I would like to go through all the files that match the pattern and make edits on them. How do I do this in Vim? (Basically, I want Vim to go through my directory like git grep does, and jump me to the right files.)
You can use the single inverted commas (also a unix shell feature), something like:
vim `git grep --name-only <your expression>`
In bash, you could do
vim $(grep -l _pattern_ *.cpp *.hpp)
but that's a bash feature, not a vim feature.
you can use the args ex command:
:args *.cpp *.hpp
This will open all cpp and hpp files in the current directory.
You can use any file path expansions available to :grep as well.
You could possibly set the grepprg and grepformat options to run git grep... and interpret the result. This would then let you run the command :grep and read the results into the quickfix buffer - see :h quickfix for more information. You can then step through them with :cnext and :cprev, or :copen to open a separate window with the list of files - putting the cursor on a filename and pressing return will open that file for editing.
The advantage of this over Zoran's and ammoQ's suggestions is that it will not read the files into memory until you want to edit them. Their suggestion will load possibly hundreds of files into memory at once, and can be a nightmare to manage. It is also cross platform so should work on Windows without having to use a third-party shell such as cygwin bash.
By properly using the quickfix list, you can even go immediately to the the right line (using the :help quickfix commands, eg. :cn or :cw). So, if you are using bash or zsh:
vim -q <(git grep foo)
Related
Our servers only have vi/vim to check the log files and I feel searching in vi is painful and limited.
I wonder if it's possible to provide an executable file in the path and then use the vi user command to call it and the user command is able to accept multiple conditions like A=value1 && B=value2, A=value1 || B=value2, etc and then it searches the content in the open vi editor and places the cursor in matching text.
If it's possible please describe a bit the steps.
If what you have on your machines is actually Vim, you should be able to leverage the "quickfix" feature. In a nutshell, you can:
feed a list of locations to Vim,
optionally tell Vim how to parse that list,
go through that list with commands like :cnext or :lprevious,
display that list in a special window,
batch operate on every line in the list.
In the simplest scenario, your hypothetical external program would output a list formatted in a way Vim already understand, like:
filename.txt:3067:12:some text
filename.txt:4321:7:some text
which could be fed "directly" to Vim:
$ vim -q <(yourcommand)
# also open the quickfix window
$ vim -q <(yourcommand) +cwindow
or via some file:
$ vim -q yourfile
It can all be done from within Vim by telling it to use your program instead of grep for the :grep command:
set grepprg=yourcommand
and doing:
:grep <your arguments>
References:
:help quickfix
:help :cnext
:help :lprevious
:help -q
:help -+c
:help :cwindow
:help :grep
:help 'grepprg'
:help 'grepformat'
i want to grep search with vim editor on raspberry pi, Rasbian.
in windows, i usually use findstr and command like this
grep -s xxxx *.c
how do i grep search with vim editor on os Rasbian?
If you wanna grep, just without leaving Vim, you can use :!cmd to run grep as an external command: :!grep xxx *.c
Vim has :grep; it also uses the external grep (or whatever is configured in 'grepprg'), but parses the results and presents them in the quickfix list, which allows you to quickly navigate results inside Vim.
If you don't have / don't want to use external grep, there's also the :vimgrep variant. You have to use Vim's regular expression syntax, and it'll be slower because files are loaded into Vim.
Within a buffer, there are many alternatives, like :global or :ilist. With :bufdo, you can run them on all opened buffers.
I'd like to do a grep -r -l "index.php" while inside vim. I am using the NERDTree plugin too. I've tried the command :! but after this it states
Press ENTER or type command to continue
I try to type a command in and it immediately reverts back to vim.
Inorder to run an external command, you can prefix it with :!
In your case,
:!grep -r -l "index.php"
ie, your supposed to type the command(s) after :! while you're in vim itself.
Using vimgrep, you can do
:vimgrep /\cindex\.php/ **
Do check the examples given in vim-tips-working-with-external-commands
but after this it states "Press ENTER or type command to continue"
This is the expected result. For grep command, you can see the results on top of this line.
Do checkout vimgrep, Silver Searcher etc for a better workflow. Some links to familiarize them
Faster Grepping in Vim
Search multiple files with :vimgrep
Without plugins:
:vimgrep \cindex.php **
(\c forces ignorecase; ** is "all files in this directory and below")
With ack and Ack.vim:
:Ack -i index.php
With the_silver_searcher and Ag.vim:
:Ag -i index.php
You can also add in NERDTree integration using NERDTree-Ack and NERDTree-Ag.
Consider the following directory tree:
root/include/file.hpp
root/source/file.cpp
root/images/file.png
The command line is inside the directory root.
In the vimrc file, there is set wildignore=*.png.
If you open Vim in the folder root and run :next */file.*, it opens only file.hpp and file.cpp.
However, if you launch Vim from command line with vim */file.*, it opens all three files.
So, when feeding it a filename, it first loads the files, then vimrc? Is there a way to ignore extensions when opening files with Vim through the command line? Or to make Vim load vimrc first?
In the first scenario, the glob expansion is done by Vim and thus obeys the rules in your vimrc.
In the second scenario, the glob expansion is done by your shell and there's no reason to expect it to obey the rules in your vimrc.
You can do something like $ vim -c "next */file.*", which essentially opens Vim without a filename and executes next */file.*.
Or you can exclude the pattern directly in your shell. Assuming you have extglob set, this can be done in bash with $ vim !(file.png).
When doing :next */file.* from within Vim, vim expands the wildcard and filters by wildignore. When doing vim */file.* from your shell, the shell expands the wildcard, and passes all three files to Vim.
Depending on your shell, this will probably work instead:
vim +"args */file.*"
So far I always used EasyGrep for replacing text in multiple files. Unfortunately it is quite slow when a project gets bigger. One thing that seems to be amazingly fast is Ggrep of fugitive.vim that only search my version controlled files. All results are also stored in the quickfix list.
How can I use the results of Ggrep for doing a simple replace over all those found files? Is it somehow possible to use %s/foo/bar/cg on all files in the quickfix list or are there any better ways?
Update:
Vim now has cdo, see Sid's answer.
Original Answer:
Vim has bufdo, windo, tabdo and argdo, which let you perform the same command in all open buffers, windows or files in the argument list. What we really need is something like quickfixdo, which would invoke a command on every file in the quickfix list. Sadly, that functionality is lacking from Vim, but here's a solution by Al that provides a home-rolled solution. Using this, it would be possible to run:
:QFDo %s/foo/bar/gc
And that would run the foo/bar substitution on all files in the quickfix list.
The bufdo, windo, tabdo and argdo commands have some common behaviour. For example, if the current file can't be abandoned, then all of these commands will fail. I'm not sure if the QFDo command referenced above follows the same conventions.
I've adapted Al's solution to create a command called Qargs. Running this command populates the argument list with all of the files listed in the quickfix list:
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
Using this, you could follow these steps to do a project-wide search and replace:
:Ggrep findme
:Qargs
:argdo %s/findme/replacement/gc
:argdo update
Edit: (with a hat tip to Peter Rincker)
Or you could join the last 3 commands together in a single line:
:Ggrep findme
:Qargs | argdo %s/findme/replacement/gc | update
cdo command has now been added! After you grep, you can use cdo to execute the given command to each term in your quickfix list:
cdo %s/<search term>/<replace term>/cg
(Take a look at this git commit and this vim developers google group discussion for more information on cdo and the motivations behind adding it.)
nelstrom's answer is quite comprehensive and reflects his brilliant contributions to vimdom. It also goes a bit beyond what is strictly needed here; the quickfix step can be omitted in favor of populating args with the result of a shell command:
:args `git grep -l findme`
:argdo %s/findme/replacement/gc
:argdo update
should be all you need.
Edit: as Domon notes, :set hidden must be done first if it's not already set!
Using quickfix-reflector.vim, you can edit your search results in the quickfix window. The write command will then save the changes to your files.
:copen
:%s/foo/bar/cg
:write
External grep
(uses grepprg, grepformat like in makeprg/errorformat; if grepprg=='internal' this is identical to internal grep)
:grep fopen *.c
:copen
:cnext
Internal grep
:vimgrep /\<myVimregexp\>/ **/*.c
:copen
:cnext
etc.
Location list internal grep
:lvimgrep /\<myVimregexp\>/ **/*.c
:lopen
:lnext
etc.
Bonus: doing external grep for the loaded buffers:
:silent bufdo grepadd fstream %
:copen
:cnext
etc.
External for all arguments:
:silent argdo grepadd fstream %
:copen
:cnext
There's a patch to add the cdo (Quickfix do) command to vim, but it has not been pulled yet (as of 2015-03-25):
https://groups.google.com/forum/#!topic/vim_dev/dfyt-G6SMec
You may want to patch vim yourself to get this patch:
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