Vim as PHP IDE: Ctags, and Code Browsing
So, past few weeks, I have been really fascinated with the all powerful Vim. And, I often wonder why: I took so much time switching to it? Probably, the steep learning curve! It has to be.
Anyways, so I have really really progressed with Vim this time, as compared to
my earlier trials. I am quite efficient with Vim now – even writing this blog
post on it. I know how to move quickly, make efficient uses of search and
replace, using Vim scripts etc. I have really really found plugins like
Gundo, Fugitive, Tagbar, Syntastic, Snipmate, NerdTree, and Powerline to be
useful and not to mention plugins like Vim-Rails which make my day-to-day
tasks easier with a particular language. Oh, and did I mention the incredible
!
and @
operators? They just rock!
But, well. This post is about using Ctags with Vim to make Vim feel more like an IDE and readily use Source Code Browsing within frameworks, large code projects, etc. Here, in this post, I have specified my configuration/process for using Ctags with MacVim for a CakePHP based project.
The Process
Well, I would try to create my Ctags on the fly, using Git hooks. This lets me
simply checkout, merge or commit to a branch and my tags would be generated
for the code in question. Moreover, these Ctags generated files are stored
inside .git
directory, which keeps our repositories clean (no need to add
a file to .gitignore
). Also, I would prefer a centralized place where I can
manage any script I use to create these Ctags, and hence, if after about an
year I think I need a change in the way script is working, or if say I want to
add support for or remove support for a language, I should be able to do it
from a single place and affect all my git repositories using these Ctags
hooks.
For this to work, i.e. for Vim to pick up our Ctags (that will be created in
.git/tags
file) we need to have Fugitive
installed (which I will really
really recommend anyways). This will make Vim look for Ctags in a .git/tags
and .git/<lang>.tags
file in our repository, irrespective of the current
working directory.
Let s set up a default set of hooks that Git will use as a template when creating or cloning a repository (requires Git 1.7.1 or newer):
1 2 |
|
I, usually, put all my Git related stuff in ~/Code/__dotfiles/git/
and
hence, the above template directory lands up as
~/Code/__dotfiles/git/template/
with all the hooks, in my
.dotfiles repository.
Now onto the first hook, which isn’t actually a hook at all, but rather
a script the other hooks will call. Place in ~/.git_template/hooks/ctags
and
mark as executable:
1 2 3 |
|
Although, make sure that the ctags
version is the GNU one, and the above
script runs without showing any errors. If installing via Homebrew
make sure
that the which ctags
command shows the correct ctags
executable path.
Making this a separate script makes it easy to invoke .git/hooks/ctags
for
a one-off re-index (or git config --global alias.ctags '!.git/hooks/ctags'
,
then git ctags
), as well as easy to edit for that special case repository
that needs a different set of options to ctags. For example, I might want to
re-enable indexing for JavaScript or SQL files, which I’ve disabled here
because I’ve found both to be of limited value and noisy in the warning
department. And, in these edge cases, all I need is to modify the
corresponding .git/hooks/ctags
script in that git repository. Neat and
clean.
We still need to create the actual hooks that the Git will copy to all
repositories that are (re)initialized using the git init
command. All the
files in the ~/.git_template/hooks
folder needs to be marked as executables.
You should use the following content for: post-commit
, post-merge
, and
post-checkout
hooks (which simply calls the ctags
hook, we create above):
1 2 |
|
Additionally, if you feel tags should also be generated on using git rebase
,
add the following code to post-rewrite
hook:
1 2 3 4 |
|
Once, the above is done, all we need to do is to issue a git init
command to
create Ctags for an already existing repository. All new git repositories will
automatically include these hooks and hence, will create the Ctags file on the
fly. Pure Automation. ;)
Global Projects
There are some projects that I always want available for source code browsing
like the Rails source code itself. For such projects, I would generally run
a one-off shell script that does this work for me, and store the generated
tags file in a directory such as ~/.tags/
with a suitable name. O’course it
does not make sense to version this directory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
Finally, I set the following inside my ~/.vimrc
file:
1 2 3 4 5 6 |
|
This basically tells vim to only load ctags for the current filetype, i.e. for
a ruby
buffer, vim will load all ctags files inside ~/.ctags/ruby
directory, and no ctags file inside ~/.ctags/php
Epilogue
(Now, that I have completed writing the post and I read it again, it seems that this post feels like a rewrite a post by tPope. Well, I was originally thinking of a different way to create these Ctags, but as I went deeper and deeper, I realized that what tPope describes is so natural and easy, that I have to ditch whatever it is – what I was doing now. And, do not forget, I am less than a month old with Vim and I am talking Ctags with Vim. I am allowed to reherse my steps :P )