A few month ago I went to Sydney where my teammate Andrew showed me a pretty nifty feature of Rubymine. He was able to jump into definitions of Ruby methods. That wouldn’t be so special until he seamlessly navigated into one of the ruby gems source code – I was amazed.
In this article I’m going to describe how to achieve a similar workflow with Vim and convert it into a powerful IDE. Let’s start with jumping into method declarations inside your project.
To jump between method declarations and symbols we need some sort of a map that Vim can use to navigate. These maps are called tags and the one we are going to use is Exuberant Ctags.
The simplest generation is running
ctags -R in the root of your project. If you are using vim-rails plugin you can regenerate your tags with
:Rtags command. You can also set up your environment to automatically generate tags when file changes with guard or when you checkout new code with a git hook. For me, the manual generation is good enough.
Navigating between tags
Vim has a built-in navigation through the tags so there is no need for any plugin. The two commands I use the most are go to defition which is bound to
ctrl + ] and go back
ctrl + o.
If there are multiple tags for selected symbol you can use
:tselect command which is also accessible through visual mode and the key combination
g]. You select the number of a tag that is the most likely match and hit enter. Apart from that, you can use
Another option is to use CtrlP – a fuzzy finder that can browse file names as well as tags. The command for that is
Vim also support mouse mode and navigation similar to more modern IDEs when you can use
ctrl + click to navigate to definition and
ctrl + right click to get back.
Jumping into gem source
So far we covered generating tags and navigation only in your project and that was good enough for me for couple years. But can we jump into method definition inside of gem we use?
Without any integration you can use
bundle open to browse the source code of a gem in your editor. Fortunately, we can do better and create tags for the gems we use.
That should be enough to teach our Vim how to navigate into the source of the gems we are using in a current project. Also, it hooks into bundler and whenever we update or install a new one it regenerates the tags for us – neat.
To get the fully functional setup firstly, install Exuberant Ctags with brew.
brew install ctags
You need the following plugins in your
.vimrc if you are using Pathogen.
Plugin 'vim-ruby/vim-ruby' Plugin 'tpope/vim-rails' Plugin 'tpope/vim-rbenv' Plugin 'tpope/vim-bundler'
gem install gem-ctags gem ctags mkdir -p ~/.rbenv/plugins git clone git://github.com/tpope/rbenv-ctags.git \ ~/.rbenv/plugins/rbenv-ctags rbenv ctags
And you changed your Vim into a powerful Ruby IDE. Now you can generate and update your project tags by running
:Rtags and jump into code definition pressing
ctrl + ].
Important projects needed for a Vim setup:
- gem-ctags generates tags for gems on installation
- rbenv-ctags generates tags for ruby when installed with rbenv
- vim-ruby provides path support for ruby files in Vim
- vim-rails adds easy way to regenerate tags
- vim-rbenv provides path support for rbenv ruby files in Vim
- vim-bundler sets the location of tags in Vim
How to keep your Ctags up to date?
- Git hook approach to tag generation
- guard-ctags-bundler allows you to automatically generate tags on file changes
Articles and guides about Vim setup and tags:
- Vim guide on browsing tags
- Supercharge your VIM into IDE with Ctags
- Combining Vim and Ctags
- Exuberant Ctags
Benoit T: I added this in my vimrc
set tags+=.tags nnoremap <leader>ct :silent ! ctags -R --languages=ruby --exclude=.git --exclude=log -f .tags<cr>
<space>ct I get my ctags refreshed.
ivalkeen: For ruby I would recommend to take a look at ripper-tags instead of exuberant ctags, because it understands ruby much better and produces much more precise and complete tags files (the output format is the same).
Also if you use CtrlP, you might like my ctrlp-tjump plugin, which allows to do IDE-like fuzzy-search in multiple matches (instead of using :tselect/:tjump)
The ctrl-p-jump looks awesome – much nicer interface than :tselect. Thanks for the recommendation!