Navigating Vim projects like a Boss
I’ll admit it, I’m a Vim addict. I started using Vim while programming
Ruby on Rails and quickly got hooked on
vim-rails’ project navigation shortcuts.
Commands like :A
(meaning “alternate ”) to jump between a Ruby file and its
spec were huge timesavers. There were also other cool commands to jump to a
specific type of file.
:Econtroller - Jump to controller
:Emodel - Jump to model
:Emigration - Jump to migration
:Einitializer - Jump to initializer
In the past year, my day job has helped me venture beyond Ruby into Elixir and Angular. It’s fun getting to work in these new languages and frameworks, but I sorely missed my shortcuts to jump around projects. Fortunately, Tim Pope has written vim-projectionist to tackle just this problem.
Quick install
I use vim-plug to manage my dotfiles, but any Vim plugin manager will do. If you happen to be using vim-plug, all you have to do is add
Plug 'tpope/vim-projectionist'
to your .vimrc, then open Vim and run :BundleInstall
.
Your first .projections.json
To try out vim-projectionist let’s clone the
angular.js repo and open it up
in vim. As you look around, notice that for almost every file in the
src/
folder, there’s a matching spec file in the test/
directory.
src/ngMock/angular-mocks.js
test/ngMock/angular-mocksSpec.js
Since we know this is the pattern of how files are named in this project, let’s create a .projections.json file in the root of the project that allows use :A to toggle between the src file and its corresponding test.
{
"src/*.js": {
"alternate": "test/{}Spec.js"
},
"test/*Spec.js": {
"alternate": "src/{}.js"
}
}
Now open up src/ngMock/angular-mocks.js
and type :A
to watch it switch to test/ngMock/angular-mocksSpec.js
. Type :A
again and you should be switched back to the original file.
Here’s how it works.
1."src/*.js"
uses the * to capture the string between src/
and
.js
. In the src/ngMock/angular-mocks.js
example, the *
captures
ngMock/angular-mocks
.
"alternate": "test/{}Spec.js"
specifies the file to switch to when using:A
.{}
is replaced with the value captured in Step 1. If the captured value wasngMock/angular-mocks
then the alternate file would betest/ngMock/angular-mocksSpec.js
.- To be able to switch back from the test file to the src file, we have to
define the reverse association with a
"test/*Spec.js"
section.
More advanced example
Now that you have made your first .projections.json file, let’s try some more advanced features. For this example, clone the hex-web elixir project and open it up in vim. Take a look around and notice for every file in the web folder, there is usually a matching file in the test folder.
web/controllers/dashboard_controller.ex
test/controllers/dashboard_controller_test.exs
We can use this pattern to build a basic .projections.json file.
{
"web/*.ex": {
"alternate": "test/{}_test.exs"
},
"test/*_test.exs": {
"alternate": "web/{}.ex"
}
}
Now open up web/controllers/api/docs_controller.ex
and type :A
to watch
it switch to test/controllers/api_docs_controller_test.exs
. Type :A
again
and you should be switched back to the original controller file.
Now, let’s make it so we can jump to the controllers using an :Econtroller
shortcut like we could in vim-rails. Reopen the .projections.json, and add
the following section:
{
"web/controllers/*\_controller.ex": {
"type": "controller"
},
"web/*.ex": {
"alternate": "test/{}\_test.exs"
},
"test/*\_test.exs": {
"alternate": "web/{}.ex"
}
}
Now type the :Econtroller api/
command and hit Tab to see your options.
Projectionist will show you all of the possible controllers that match
what you’ve typed so far.
:Econtroller api/
api/docs api/key api/package api/retirement
api/index api/owner api/release api/user
:Econtroller api/
You can tab through all of the available options and hit enter to open. Once
it’s open you can use :A
to switch to the test file and :A
again to switch
back. You can also use the following variations of the :Econtroller
command
to control how the file is opened.
:Econtroller - Open the controller in the current window
:Tcontroller - Open the controller in a new tab
:Vcontroller - Open the controller in a vertical split
:Scontroller - Open the controller in a horizontal split
You can add as many of these “type” definitions to your .projections.json as
you like. For example, the following section would add the :Emodel
,
:Tmodel
, :Vmodel
, and :Smodel
commands.
{
"web/models/*.ex": {
"type": "model"
},
/* Rest of the .projections.json file */
}
Takeways
These are just a few of the features offered by vim-projectionist. Other
features include using templates for new files and transforming the path
captured by *
. Run :help projectionist
to see the full documentation.
Provided a project has a standard structure, you can easily build a .projections.json file that allows you to quickly navigate a new repo. I’m definitely indebted to Tim Pope for putting this plugin together, and can’t fathom the amount of time it’s saved me.
Thanks so much for reading this post and please follow my blog or share this article if you found it helpful.