Ctags for JavaScript and Less

This is how to achieve “JumpToDefinition” in Vim, for JS and Less files.

I’ve tested a lot of plugins, most famous ones being:


  • Result: creates a bar of definitions, ideally


  • Advantage: a clear list of definitions to be toggled on and off.
  • Disadvantage: in reality, Tagbar rarely works that smoothly. It depends on exuberant-ctags rather than ctags to generate tags, and exuberant-ctags doesn’t work well with modern Javascript, including RequireJS and prototypes. For example, a js file wrapped in Require() yields an empty list.


  • Result:

  • Advantage: navigates through file, buffer, mru (most recently used), tag… easily
  • Disadvantage: can’t directly place cursor upon word and Ctrl-] to definition. You’ll need to open the search panel and type in the keywords. But its fuzzy search is really nice. Besides, sometimes the fire buffer just can’t find the file I need (in both current path and search by file name).

And a workaround for Jumping to CSS definition:

  • add this in .vimrc:
function! JumpToCSS()
  let id_pos = searchpos("id", "nb", line('.'))[1]
  let class_pos = searchpos("class", "nb", line('.'))[1]

  if class_pos > 0 || id_pos > 0
    if class_pos < id_pos
      execute ":vim '#".expand('<cword>')."' **/*.less"
    elseif class_pos > id_pos
      execute ":vim '.".expand('<cword>')."' **/*.less"

nnoremap <leader>] :call JumpToCSS()<CR>zz
  • Result: place mouse on html class/id and directly jump to definition in less/css
  • Advantage: fast in pressing the keys.
  • Disadvantage:
    1. slow in responding if your Less files are large (approximately 0.5s in my case)
    2. can’t navigate through occurrences by :tn, :tp, :tjump (:ts), :tag…

And there’s also the native Ctag:

which, added support for JavaScript and Less, is actually quite nice to go with CtrlP. Add these to your ctags file (usually placed ~/.ctags on Mac):


--regex-less=/^[ t]*.([A-Za-z0-9_-]+)/1/c,class,classes/
--regex-less=/^[ t]*#([A-Za-z0-9_-]+)/1/i,id,ids/
--regex-less=/^[ t]*(([A-Za-z0-9_-]+[ tn,]+)+){/1/t,tag,tags/
--regex-less=/^[ t]*@medias+([A-Za-z0-9_-]+)/1/m,media,medias/

--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/

The first part is files to be excluded, followed by rules for generating tags for less/js files.

Solution 1: Pure Ctags

  • update .ctags file
  • generate Ctags with :!ctags -R .
  •  jump to definition with Ctrl+]
  • navigate with :tn (next) :tp (previous) and all sorts or awesomeness detailed in :help tag

Solution 2: Ctags + CtrlP

  • update .ctags file
  • get CtrlP plugin
  • generate Ctags with :!ctags -R .
  • navigate with CtrlP



Leave a Reply