Commits

Audrius Kažukauskas  committed cfd9a6c

Upgrade to easytags.vim 3.1.2.

  • Participants
  • Parent commits c49e8c9

Comments (0)

Files changed (3)

File autoload/xolox/easytags.vim

 " Vim script
 " Author: Peter Odding <peter@peterodding.com>
-" Last Change: April 18, 2013
+" Last Change: April 20, 2013
 " URL: http://peterodding.com/code/vim/easytags/
 
-let g:xolox#easytags#version = '2.8.2'
+let g:xolox#easytags#version = '3.1.2'
+
+call xolox#misc#compat#check('easytags', 1)
 
 " Public interface through (automatic) commands. {{{1
 
   endif
 endfunction
 
+" The localtime() when the CursorHold event last fired.
+let s:last_automatic_run = 0
+
 function! xolox#easytags#autoload(event) " {{{2
   try
     if a:event =~? 'cursorhold'
       " Only for the CursorHold automatic command: check for unreasonable
       " &updatetime values. The minimum value 4000 is kind of arbitrary
-      " (apart from being Vim's default) so I made it configurable:
+      " (apart from being Vim's default) so I made it configurable.
       let updatetime_min = xolox#misc#option#get('easytags_updatetime_min', 4000)
       if &updatetime < updatetime_min
-        " Other plug-ins may lower &updatetime in certain contexts, e.g.
-        " insert mode in the case of the neocomplcache plug-in. The following
-        " option (disabled by default unless neocomplcache is loaded) silences
-        " the warning and makes the easytags plug-in skip the update and
-        " highlight. When the &updatetime is restored to a reasonable value
-        " the plug-in resumes.
-        if xolox#misc#option#get('easytags_updatetime_autodisable', exists('g:loaded_neocomplcache'))
-          return
+        if s:last_automatic_run == 0
+          " Warn once about the low &updatetime value.
+          call xolox#misc#msg#warn("easytags.vim %s: The 'updatetime' option has an unreasonably low value, so I'll start compensating (see the easytags_updatetime_min option).", g:xolox#easytags#version)
+          let s:last_automatic_run = localtime()
         else
-          call xolox#misc#msg#warn("easytags.vim %s: I'm being executed every %i milliseconds! Please :set updatetime=%i. To find where 'updatetime' was changed execute ':verb set ut?'", g:xolox#easytags#version, &updatetime, updatetime_min)
+          let next_scheduled_run = s:last_automatic_run + max([1, updatetime_min / 1000])
+          if localtime() < next_scheduled_run
+            " It's not our time yet; wait for the next event.
+            call xolox#misc#msg#debug("easytags.vim %s: Skipping this beat of 'updatetime' to compensate for low value.", g:xolox#easytags#version)
+            return
+          else
+            call xolox#misc#msg#debug("easytags.vim %s: This is our beat of 'updatetime'!", g:xolox#easytags#version)
+            let s:last_automatic_run = localtime()
+          endif
         endif
       endif
     endif
     let tagsfile = xolox#easytags#get_tagsfile()
     let firstrun = !filereadable(tagsfile)
     let cmdline = s:prep_cmdline(cfile, tagsfile, firstrun, a:filenames, context)
-    let output = s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline)
+    let [output, has_updates] = s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline)
     if !firstrun
+      if !has_updates
+        return 1
+      endif
       if have_args && !empty(g:easytags_by_filetype)
         " TODO Get the headers from somewhere?!
         call s:save_by_filetype(a:filter_tags, [], output, context)
 endfunction
 
 function! s:prep_cmdline(cfile, tagsfile, firstrun, arguments, context) " {{{3
