views:

323

answers:

3

I've recently abandoned mouse-driven, platform-specific GUI editors and committed entirely to vim. The experience so far has been fantastic, but I'm stuck when it comes to Javascript.

The ever-popular taglist utility (using Exuberant Ctags) has been great for everything but Javascript. With the language's overly-free form and structure, taglist could only pick up a handful of functions when I opened it up -- only those defined in the format:

function FUNCNAME (arg1, arg2) {

but no variables or function objects defined like:

var myFunc = function (arg1, arg2) {

So I googled a bit and found the following definition set for ctags, which I put in my ~/.ctags file:

--langdef=js
--langmap=js:.js
--regex-js=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\{/\1/,object/
--regex-js=/([A-Za-z0-9._$()]+)[ \t]*[:=][ \t]*function[ \t]*\(/\1/,function/
--regex-js=/function[ \t]+([A-Za-z0-9._$]+)[ \t]*([^])])/\1/,function/
--regex-js=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\[/\1/,array/
--regex-js=/([^= ]+)[ \t]*=[ \t]*[^""]'[^'']*/\1/,string/
--regex-js=/([^= ]+)[ \t]*=[ \t]*[^'']"[^""]*/\1/,string/

After that, running ctags from the command line was fantastic. It found every function and object that I needed it to find.

The problem is that the taglist.vim plugin isn't seeing those new results. When I open my javascript file in vim and hit :TlistToggle, I get the exact same meager handful of functions I got before. I hit 'u' to update the list, with no effect.

Digging into taglist.vim, I found this:

" java language
let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
                               \ 'f:field;m:method'

" javascript language
let s:tlist_def_javascript_settings = 'javascript;f:function'

...which implies we're only looking at one specific kind of output from the ctags utility for javascript. Unfortunately, I'm not savvy enough with taglist or vim in general (yet) to discover what change I can make to get all those wonderful ctags command-line results to show up in vim.

Help appreciated!

A: 

I've not used javascript or taglist much, but looking through :help taglist-extend, it looks like your definitions (listed above) rename the javascript output to js, so you'll probably need something like (in your vimrc):

let tlist_js_settings = 'js;f:function;m:method'

This is assuming that the ctags 'kind' is 'f' for function and 'm' for method. Have a look at your tags file and see what the 'kind' column looks like. By way of example, my C code tags file includes this line:

ADC_CR1_AWDCH_0 .\LibraryModules\CMSIS\Headers\stm32f10x.h 2871;" d

This is a #define of a symbol ADC_CR1_AWDCH_0, which is in the listed file at line 2871. The 'd' is the ctags 'kind' for a defined name. Hopefully that will give you enough to get you going.

As an aside, I'm not sure whether the override will work correctly, so it might be worth naming your file 'myfile.mjs' and changing your langmap to js:.mjs until it's working properly. Then at least you'll know whether your problems are associated with misidentification of files or the actual parsing.

Al
+7  A: 

Got it! I dove into the taglist.vim code for awhile, and this is what I found:

taglist.vim forces ctags to use the same filetype that vim is using. So even though the ~/.ctags snippet I found via google is assigning my much-needed definitions to the new "js" language and applying it to files that end in .js, taglist is forcing ctags into using the "JavaScript" filetype that vim is using -- which is built right into ctags already.

The solution is to change the ~/.ctags file from what I've posted above to this:

--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*new[ \t]+Object\(/\1/o,object/
--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\{/\1/o,object/
--regex-JavaScript=/([A-Za-z0-9._$()]+)[ \t]*[:=][ \t]*function[ \t]*\(/\1/f,function/
--regex-JavaScript=/function[ \t]+([A-Za-z0-9._$]+)[ \t]*\([^\]\)]*\)/\1/f,function/
--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*new[ \t]+Array\(/\1/a,array/
--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\[/\1/a,array/
--regex-JavaScript=/([^= ]+)[ \t]*=[ \t]*[^""]'[^'']*/\1/s,string/
--regex-JavaScript=/([^= ]+)[ \t]*=[ \t]*[^'']"[^""]*/\1/s,string/

which alters the pre-existing JavaScript language definition directly, rather than creating a new language definition within ctags. Now, when taglib forces vim's registered filetype, the new definitions are used. Also missing from the previously posted ~/.ctags lines was the "kind" letter that Al mentioned in his answer, so those are included in my updated version as well.

From there, drop the following into your ~/.vimrc to activate the new types:

let g:tlist_javascript_settings = 'javascript;s:string;a:array;o:object;f:function'

All-in-all, the new regex lines aren't perfect -- they'll definitely need some tweaking to avoid a lot of false positives, and it might be nice to separate out constants and such. But now, at least, I have the ability to do that :).

Edit: Added instructions on how to activate types without editing the plugin, and vastly improved the main ctags function regex to avoid some false-positives.

Edit 2: Added more array and object definitions to the ctags regex.

Tom Frost
A: 

I ran into this post on a google search, and although your findings are excellent, I think we can improve them. This is the results of a bit of hacking on your solution:

.ctags

--regex-JavaScript=/^var[ \t]+([a-zA-Z0-9._$]+) = \[/\1/a,array/
--regex-JavaScript=/^var[ \t]+([a-zA-Z0-9._$]+) = \{/\1/o,object/
--regex-JavaScript=/^var[ \t]+([a-zA-Z0-9._$]+) = (^{^[)+/\1/r,var/
--regex-JavaScript=/(this\.)?([A-Za-z0-9._$()]+)[ \t]*[:=][ \t]*function[\t]*\(\)/\2/u,function/
--regex-JavaScript=/^[ \t]*function ([A-Za-z0-9]*)/\1/u,function/

.vimrc

let g:tlist_javascript_settings = 'javascript;r:var;s:string;a:array;o:object;u:function'

This gets rid of a few more false positives, and adds some more features in, as a tradeoff for getting rid of some of the more problematic regexes. I'll keep updating if I find I need more.

Edit: I've gotten everything working really nicely now; I feel like this result is solid. The only major deficiency is that it doesn't work on comma separated variable definitions. That seems particularly nasty. Maybe another day. :)

Note also that I changed the .vimrc. This isn't because I'm a freak; it's because somehow taglist or ctags or something has some default values set, and if you don't change it, then you get a lot of doubles where functions and vars are concerned, which really drives me insane (I pay super attention to detail.. :P )

thedayturns