How can I search a word in whole project/folder recursively? - search

Suppose I'm searching a class JFactory inside a folder and it's sub-directories.
How can I file that file which contains class JFactory?
I don't want to replace that word but I need to find that file that contains class JFactory.

:vimgrep /JFactory/ **/*.java
You can replace the pattern /JFactory/ with /\<JFactory\>/ if you want full word match. :vim is shorthand for :vimgrep.
If JFactory or \<JFactory\> is your current search pattern (for example you have hit * on one occurrence) you can use an empty search pattern: :vimgrep // **/*.java, it will use last search pattern instead. Handy!
Warning: :vimgrep will trigger autocmds if enabled. This can slow down the search. If you don't want that you can do:
:noautocmd vimgrep /\<JFactory\>/ **/*.java
which will be quicker. But: it won't trigger syntax highlighting or open gz files ungzipped, etc.
Note that if you want an external program to grep your pattern you can do something like the following:
:set grepprg=ack
:grep --java JFactory
Ack is a Perl-written alternative to grep. Note that then, you will have to switch to Perl regexes.
Once the command of your choice returned, you can browse the search results with those commands described in the Vim documentation at :help quickfix. Lookup :cfirst, :cnext, :cprevious, :cnfile, etc.
2014 update: there are now new ways to do that with the_silver_searcher or the_platinum_searcher and either ag.vim or unite.vim plugins.

From the project root folder, run following:
grep -H -r 'what_you_search' * | less
You will get a list of folders and matching lines with that string.

The Silver Searcher(https://github.com/ggreer/the_silver_searcher)
highly recommended, really fast!
install
sudo pacman -S the_silver_searcher // arch linux
sudo apt install silversearcher-ag // ubuntu
usage
$ ag keywords
integrate with vim
rking/ag.vim (https://github.com/rking/ag.vim)
after installing
:Ag keywords

Take a look at ctags and cscope which let you jump to class and function definitions, and find where those functions/classes are used.

This script may help: Filesearch.

Open the command line window by:
Esc - to enssure you are in Normal mode
type q , type :
the command line should open ( it like a tmp file to write the command you can navigate as you would navigate normally in any vim file ...
type i to enter insert mode
this example will search for the to_srch string recursively bellow the current dir for all file types of type '.js' and '.java' but omit all file paths containing the string node_modules
:g/console.log/ | :vimgrep /console.log/ `find . -type f -name '*.js' -o -name '*.java' -not -path '*node_modules/*'`
Now wheen you :copen you could navigate with the arrow keys through the sarch results ...
you could also set those in .vimrc
" how-to search recursively under the current dir for the files of type js and java but omit the
" node_modules file paths
":g/console.log/ | :vimgrep /console.log/ `find . -type f -name '*.js' -o -name '*.java' -not -path '*node_modules/*'`
" reminder open the quick fix window by :copen 20
" reminder close the quick fix window by :ccl
you could omit the first :q/to_srch/ I use it to highlight the search results automatically since I have "set hlsearch" in my ~/.vimrc
Any hint how-to enable automatically the srch results from the vimgrep or in vimrc will be highly appreciated ...

Related

Skip showing external command to be run when invoking `:grep`

Let's say I have many files:
for i in $(seq 1 1000)
do
if [ $((1 + RANDOM % 100)) -lt 2 ]
then
echo "needle" > $(uuid)
else
echo "haystack" > $(uuid)
fi
done
which I then edit with vim:
find . -type f | xargs -o vi --clean
I can search in these files via:
:vimgrep needle ##
or:
:grep needle ##
However, when I use the latter, vim does two things that I would like it to skip:
shows me the external command that it will execute, in this case pages of:
:!grep -n needle ./499553b6-615d-11ed-9ef7-5f9f4b37d6da ./484c2354-615d-11ed-94ff-a3a9a2d52531 ./49492e82-615d-11ed-af5d-5363f17c2e2b ./4ab7cc42-615d-11ed-8d84-4fd2cdf1942
c ./4ad4a132-615d-11ed-8af6-2f5cbf24f5de ./4c1f26c0-615d-11ed-b630-6bcbd445b4a1 ./4de4b948-615d-11ed-8e82-4f0c16b0065e <snip>
asks me to Press ENTER or type command to continue before starting to edit the matching files
How can I achieve this?
If you don't depend on specific features of your :help 'grepprg', then :help :vimgrep is your best choice because the work is done internally.
If you do, then you will have to use a different command because :help :grep shells out and it can't really be made to work silently. You might find mappings online that press the dreaded <CR> for you but they don't really fix anything.
The :help :cexpr family of commands is a less noisy alternative that allows you to use :help system() and thus remove both the shelling-out and the <CR> problem:
:cexpr system('grep -n needle ' .. expand('##'))
That's a lot to type, though, so you might want to turn that into a proper command or mapping.
Welcome to this particular rabbit hole.

VIM: grep search all files listed in text file

I have a complected project hierarchy for my FPGA projects. I have written a passer which examines the "Vivado/ISE" project file and returns a file containing a list of all the source file the project users (I then run ctags over this list).
I would like to be able to search this list of files from vim 7.4 without needing to do a whole recursive search through the FPGA library. I can do this from the linux command line using something like:
cat ./files.txt | xargs grep -Hn my_function
Where ./files.txt contains the list of files I would to search over. However I would like to be able to use vim's internal grep function. I would also like to be able to run this from both Windows and Linux.
Is there an easy way to pass a list of files (contained within a file) to vim's grep ex function?
You should probably use a plugin such as CtrlSF. But if you insist to do it with Vim alone, you can do something like this:
function! Grep(what, where)
exec join(extend(['vimgrep', a:what],
\ map(filter(readfile(a:where), 'v:val !=# "" && filereadable(v:val)'),
\ 'fnameescape(v:val)')))
copen
endfunction
command! -nargs=+ Grep call Grep(<f-args>)
Then you'd just call :Grep /pattern/ filelist, instead of :vimgrep /pattern/ ....
First step, populate the argument list with all the files in your list:
" in UNIX-like environments
:args `cat files.txt`
" in Windows
:args `type files.txt`
Second step, search for pattern in the argument list:
:vim pattern ##
If you have opened all files in Vim—eg with
vim `<files.txt`—then you can search all of them with (e.g.)
:bufdo g/my_function/
If you :set nu you'll get line numbers as per
grep -nHth

Why cscope don't search definitions in header files?

I use the following command to generate my cscope database:
tmpfile=$(mktemp)
find dir1/ dir2/ dir3/ -type f -regex ".*\.\([chlysS]\(xx\|pp\)*\|cc\|hh\|inl\|inc\|ld\)$" -print > $tmpfile
cscope -q -b -U -i $tmpfile -f cscope.out
Into vim, a :cs f g myfunction only leads me to the definition in C file, and nether in header file.
Make sure you got the terminology right. In C, usually the function definitions are put in C files, whereas declarations go into header files.
The cscope command f g (find definition) should correctly take you to the function definition. In the case where you actually have definitions in a header file (for example inline functions) the find definition command takes you there as well. If this is not the case, you should file a bug report to the cscope team.
Cscope unfortunately does not provide functionality for showing only a declaration. You could use the find symbol command (f s) but this might show a lot of results if the function is called from many places in your code.
You can use ctags which usually lets you choose from the declaration or definition. I usually use a mix of cscope and ctags within my projects because neither of them provides all the functionality i want.

Efficient way to refactor a class/method/string within a directory using vim

So far, I have been manually refactoring code by using the find-and-replace operation
%s:/stringiwanttoreplace/newstring/g
in vim.
But this is a slow and laborious process if I have stringiwanttoreplace in many files inside a specific directory.
My current/typical slow and laborious process involves a grep:-
grep -rn "stringiwanttoreplace" .
in my terminal to reveal all the locations/filenames where stringiwanttoreplace are; and now that I know which files contain stringiwanttoreplace, I will open each file one-by-one to perform the find-and-replace operation in each file.
Is there a more efficient workflow (in vim) to get this done?
CLARIFICATION: I would prefer a vim-based solution instead of a bash script/one-liner.
Here's the full sequence of commands that I would use:
/stringiwanttoreplace
:vimgrep /<c-r>// **
:Qargs
:argdo %s//newstring/g
:argdo update
In the first line, we search for the target pattern. That populates the last search pattern register (:help quote/), which means that we won't have to type it out in full again.
The :vimgrep command searches the entire project for the specified pattern. Type <c-r>/ as ctlr+r followed by / - this inserts the contents of the last search pattern register onto the command line. The first and last / symbols are delimiters for the search field. The trailing ** tells Vim to look inside every file and directory below the current directory.
At this point, the quickfix list will be populated with search matches from all matching files. :Qargs is a custom command, which populates the argument list with all of the files listed in the quickfix list. Here's the implementation:
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
Add that to your vimrc file.
Having run :Qargs, our argument list should now contain all of the files that include our target string. So we can run the substitution command with :argdo, to execute the command in each file. We can leave the search field of the substitution command blank, and it will automatically use the most recent search pattern. If you want, you could include the c flag when you run the substitution command, then you'll be prompted for confirmation.
Finally, the :argdo update command saves each file that was changed.
As #Peter Rincker pointed out, you should ensure that Vim's 'hidden' option is enabled, otherwise it will raise an error when you try to switch to another buffer before writing any changes to the active buffer.
Also, note that the last 3 commands can be executed in a single command line, by separating them with a pipe character.
:Qargs | argdo %s//replacement/gc | update
The :Qargs command is pinched from this answer (by me), which in turn was inspired by this answer by DrAl. A very similar solution was posted by #ib, which suggests to me that Vim should really implement something like :quickfixdo natively.
If you really want to do it in Vim you can follow the suggestions here.
You can call this from within Vim (:!find ...) but you don't need to:
find . -type f | xargs sed -i 's/stringiwanttoreplace/newstring/g'
Fine-tune the file selection with the dozens of parameters described in
man find
(e.g., replace only in HTML files: -name \*.html)
This solution will try to attempt the replacement in all files. You can filter that through grep before, but that is just doing twice the work for no gain.
By the way: sed uses almost the same syntax for regular expressions as Vim (stemming from the same history).
You could open all the files and type
:bufdo :s/stringiwanttoreplace/newstring/g
It performs the search/replace in all your buffers.
You don't need vim to do this, you can use command line tools. Using sed in a loop on the list of files to do this for you automatically. Something like this:
for each in `grep -l "stringiwanttoreplace" *` ;
do
cat $each | sed -e "s/stringiwanttoreplace/newstring/g" > $each
; done
vim7 has recursive grep built-in
:vimgrep /pattern/[j][g] file file1 file2 ... fileN
the result will be shown in a quickfix-window (:help quickfix)
to do the search recursively use the **-wildcard like
**/*.c to search through the current folder and recursively through all subdirectories.

How can I replace a word all the files within a folder in Vim?

I know that by typing the following: :%s/iwanthis/replacedbythis/g will change all the matching words of the file. How can I do the same for all the files within a folder?
(actually replacing a lot of words like this: padding-bottom:5px;)
Open Vim with all the files loaded into buffers, and do the replace on all buffers at once with bufdo:
% vim *
... when vim has loaded:
:bufdo %s/iwanthis/replacedbythis/g | w
The | w will write each file back to disk.
you can try greplace.vim that can give you a buffer include all lines matching a given regex across multiple files, then you can modify things in the buffer, and then call another greplace command to make all the changes updated to all these files.
Hope this would be helpful for those who work without vim
find /your_path/to/folder -type f -exec sed -i 's/text_to_be_replaced/new_text/g' {} \;
This code replaces all the occurrences of the text in the specified path (/your_path/to/folder). Thought it might be helpful for someone.

Resources