Using VIM as your Grails IDE Part 1: Navigating your project

For the last few months I’ve been steadily moving more towards VIM as my primary editor for Grails development.  Here I’ll share some of the plugins, scripts tips and tricks that I’ve found most useful for this.   I’ll assume you have some knowledge of VIM and the ability to install VIM or your system of choice.  Because VIM is so customizable, and everyone is sure to have different workflows, I don’t expect anyone to follow this setup to the letter.  Hopefully it will give you a good jump start though.

So…why do you want to do this?

I don’t want to get into flame wars over editors.  Some prefer a very robust IDE like Intellij or Eclipse, while others might find Textmate or even Emacs their speed.  I find VIM to be the ideal development environment for the following reasons, among others:

  • It’s lightweight – Even with all of the tweaks and plugins I go through below it’s still snappy and there is very little time spent waiting for the editor.
  • It’s amazingly customizable – With a huge variety of user generated scripts, plus the ability to write your own quickly and easily, it’s one of the most flexible editors out there.  Having full control of how your editor works allows you to take the features you care about and use, and throw out those you don’t.
  • Normal mode – Navigating with the keyboard is incredibly efficient. (Once you get past the fairly steep learning curve)

Part 1: Navigating your project

This blog post got really big, really quickly, so this first one will deal only with navigation of the project.

First and foremost, if you don’t already have the pathogen plugin, get it now.  This plugin makes plugin management much easier.  Instead of extracting files all over your .vim directory (and finding and deleting them if you decide you don’t like the plugin), you can put each plugin and it’s files into it’s own directory in the .vim/bundle directory.  As an added benefit, if you feel like keeping your plugins on the bleeding edge, and your plugins source repository is available, you can clone the repository right into your bundle directory.

For example, the next plugin that you may want to add, is nerdtree.  Rather than download the zip file from vim.org, you can do the following

cd ~/.vim/bundle
git clone https://github.com/scrooloose/nerdtree.git

This makes it much easier to update the plugin as changes come.

 

NERDTree
NERDTree adds a file browser on the left side of your VIM window, much like a typical IDE would have.  This allows for simple file browsing and editing.  It also comes with some handy functions like locating the current file. in a file tree. NERDTree allows you bookmark frequently used directories with the command

:Bookmark bookmarkName

Then, within NERDTree, you can just type ‘B’ to show or hide your bookmarks.  Highlight it and hit enter to navigate to that directory.  Note that viewing a different directory in NERDTree will not change VIM’s current directory.  To change the current directory, highlight the desired directory and type ‘cd’.

As with most of the functions that I use on a regular basis, I’ve added shortcuts for some of NERDTree’s functions so I don’t have to type the whole command.  For example:

map <F2> <Esc>:NERDTreeToggle<CR> "Toggle the file browser
map <A-F1> <Esc>:NERDTreeFind<CR> "Find the current file in the file browser

These shortcuts allow you easily navigate the file tree, which is extremely useful, but there is an easier way to open files within your project.

Command-T
Command-T is a plugin that provides the ability to find files through a file path search.  By typing <Leader>t, the plugin brings up a list of all files in the project.  That list can then be filtered by typing portions of the desired files path.  Because of the structure of a grails project, it is fairly easy to reduce the size of that list quickly, even on a large project.   For example, to find the domain class Product and not ProductService, ProductTest etc, you can search with something like “domprod”.  By specifying the top level directory first, it will quickly remove items that aren’t in a directory starting with “dom”.

To ensure that command-T doesn’t start finding a bunch of files that you don’t care about, you should be sure to set your wildignore property in your .vimrc

set wildignore+=*.class,.git,.hg,.svn,target/**

Another important thing to note is that command-t will only search the current working directory.  If you need to change your current directory you can either enter

:cd /path/to/directory

or go into nerdtree, highlight the directory you want to use and type

cd

Buffer Explorer
Buffer Explorer is a fairly simple plugin that nonetheless adds a lot of value.  By typing <Leader>be, you will be given a list of the currently open buffers in VIM.  If you are using Command-T to open files this is very useful.  Once you’ve opened several buffers, you can quickly navigate back to a file that is already open.  The list also has indicators for whether or not the buffer is modified/active etc.  To keep the list small, you can use the :bd command to close a file that no longer needs to be open.  Within buffer explorer you can also use ‘d’ to close the buffer as well.

EasyGrep
EasyGrep provides an easy way to search all files for certain text.  You can simply put the cursor on a word that you want to search and type <Leader>vv to search for that in the current directory.  It also gives you a :Grep command that will perform the same search but with the provided text.  EasyGrep allows you to specify the following options in .vimrc.

" EasyGrep
let g:EasyGrepMode=2
let g:EasyGrepCommand=0
let g:EasyGrepRecursive=1
let g:EasyGrepIgnoreCase=1

When EasyGrepMode is set to 2, it will only search for files that are of a similar type to the current file which can significantly improve performance.  To make this work with Grails, add the following line to ~/.vim/bundle/EasyGrep/plugin/EasyGrepFileAssociations

Groovy=*.groovy *.gsp *.gradle <Java> <Properties>
Properties=*.properties

This will tell EasyGrep to search groovy, gsp, gradle and properties files, as well as all of the types associated with Java.

MRU
One other small plugin that is useful is MRU (Most Recently Used) which provides a list of your most recently used files.  Just type :MRU and the list is there for you.

Taglist
The Taglist plugin gives you the ability  to navigate methods more easily.  It requires exuberant ctags.  Unfortunately neither ctags or taglist support Groovy by default.  To tell ctags how to parse Groovy, create a .ctags file in your home directory and adding the following to it.

--langdef=groovy
--langmap=groovy:.groovy
--regex-groovy=/^[ t]*[(private|public|protected) ( t)]*[A-Za-z0-9_<>]+[ t]+([A-Za-z0-9_]+)[ t]*(.*)[ t]*{/1/f,function,functions/
--regex-groovy=/^[ t]*def[ t]+([A-Za-z0-9_]+)[ t]*=[ t]*{/1/f,function,functions/
--regex-groovy=/^[ t]*private def[ t]+([A-Za-z0-9_]+)[ t]*/1/v,private,private variables/
--regex-groovy=/^[ t]*def[ t]+([A-Za-z0-9_]+)[ t]*/1/u,public,public variables/
--regex-groovy=/^[ t]*[abstract ( t)]*[(private|public) ( t)]*class[ t]+([A-Za-z0-9_]+)[ t]*/1/c,class,classes/
--regex-groovy=/^[ t]*[abstract ( t)]*[(private|public) ( t)]*enum[ t]+([A-Za-z0-9_]+)[ t]*/1/c,class,classes/

