Search whole project by default with Vim/Ack - vim

I would like to use Ack (or similar plugin if something else can do the job) to search my whole project in Vim by default, rather than just the current directory. Ideally I'd end up with a process that works like using Cmd+Shift+F in Sublime. How can I do this?
An option like CtrlP's let g:ctrlp_working_path_mode = 'r' that makes it search within the nearest parent directory that contains a file like .git would be perfect. (https://github.com/kien/ctrlp.vim#basic-options)

I think Rooter is what you want. For example:
let g:rooter_patterns = ['Rakefile', '.git/']

I don't think Ack (or grep/vimgrep) can detect your "project root". If you often work on several projects, you could add this block in your vimrc:
let g:projectA_path="/path/to/A"
let g:projectB_path="/path/to/B"
let g:projectC_path="/path/to/C"
also define some functions/commands, like AckA, AckB, AckC...
basically the func/command just does:
exec 'Ack! '. pattern . " " . g:projectA_path
the pattern is the argument you passed in. then, in future, you could do:
:AckA foo
or
:call AckA("foo")
for quick grepping/acking in projectA.
I didn't think of a simpler way to do it. glad to see if there is better solution.

Most of the time I don't need to cd the project root, but stay in the same working directory.
So there is a simpler solution, based on answer of Kent, without cd'ing the project root, installing additional plugins and using ag:
let g:ackprg = 'ag --vimgrep --smart-case'
function! Find_git_root()
return system('git rev-parse --show-toplevel 2> /dev/null')[:-2]
endfunction
command! -nargs=1 Ag execute "Ack! <args> " . Find_git_root()
And to use it call :Ag <keyword>

I have this line in my .vimrc:
cnoreabbrev ack cd ~/your-project <bar> Ack! <Space>
Whenever you type :ack and hit the space the rest will be added to the command line and you can add the keyword.

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 call multiple function on Vim startup?

I frequently send files to Vim from Visual Studio. I have it set up as an external tool with the following parameter:
"+call cursor($(CurLine), $(CurCol))"
However, I also want to be able to call my own function as well. When I'm editing a file from VS I want the window to be large, so I expected to be able to do something like this:
"+call cursor($(CurLine), $(CurCol)); +call Embiggen()"
However, that doesn't work. I've tried a few variations (e.g. , call Embiggen(), etc).
Obviously I could write my own PlaceCursorAndEmbiggen function, but I don't really want to do that. Is there any way to call multiple functions on Vim startup?
Eureka!
Simply pass two strings:
"+call cursor($(CurLine), $(CurCol));" "+call Embiggen()"
Maybe the solution would have been easier to find had you used the alternative, more commonplace syntax: -c "cmd" instead of "+cmd". According to :help -c, you can pass up to 10 of these.
These exact commands can be combined into one using pipe symbol:
"+call cursor($(CurLine), $(CurCol)|call Embiggen()"
. There are much more that can be combined this way, but some like :normal can’t, use #Ingo Karkat’s or your own answer for them. If you are short* on +commands and still don’t want to create a .vim file you can use either :execute
vim -c "execute 'normal! 1' | execute 'normal! 2'"
or (bash/zsh) -S with process substitution:
vim -S <(echo '
normal! 1
normal! 2
')
. Though most of time it is better to just create a .vim file.
* You can pass up to 10 + or -c (they are equivalent and they are not counted separately) and 10 other --cmd, though letter is less useful.

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

Vim findfile function usage?

I'm looking for an example of how to use the findfile function in a vim script to search upwards recursively for a file, specifically using a wildcard.
Whenever I include a wildcard character as part of the first function parameter this doesn't seem to work.
For example, with the following directory structure:
~/MyProject/
Test.sln
src/
Test.cs
If I run the following function, while editing the file Test.cs with pwd set to ~/MyProject/src
function! Test()
let a = findfile("*.sln", ".;")
echo a
endfunction
findfile appears to return nothing. However, if I modify the function to remove the widcard as follows:
function! Test()
let a = findfile("Test.sln", ".;")
echo a
endfunction
It does what I would expect.
I've tested this on both ubuntu and windows and I see the same behavior on both. Am I doing something wrong here, or does findfile just not support wildcard characters? A lack of support for the wildcard character seems like a fairly strange omission. It seems like I must be doing something wrong here.
If you're using wildcards I think the glob() and/or globpath() functions are what you're looking for. See :h glob() and :h globpath().
One way to do it with external (fast) find
function! Test()
let l:list=system("find .. -maxdepth 1 -name \*.sln")
echo l:list
endfunction

Getting relative paths in Vim

Say I am running Vim and pwd returns
/home/rafid/myproject
And say I am currently editing the file
/home/rafid/myproject/website/editpage.php
Is there any command that returns this for me?
website/editpage.php
That is, the path of the file relative to the current folder.
Although expand('%') often works, there are rare occasions where it does not. But you can force Vim to always present the relative path by calling fnamemodify:
:echo fnamemodify(expand("%"), ":~:.")
From the manual:
:. Reduce file name to be relative to current directory, if
possible. File name is unmodified if it is not below the
current directory.
For maximum shortness, use ":~:.".
The :~ is optional. It will reduce the path relative to your home folder if possible (~/...). (Unfortunately that only works on your home; it won't turn /home/fred into ~fred if you aren't logged in as fred.)
As Adam pointed out the comments, this can be shortened to:
:echo expand("%:~:.")
Reference: :h expand<Tab> and :h fnamem<Tab>
If you are limited for space (e.g. using this in your statusline), and can manage with "fuzzy" information about where the file is located, then check out pathshorten() which compresses folder names down to one character:
:echo pathshorten('~/.vim/autoload/myfile.vim')
~/.v/a/myfile.vim
Reference: :h pathsh<Tab>
Another option would be to write a vim function. Here's my humble attempt:
function! Relpath(filename)
let cwd = getcwd()
let s = substitute(a:filename, l:cwd . "/" , "", "")
return s
endfunction
You call Relpath with any full path name, and it will strip the current directory name from its argument.
For example, try :echo Relpath(expand("%:p")) (the :p modifier asks Vim to return the full path). Obviously, this is not necessary in your case, since % by itself returns relative path. However, it might come in handy in other cases.
This works for me :
:echo expand("%")
if you use autocmd to always set the current directory of the buffer that you are working on ( cd %:p:h ) then you can just type :cd
Blockquote
This works for me :
:echo expand("%")
This is only working if you opened that file with a relative file:
for vi ./foo, expand("%") will be ./foo
but
for vi /tmp/foo expand("%") will be /tmp/foo
Yes, you can use
:args
This will give you the filename of the current file, for informational purposes.
A workaround can be :cd . which seems to re-evaluate the path relative-ness. I agree this is very annoying though.

Resources