"Jump to Definition" in Vim
Did you know Vim has a few built-in features designed to help with the "Jump to Definition" action you see in most IDEs?
Did you know Vim has a few built-in features designed to help with the "Jump to Definition" action you see in most IDEs?
Level 1: include and define
Since Vim is a "dumb" editor (that is, it doesn't do any static analysis on your text), you'd expect a "Jump to Definition" feature that relies on a simple text search.
include
and define
are two mechanics to help facilitate that.
Include
include
is a pattern to help Vim understand which files are relevant when performing code searches.
Let's take a look at the default value:
:let &include = '^\s*#\s*include'
It's trying to catch a pattern that looks like #include <filename>
.
That makes sense! In C, that's how you tell the preprocessor, "I need code in <filename> in this position". If you want to jump to the definition of a macro or whatnot, you'd want to look into all included files.
A good include
pattern is crucial to making this work. For example, for Javascript filetypes, I have:
:let &l:include = 'from\|require'
Now I can look for any keyword appearing in any required files!
Demo: asciinema
Further reading: :help include-search
in Vim: hotlink.
Define
define
is a pattern to help Vim understand which parts of your code are definitions.
Let's take a look at the default value:
let &define = '^\s*#\s*define'
In this case, it's looking for something that looks like #define <keyword>
.
This time, it seems to be looking for preprocessor macros. Makes sense, although since there are languages for which no analogue exists (e.g. Javascript), we can repurpose it to match variable definitions instead.
For my Javascript filetype, I have:
let &l:define = '\v(export\s+(default\s+)?)?(var|let|const|function|class)|export\s+'
A bit convoluted, but at least it can catch different permutations such as export default function <name>
and const <name> = ...
.
Now I can jump to definitions in required files!
Demo: asciinema
Further reading: :help definition-search
in Vim: hotlink.
Level 2: Ctags
Vim also has builtin support for ctags. Ctags tags important parts of your code so you can jump around the project without the restriction of include
files.
To work with ctags, all you have to do is generate a tags
file (preferably in project root):
$ ctags -R .
Then open Vim in the same directory. You can now jump to tags!
Demo: asciinema
Universal ctags is an often recommended ctags implementation, since it's actively maintained and has good language coverage.
For Javascript filetypes, I actually rely on es-ctags, which uses the Tern static analysis engine to generate a tags file.
Bonus: maintaining the tags file
Several people have different techniques to keep the tags file up-to-date as you edit.
Tim Pope has a blog post detailing his workflow with Git hooks.
A lot of people also love the popular Gutentags plugin.
I've read some people rely on their task/build runner for such a task.
I myself rely on a simple file watcher that re-runs ctags and appends new tags to the file:
$ watchrun src -- es-ctags -a
Further reading: :help tags-and-searches
in Vim: hotlink.
Level 3: Static code analysis
The smartest "Jump to Definition" mechanic would definitely rely on parsing and analyzing the code itself, which is what static analysis engines are for.
There are multiple plugins out there that work to integrate with these engines, e.g. tern_for_vim for Javascript. Try and find one for your language of choice, or ask some of the helpful chaps in r/vim or #vim on freenode!
Many people (myself included) are also hopeful for the Language Server Protocol, which aims to provide a standard for text editors and static analysis engines to work together.
About the Author
Written by Ian Emnace