To enable Taglist, you’ll actually have to edit the plugin source.  You can add the following line to your ~/.vim/bundle/taglist/plugin/taglist.vim

let s:tlist_def_groovy_settings = 'groovy;p:package;c:class;i:interface;' .
                               'f:function;v:variables'

Again since displaying the method list is something that I do frequently, I’ve added the following to my .vimrc as a shortcut

map <F3> <Esc>:TlistToggle<CR>

Custom Scripts

In addition to all of the great plugins above, I’ve added a few custom scripts that make navigating my project a little easier.  The scripts are below.  The first one ‘OpenVariableUnderCursor’ which I map to Control-i, grabs the word under the cursor and looks for a file with that name and the same extension as the current file.  It will capitalize the first letter of the word so you can use it on instance names that share the name of the class.

The FindSubClasses script uses EasyGrep to find any classes that directly extends or implements the item under the cursor.

"Open file under cursor
map <C-i> :call OpenVariableUnderCursor(expand("<cword>"))<CR>
map <Leader>h :call FindSubClasses(expand("<cword>"))<CR>

function! OpenVariableUnderCursor(varName)
    let filename = substitute(a:varName,'(<w+>)', 'u1', 'g')
    :call OpenFileUnderCursor(filename)
endfunction

function! OpenFileUnderCursor(filename)
   let ext = fnamemodify(expand("%:p"), ":t:e")
   execute ":find " . a:filename . "." . ext
endfunction

function! FindSubClasses(filename)
    execute ":Grep (implements|extends) " . a:filename
endfunction

Putting it all together

With all of this put together you can easily move around your Grails project in VIM.  Open VIM from your project root and use Command T or NERDTree to open a file.  Use Taglist to navigate methods.  Use EasyGrep to find usages.  Use buffer explorer to move between open files and custom scripts to jump to other classes from source.  All of this coupled with the power of VIM’s normal mode allows for smooth navigation of your project without the overhead of a full blown IDE.

 

About the Author

Object Partners profile.

One thought on “Using VIM as your Grails IDE Part 1: Navigating your project

  1. Peter Ledbrook says:

    How do you find EasyGrep compares with Ack?

    I’ll second that selection. NERDTree, Command-T and one of the grep equivalents are essential. I’ll have to try out Taglibs.

  2. Thank-you for sharing this Shaun. This is very useful. I have been using VIM on Grails projects; but not so systematically. I am definitely going to try this.

    Looking forward to part 2, and beyond !

  3. You don’t have to modify the taglist plugin itself. This is not desired if you’re using submodules inside your bundle directory. Just add this to your vimrc or any other initialization file:

    let tlist_groovy_settings = ‘groovy;p:package;c:class;i:interface;’ .
    ‘f:function;v:variables’

    But thanks for pointing out how to make taglist work for Groovy too 🙂

  4. Shaun Jurgemeyer says:

    Peter,

    I tried Ack for a little while. It might be slightly faster, but I felt like EasyGrep had a little more functionality “out of the box”. I’m guessing most of EasyGrep’s functionality can be mimicked with Ack, but I didn’t take it that far

  5. Shaun Jurgemeyer says:

    Rodrigo,
    Thanks for the tip on taglist. That’s a lot cleaner then the way I did it.

  6. Shaun Jurgemeyer says:

    OK, so I’ve only been trying CtrlP for a few hours and I think I’m sold already. Thanks for pointing that one out to me!

  7. badass says:

    .ctags above wont work, there need to be [ t] and not [ t] – after creating .ctags there is a need to run ctags -R in your project directory so tag files are built and available to vim – my .vimrc have: let tlist_groovy_settings = ‘groovy;p:package;c:class;i:interface;’ . ‘f:function;v:variables’
    set tags=./tags,./TAGS,tags;~,TAGS;~

    thanks, really good job

Leave a Reply to Deepak Mittal Cancel reply

Your email address will not be published.

Related Blog Posts
Natively Compiled Java on Google App Engine
Google App Engine is a platform-as-a-service product that is marketed as a way to get your applications into the cloud without necessarily knowing all of the infrastructure bits and pieces to do so. Google App […]
Building Better Data Visualization Experiences: Part 2 of 2
If you don't have a Ph.D. in data science, the raw data might be difficult to comprehend. This is where data visualization comes in.
Unleashing Feature Flags onto Kafka Consumers
Feature flags are a tool to strategically enable or disable functionality at runtime. They are often used to drive different user experiences but can also be useful in real-time data systems. In this post, we’ll […]
A security model for developers
Software security is more important than ever, but developing secure applications is more confusing than ever. TLS, mTLS, RBAC, SAML, OAUTH, OWASP, GDPR, SASL, RSA, JWT, cookie, attack vector, DDoS, firewall, VPN, security groups, exploit, […]