Are there any features/plugins/external tools which can be used to get tag navigation that understands RequireJS imports?
1 Answer
Built-in definition search
Vim is able to follow "includes" for completion and for navigation. What constitutes an "include" can be defined with the 'include'
option.
Sadly, Vim's include mechanism is not flexible enough to work with RequireJS's standard way to define multiple dependencies in a same line:
define(foo, ["bar", "module/baz"], function(Bar, Baz) {
but we can sort of work around that limitation by putting every dependency on its own line (which is a lot cleaner anyway… I'm looking at you, K. ;-)):
define(foo, [
"bar",
"module/baz"
], function(Bar, Baz) {
It is possible (but not really straightforward) to craft an 'include'
value that deals with the notation above and the new import
from ES6 or its bastard copycats found in recent libraries like RequireJS.
Adding the code below to ~/.vim/after/ftplugin/javascript.vim
should give you a reasonably working setup:
setlocal define=^\\s*\\(function\\\|var\\\|define\\)[('\"]\\{-\\}
setlocal suffixesadd+=.js
if &expandtab
let &l:include = '^\s\{,' . &shiftwidth . "}\\(import[^'\\\"]*\\)*['\\\"]\\zs[^'\\\"]*\\ze"
else
let &l:include = "^\t\\(import[^'\\\"]*\\)*['\\\"]\\zs[^'\\\"]*\\ze"
endif
With that, you should be able to do:
:dlist foobar
in this buffer:
define(main, [
"imports/imports"
], function(imports) {
return "main";
});
and get a list like this:
imports/imports.js
1: 2 function foobar() {
Basically, Vim can now search for stuff in the current buffer and imported files which will make the features below work with your code:
:dlist foo list possible definitions of foo
[D jump to definition of current word
:ilist bar list occurrences of bar
[I jump to first occurrence of current word
gf jump to include under the cursor
<C-n>/<C-p> keyword completion from many sources including includes
This can be slower than tag-based navigation but it is often a lot more accurate: :dlist foo
will only list the foo
that are relevant to your current context (from the current buffer, the files "included" in the current file and the files included in those "includes") whereas tselect foo
will list every foo
in your project.
Resources
:help include-search
:help 'include'
:help 'suffixesadd'
:help 'define'
Tags
Ctags doesn't follow includes: it merely indexes whatever indexable files it finds where you tell it to search. Tag search being a bit naïve, it can be cumbersome to find the right tag in large projects with many dependencies. This is not a JavaScript issue, though, the same applies to every supported language.
Cscope follows includes in some languages and is generally smarter than ctags but its "oldschool" JavaScript parser obviously doesn't care about your fancy ES6 imports or RequireJS dependencies. Like ctags, it can perfectly be used to search methods and such across your project but don't expect anything "smart".
Tern is a code-analysis engine designed to work with "modern" JavaScript so you can expect it to find your definitions and usages, even in large projects. I find it too slow but it is really good at what it does.
Resources
:help tags
:help ctags
:help cscope
-
If you decide to take "definition search" for a ride, you'll probably find this plugin of mine handy.– romainlCommented Jun 28, 2015 at 8:39