vimgrep as per vim's path variable - vim

I usually work in multi location projects, where source files are distributed among different servers, databases, etc. What I isually do is to add these locations to vim's path, so, for instance, I can 'gf' into these files.
When firing a search to find a string using ":vimgrep", is it possible to somehow specify that the search is to be performed not at the current location but at all the levels specified by path?
My only options at the moment are
a) Create a folder with symlinks to the different source codes and start vim from there
b) Manually add the locations to the vimgrep command after the pattern expression

You could implement something like searchsavvy's ListGrep, but instead of doing vimgrepadd on each a:list, you do it recursively on each element in path. Roughly something like this:
...
call setqflist([])
for path in split(&path, ",")
" Recursively (**) grep each path and add it to quickfix.
exec 'silent! vimgrepadd/' . a:query . '/gj '. path .'/**'
endfor
Alternatively, you could use the :grep command (probably faster for large trees but needs work for paths with spaces):
function! GrepInPath(query)
exec ':grep '. a:query .' -R '. join(split(&path, ","), " ")
endf
(Untested.)
If I were you, I'd generate the list of all files every time I sync. You could use csearch and use notgrep and it would work with Unite's file_list source.

Related

vimscript augment rtp with directory above result of system command

I'm trying to modify my vimrc to include a directory
let g:mydir = system('which someExecutable')
execute "set rtp+=" . g:mydir
The problem is that which someExecutable returns something like
/aDir/a/b.
I need g:mydir set to /aDir/, so two dirs above b.
Is there an easy way to do this in vimscript?
You're looking for fnamemodify(path, ":h")
If you version of vim is recent enough, you can even use exepath('someExecutable') instead of system('which someexecutable'). Which gives:
fnamemodify(exepath('someExecutable'), ":h")
PS: don't forget to escape what must be escaped if you use exe "set rtp+=....

Can i use something like tunnel in vim?

For example:
If my current directory is /temp/src/com. And the file edited in vim is from /java/test.And now i want to add the path of the file to path environment. So if there is a cmd like set path+=$(filepath) in vim?
case 2:
Run make in terminal will start to compile a project, and it will out put logs about this compile. And now i want to read the outputed logs into vim using some command like r !make.
1) Pull the path into the current Vim buffer:
:r !echo \%PATH\%
Append to the path:
:let $PATH="C:\Test" . $PATH
2) This question is ambiguous, because it depends on your makefile behavior.
If your Makefile simply print to the console, then, :r make should do the trick.
If your make file actually writes to files explicitly, then there is no automatic way.
You'll have to write a custom vimscript function to pull in the logs.
1) Part 2
I do not know of what a way to do it in one line, but here's one way to achieve the functionality you want.
:redir #a "redirect output to register a
:pwd
:redir END "stop redirecting
:let #a = substitute(#a, '\n', '', 'g') "remove the newlines
:let $PATH=#a .":". $PATH
You should be able to wrap this in a function if you need to use it often.
You may reference environment variables using $MYVAR syntax. To set system environment variables use
let $MYVAR=foo
e.g.
let $PATH = "/foo" . $PATH
See http://vim.wikia.com/wiki/Environment_variables or :help :let-environment
Then you may use filename-modifiers to get directory name of a file in a current buffer:
let $PATH = expand("%:p:h") . $PATH
To read and parse compilation output in vim you might be interested to check quickfix mode
Use :make instead of :!make

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 to source all vim files in directory

I have split my .vimrc into several files and placed them into ~/vimfiles/vimrc.d/.
Currently I source each file in that directory using exact name:
source ~/vimfiles/vimrc.d/file1.vim
source ~/vimfiles/vimrc.d/file2.vim
etc.
How to make a loop thourgh all files in that directory so i could only have to do such loop in my .vimrc:
for file in ~/vimfiles/vimrc.d/*.vim
source file
enfor
As mb14 has already said, if you put them in ~/.vim/plugin they will be sourced automatically. For information, however, if you want to source all of the files in your vimrc.d directory, you could do this (requires a relatively recent Vim):
for f in split(glob('~/vimfiles/vimrc.d/*.vim'), '\n')
exe 'source' f
endfor
You may also be interested in the autoload mechanism, described in :help 41.15: if you're defining a lot of functions, this can make start-up a bit quicker as the functions are only loaded the first time they're used.
You can just put your files in the plugins directory (~/.vim/plugin). They will be automatically loaded.
mb14 gave you the best answer. You want something automatically executed? Then use the standard organization: here the plugin/ subdirectory.
Otherwise, :runtime would have been your friend:
:runtime! vimrc.d/*.vim
:source barks when its parameter doesn't exist while :runtime silently source nothing.
:source can source only one file while :runtime! can source any number of files.
:source takes an absolute pathname, or a pathname relative to the current directory while :runtime takes a pathname relative to the 'runtimepath' option, which shouldn't be a problem as long as you respect vim conventions.
The example from DrAl did not work for me, this is how I achieved it:
for fpath in split(globpath('~/.vimrc.d/', '*.vim'), '\n')
exe 'source' fpath
endfor
The following snip is what I use within my ~/.vimrc file to source scripts within the ~/.vimrc.d/ directory and sub-directories...
for f in glob('$HOME/.vimrc.d/**/*.vim', 0, 1)
execute 'source' f
endfor
Check vim -c ':help glob' for details about additional glob arguments.
TLDR
glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) *glob()*
{nosuf} set to False allows 'suffixes' and 'wildignore' options to apply
{list} set to True causes glob to return a list that respects new-lines within file names