-  let program = xolox#misc#option#get('easytags_cmd')
-  let cmdline = [program, '--fields=+l', '--c-kinds=+p', '--c++-kinds=+p']
-  if a:firstrun
-    call add(cmdline, xolox#misc#escape#shell('-f' . a:tagsfile))
-    call add(cmdline, '--sort=' . (&ic ? 'foldcase' : 'yes'))
+  let languages = xolox#misc#option#get('easytags_languages', {})
+  let ctags_language_name = xolox#easytags#to_ctags_ft(&filetype)
+  let language = get(languages, ctags_language_name, {})
+  if empty(language)
+    let program = xolox#misc#option#get('easytags_cmd')
+    let cmdline = [program, '--fields=+l', '--c-kinds=+p', '--c++-kinds=+p']
+    if a:firstrun
+      call add(cmdline, xolox#misc#escape#shell('-f' . a:tagsfile))
+      call add(cmdline, '--sort=' . (&ic ? 'foldcase' : 'yes'))
+    else
+      call add(cmdline, '--sort=no')
+      call add(cmdline, '-f-')
+    endif
+    if xolox#misc#option#get('easytags_include_members', 0)
+      call add(cmdline, '--extra=+q')
+    endif
   else
-    call add(cmdline, '--sort=no')
-    call add(cmdline, '-f-')
-  endif
-  if xolox#misc#option#get('easytags_include_members', 0)
-    call add(cmdline, '--extra=+q')
+    let program = get(language, 'cmd', xolox#misc#option#get('easytags_cmd'))
+    if empty(program)
+      call xolox#misc#msg#warn("easytags.vim %s: No 'cmd' defined for language '%s', and also no global default!", g:xolox#easytags#version, ctags_language_name)
+      return
+    endif
+    let cmdline = [program] + get(language, 'args', [])
+    if a:firstrun
+      call add(cmdline, xolox#misc#escape#shell(get(language, 'fileoutput_opt', '-f') . a:tagsfile))
+    else
+      call add(cmdline, xolox#misc#escape#shell(get(language, 'stdout_opt', '-f-')))
+    endif
   endif
   let have_args = 0
   if a:cfile != ''
     if xolox#misc#option#get('easytags_autorecurse', 0)
-      call add(cmdline, '-R')
+      call add(cmdline, empty(language) ? '-R' : xolox#misc#escape#shell(get(language, 'recurse_flag', '-R')))
       call add(cmdline, xolox#misc#escape#shell(a:cfile))
     else
-      " TODO Should --language-force distinguish between C and C++?
-      " TODO --language-force doesn't make sense for JavaScript tags in HTML files?
-      let filetype = xolox#easytags#to_ctags_ft(&filetype)
-      call add(cmdline, xolox#misc#escape#shell('--language-force=' . filetype))
+      if empty(language)
+        " TODO Should --language-force distinguish between C and C++?
+        " TODO --language-force doesn't make sense for JavaScript tags in HTML files?
+        let filetype = xolox#easytags#to_ctags_ft(&filetype)
+        call add(cmdline, xolox#misc#escape#shell('--language-force=' . filetype))
+      endif
       call add(cmdline, xolox#misc#escape#shell(a:cfile))
     endif
     let have_args = 1
 
 function! s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline) " {{{3
   let lines = []
+  let has_updates = 1
   if a:cmdline != ''
     call xolox#misc#msg#debug("easytags.vim %s: Executing %s.", g:xolox#easytags#version, a:cmdline)
     try
       let lines = xolox#shell#execute(a:cmdline, 1)
+      let has_updates = a:firstrun || s:has_updates(a:cfile, join(lines, "\n"))
     catch /^Vim\%((\a\+)\)\=:E117/
       " Ignore missing shell.vim plug-in.
       let output = system(a:cmdline)
         throw printf(msg, fnamemodify(a:tagsfile, ':~'), strtrans(output))
       endif
       let lines = split(output, "\n")
+      let has_updates = a:firstrun || s:has_updates(a:cfile, output)
     endtry
     if a:firstrun
       if a:cfile != ''
       return []
     endif
   endif
-  return xolox#easytags#parse_entries(lines)
+  return [xolox#easytags#parse_entries(lines), has_updates]
 endfunction
 
+" Vim 7.3 now has the sha256() function. We use it below to recognize when the
+" tags haven't changed from the last time we ran Exuberant Ctags on a file; in
+" this case the tags file doesn't have to be written to disk which makes the
+" plug-in much faster for a very common case.
+
+let s:fingerprints = {}
+
+function! s:has_updates(cfile, output)
+  if empty(a:cfile)
+    " The cache doesn't work when tags aren't created for the current file.
+    return 1
+  endif
+  let fingerprint = s:get_fingerprint(a:cfile, a:output)
+  call xolox#misc#msg#debug("easytags.vim %s: Fingerprint of tags in %s is %s.", g:xolox#easytags#version, a:cfile, string(fingerprint))
+  if !empty(fingerprint) && get(s:fingerprints, a:cfile, '') ==# fingerprint
+    call xolox#misc#msg#debug("easytags.vim %s: The fingerprint didn't change! We can take a shortcut :-)", g:xolox#easytags#version)
+    return 0
+  endif
+  let s:fingerprints[a:cfile] = fingerprint
+  return 1
+endfunction
+
+if exists('*sha256')
+  function! s:get_fingerprint(cfile, output)
+    return sha256(a:output)
+  endfunction
+else
+  function! s:get_fingerprint(cfile, output)
+    " Don't want to re-implement a costly hashing function in Vimscript. Just
+    " handle files that never had any tags.
+    if empty(a:output)
+      return get(s:fingerprints, a:cfile, 1)
+    else
+      return ''
+    endif
+  endfunction
+endif
+
 function! s:filter_merge_tags(filter_tags, tagsfile, output, context) " {{{3
   let [headers, entries] = xolox#easytags#read_tagsfile(a:tagsfile)
   let filters = []
 function! xolox#easytags#supported_filetypes() " {{{2
   if !exists('s:supported_filetypes')
     let starttime = xolox#misc#timer#start()
-    let command = g:easytags_cmd . ' --list-languages'
-    try
-      let listing = xolox#shell#execute(command, 1)
-    catch /^Vim\%((\a\+)\)\=:E117/
-      " Ignore missing shell.vim plug-in.
-      let listing = split(system(command), "\n")
-      if v:shell_error
-        let msg = "Failed to get supported languages! (output: %s)"
-        throw printf(msg, strtrans(join(listing, "\n")))
-      endif
-    endtry
-    let s:supported_filetypes = map(copy(listing), 's:check_filetype(listing, v:val)')
+    let listing = []
+    if !empty(g:easytags_cmd)
+      let command = g:easytags_cmd . ' --list-languages'
+      try
+        let listing = xolox#shell#execute(command, 1)
+      catch /^Vim\%((\a\+)\)\=:E117/
+        " Ignore missing shell.vim plug-in.
+        let listing = split(system(command), "\n")
+        if v:shell_error
+          let msg = "Failed to get supported languages! (output: %s)"
+          throw printf(msg, strtrans(join(listing, "\n")))
+        endif
+      endtry
+    endif
+    let s:supported_filetypes = map(copy(listing) + keys(xolox#misc#option#get('easytags_languages', {})), 's:check_filetype(listing, v:val)')
     let msg = "easytags.vim %s: Retrieved %i supported languages in %s."
     call xolox#misc#timer#stop(msg, g:xolox#easytags#version, len(s:supported_filetypes), starttime)
   endif

File doc/easytags.txt

   2. The |:HighlightTags| command
  4. Options                                                   |easytags-options|
   1. The |g:easytags_cmd| option
-  2. The |g:easytags_file| option
-  3. The |g:easytags_dynamic_files| option
-  4. The |g:easytags_by_filetype| option
-  5. The |g:easytags_always_enabled| option
-  6. The |g:easytags_on_cursorhold| option
-  7. The |g:easytags_updatetime_min| option
-  8. The |g:easytags_updatetime_autodisable| option
+  2. The |g:easytags_languages| option
+  3. The |g:easytags_file| option
+  4. The |g:easytags_dynamic_files| option
+  5. The |g:easytags_by_filetype| option
+  6. The |g:easytags_always_enabled| option
+  7. The |g:easytags_on_cursorhold| option
+  8. The |g:easytags_updatetime_min| option
   9. The |g:easytags_auto_update| option
   10. The |g:easytags_auto_highlight| option
   11. The |g:easytags_autorecurse| option
 >
     :let g:easytags_cmd = '/usr/local/bin/ctags'
 
+If you rely entirely on language-specific configuration and don't have a
+general ctags program, set this to the empty string.
+
+-------------------------------------------------------------------------------
+The *g:easytags_languages* option
+
+Exuberant Ctags supports many languages and can be extended via regular
+expression patterns, but for some languages separate tools with
+ctags-compatible output exist (e.g. jsctags [9] for Javascript). To use these,
+the executable and its arguments must be configured:
+>
+    let g:easytags_languages = {
+    \   'language': {
+    \     'cmd': g:easytags_cmd,
+    \       'args': [],
+    \       'fileoutput_opt': '-f',
+    \       'stdout_opt': '-f-',
+    \       'recurse_flag': '-R'
+    \   }
+    \}
+
+Each key is a special language definition. The key is in the notation of ctags
+in lowercase; you still need to use 'xolox#easytags#map_filetypes()' to map
+this to Vim's filetypes, if necessary.
+
+Above snippets shows the defaults; you only need to specify options that
+differ.
+
 -------------------------------------------------------------------------------
 The *g:easytags_file* option
 
 
 Vim has a setting which influences how often the plug-in is automatically
 executed. When this setting is too low, the plug-in can break. For this reason
-the plug-in warns you when |'updatetime'| is lower than 4000 milliseconds. If
-you really want the plug-in to be executed more than once every 4 seconds
-(without a warning) you can lower the minimum acceptable updatetime by setting
-this option (number of milliseconds).
+the plug-in compensates by keeping track of when it was last executed. You'll
+get one warning when the plug-in first notices the low value, after that it
+will shut up. The default value of this option is 4000 milliseconds (4
+seconds).
 
--------------------------------------------------------------------------------
-The *g:easytags_updatetime_autodisable* option
-
-Other plug-ins may lower the |'updatetime'| value in certain contexts, e.g.
-insert mode in the case of the neocomplcache [9] plug-in. By setting this
-option to 1 (true) you can configure the easytags plug-in so that it doesn't
-give warnings about the updatetime option but instead skip updating and
-highlighting while the updatetime is set too low. When the updatetime is
-restored to a reasonable value the plug-in resumes.
+If you really want the plug-in to be executed more than once every 4 seconds
+you can lower the minimum acceptable updatetime by setting this option (as the
+number of milliseconds) however note that subsecond granularity is not
+supported.
 
 -------------------------------------------------------------------------------
 The *g:easytags_auto_update* option
 [6] http://peterodding.com/code/vim/downloads/easytags.zip
 [7] http://peterodding.com/code/vim/shell/
 [8] http://en.wikipedia.org/wiki/Dynamic-link_library
-[9] http://www.vim.org/scripts/script.php?script_id=2620
+[9] https://npmjs.org/package/jsctags
 [10] http://en.wikipedia.org/wiki/Symbolic_link
 [11] http://en.wikipedia.org/wiki/Hard_link
 [12] http://en.wikipedia.org/wiki/Canonicalization

File plugin/easytags.vim

 " Vim plug-in
 " Author: Peter Odding <peter@peterodding.com>
-" Last Change: October 29, 2011
+" Last Change: April 19, 2013
 " URL: http://peterodding.com/code/vim/easytags/
 " Requires: Exuberant Ctags (http://ctags.sf.net)
 
     endif
   else
     " Exuberant Ctags can be installed under multiple names:
-    "  - On Ubuntu Linux, Exuberant Ctags is installed as `ctags'.
+    "  - On Ubuntu Linux, Exuberant Ctags is installed as `ctags-exuberant'
+    "    (and possibly `ctags' but that one can't be trusted :-)
     "  - On Debian Linux, Exuberant Ctags is installed as `exuberant-ctags'.
     "  - On Free-BSD, Exuberant Ctags is installed as `exctags'.
     " IIUC on Mac OS X the program /usr/bin/ctags is installed by default but
     " some frustration the plug-in will search the path and consider every
     " possible location, meaning that as long as Exuberant Ctags is installed
     " in the $PATH the plug-in should find it automatically.
-    for program in xolox#misc#path#which('ctags', 'exuberant-ctags', 'exctags')
+    for program in xolox#misc#path#which('exuberant-ctags', 'ctags-exuberant', 'ctags', 'exctags')
       if s:CheckCtags(program, a:version)
         let g:easytags_cmd = program
         return 1