Despite my failed experiment with evil-mode back in January, I wound up switching over to evil-powered Emacs full time earlier this summer. I love having modal editing combined with truly deep extensibility, and I’ve been focusing my tweaking on changes that let Emacs help me explore and understand code faster.
Ctags is a program that can parse code in many different language and generate an index of defined symbols—stuff like class names, method names, constants and so on. Text editors can be configured to use this index to do things like jump to where a particular symbol is defined (instead of just grepping for where the symbol occurs).
Here’s how I set up Ctags in Emacs.
Install Ctags
OS X ships with an older version of Ctags that can’t generate a tags index in the format that Emacs expects. I installed the latest version via Homebrew:
Tag Generation
Tags can be generated on the command line pretty easily—ctags -Re
will recursively parse and index all files below the current directory, in Emacs format. However, it’s handy to be able to regenerate them from within Emacs, especially if you’re switching git branches and want to quickly purge stale tags. The following lets me that do for the current projectile project with M-x regenerate-tags
:
Rather than re-running this on the entire project whenever a file changes, I used the ctags-update
package to do so incrementally on save. I’m just enabling it for when I’m in enhanced-ruby-mode
right now.
Tag Navigation
Now that we can generate and update a tags file, we can start using it to explore our code faster. I’ve found the following keys in normal mode:
gf
goes to the first match for the tag under the cursor. If I’ve got the symbolUser
under the cursor, I can hitgf
and go to where theUser
class or module is defined.gn
goes to the next match—if there are multiple matching tags (e.g. I’ve got multipleUser
classes in the same project), this cycles to the next one.gb
pops me back to where I was before jumping.
Tag Search
Using a fuzzy matcher to search through the tags index is a great way to zip around a codebase. I use Helm for as-you-type filtering for all sorts of things—emacs functions, project files, and now, tags! I bound Helm’s built-in tag filter to <leader>y
:
The default behavior of the filtering left something to be desired, however. Matching tag candidate were sorted alphabetically, which mean that if I was looking for the module Searchable, the results would look like this (with the top item selected):
What I really wanted was the closest item to my search to be on top. As it turns out, the shortest string that still matches the filtering text winds up being a decent hueristic for this. I did a bit of poking around in the helm-etags source, and found an empty function that’s meant to allow users to define their own custom behavior for Helm sources. Perfect!
Now, when I run the above search, the module I was looking for is on top and selected by default:
There’s still more to tweak—the Emacs motto, I think—but I’m pretty pleased with my tags setup so far.