Change Vim swap/backup/undo file name

Is it possible to change the way Vim names its swap/backup/undo files?
To avoid clutter, I've set options in my ~/.vimrc to dump these files in ~/.vim/tmp/{swap,backup,undo}; however, as I routinely edit files in different directories with the same name, I often end up with lots of otherwise indistinguishable files and Vim sometimes has trouble recovering.
Ideally, I'd like to use the naming scheme that the persistent undo has (%path%to%file.undo) for all these auxiliary files; there's no obvious way to set it, but can it be done with Buf{Read,Write} macros?
I have this in my .vimrc and it names the swap files with full path names and percent signs just as you describe:
" Store swap files in fixed location, not current directory.
set dir=~/.vimswap//,/var/tmp//,/tmp//,.
The key is the // at the end of the directories. See this note from :help dir:
For Unix and Win32, if a directory ends in two path separators "//"
or "\\", the swap file name will be built from the complete path to
the file with all path separators substituted to percent '%' signs.
This will ensure file name uniqueness in the preserve directory.
Here's part of my .vimrc from github.
This sets the undodir (and turns it on), sets the backupdir, and directory (used for .swp files). Note that it creates the directories if they don't already exist.
" Save your backup files to a less annoying place than the current directory.
" If you have .vim-backup in the current directory, it'll use that.
" Otherwise it saves it to ~/.vim/backup or .
if isdirectory($HOME . '/.vim/backup') == 0
:silent !mkdir -p ~/.vim/backup >/dev/null 2>&1
endif
set backupdir-=.
set backupdir+=.
set backupdir-=~/
set backupdir^=~/.vim/backup/
set backupdir^=./.vim-backup/
set backup
" Save your swap files to a less annoying place than the current directory.
" If you have .vim-swap in the current directory, it'll use that.
" Otherwise it saves it to ~/.vim/swap, ~/tmp or .
if isdirectory($HOME . '/.vim/swap') == 0
:silent !mkdir -p ~/.vim/swap >/dev/null 2>&1
endif
set directory=./.vim-swap//
set directory+=~/.vim/swap//
set directory+=~/tmp//
set directory+=.
" viminfo stores the the state of your previous editing session
set viminfo+=n~/.vim/viminfo
if exists("+undofile")
" undofile - This allows you to use undos after exiting and restarting
" This, like swap and backup files, uses .vim-undo first, then ~/.vim/undo
" :help undo-persistence
" This is only present in 7.3+
if isdirectory($HOME . '/.vim/undo') == 0
:silent !mkdir -p ~/.vim/undo > /dev/null 2>&1
endif
set undodir=./.vim-undo//
set undodir+=~/.vim/undo//
set undofile
endif
Hopefully, it's commented well enough to understand what's going on. If not, add a comment and I'll fix it.
Ciao!
Update [07/16/2012]
I got an email from Rob Kine asking these questions about the backupdir section that I wanted to answer for everyone:
It looks like you are removing the current directory, and then re-adding it. what does that do?
What does the ^= operator do?
How does the order of precedence in the use of folders checked work in Vim? (Like is the last folder added the first one it checks for?)
The first thing is to describe the different operators. These operators have different meanings for non-string-list options, so be warned!
-= removes the value from a string list;
+= appends the value to a string list;
^= prepends the value to a string list.
So the backupdir has the following operations applied:
Remove the current directory from the list.
Append the current directory to the list (this ensures it is the last thing checked).
Remove the home directory from the list (I don't like stuff being saved there).
Prepend ~/.vim/backup/.
Prepend ~/.vim-backup/.
When Vim looks for where to save the backups, it checks from first to last; so it'll check for ~/.vim-backup/, then check for ~/.vim/backup, then check the default list (except for . and ~/ which were removed), and finally check .
You can get help for all these in Vim by using (for example) :help ^= or :help backupdir.
Create the directory undo
$ mkdir ~/.vimundo
Set up your .vimrc file
set undodir=~/.vimundo

Resources