1

Are there any features/plugins/external tools which can be used to get tag navigation that understands RequireJS imports?

4

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. – romainl Jun 28 '15 at 8:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.