changeset 169:95afd985a4c3

Merge pull request #97 from GitHub.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 19 Feb 2017 20:00:13 -0800
parents 34c57ad6eb45 (diff) e59321cbaff7 (current diff)
children 18df731b1563
files autoload/gutentags.vim autoload/gutentags/ctags.vim
diffstat 7 files changed, 406 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/autoload/gutentags.vim	Mon Oct 10 19:04:05 2016 -0300
+++ b/autoload/gutentags.vim	Sun Feb 19 20:00:13 2017 -0800
@@ -21,6 +21,11 @@
 
 " Throw an exception message.
 function! gutentags#throw(message)
+    throw "gutentags: " . a:message
+endfunction
+
+" Throw an exception message and set Vim's error message variable.
+function! gutentags#throwerr(message)
     let v:errmsg = "gutentags: " . a:message
     throw v:errmsg
 endfunction
@@ -68,6 +73,17 @@
     return g:gutentags_res_dir . a:filename
 endfunction
 
+" Returns whether a path is rooted.
+if has('win32') || has('win64')
+function! gutentags#is_path_rooted(path) abort
+  return len(a:path) >= 2 && a:path[1] == ':'
+endfunction
+else
+function! gutentags#is_path_rooted(path) abort
+  return !empty(a:path) && a:path[0] == '/'
+endfunction
+endif
+
 " }}}
 
 " Gutentags Setup {{{
@@ -109,11 +125,12 @@
         let l:markers = get(g:gutentags_file_list_command, 'markers', [])
         if type(l:markers) == type({})
             for [marker, file_list_cmd] in items(l:markers)
-                if getftype(a:path . '/' . marker) != ""
+                if !empty(globpath(a:path, marker, 1))
                     return gutentags#validate_cmd(file_list_cmd)
                 endif
             endfor
         endif
+        return get(g:gutentags_file_list_command, 'default', "")
     endif
     return ""
 endfunction
@@ -121,7 +138,7 @@
 " Finds the first directory with a project marker by walking up from the given
 " file path.
 function! gutentags#get_project_root(path) abort
-    if g:gutentags_project_root_finder
+    if g:gutentags_project_root_finder != ''
         return call(g:gutentags_project_root_finder, [a:path])
     endif
 
@@ -137,7 +154,7 @@
     endif
     while l:path != l:previous_path
         for root in l:markers
-            if getftype(l:path . '/' . root) != ""
+            if !empty(globpath(l:path, root))
                 let l:proj_dir = simplify(fnamemodify(l:path, ':p'))
                 let l:proj_dir = gutentags#stripslash(l:proj_dir)
                 if l:proj_dir == ''
@@ -173,6 +190,9 @@
 
 " Generate a path for a given filename in the cache directory.
 function! gutentags#get_cachefile(root_dir, filename) abort
+    if gutentags#is_path_rooted(a:filename)
+        return a:filename
+    endif
     let l:tag_path = gutentags#stripslash(a:root_dir) . '/' . a:filename
     if g:gutentags_cache_dir != ""
         " Put the tag file in the cache dir instead of inside the
@@ -195,13 +215,15 @@
     " Don't setup gutentags for anything that's not a normal buffer
     " (so don't do anything for help buffers and quickfix windows and
     "  other such things)
-    if &buftype != ''
+    " Also don't do anything for the default `[No Name]` buffer you get
+    " after starting Vim.
+    if &buftype != '' || bufname('%') == ''
         return
     endif
 
     " Let the user specify custom ways to disable Gutentags.
-    if g:gutentags_enabled_user_func != '' &&
-                \!call(g:gutentags_enabled_user_func, [expand('%:p')])
+    if g:gutentags_init_user_func != '' &&
+                \!call(g:gutentags_init_user_func, [expand('%:p')])
         call gutentags#trace("Ignoring '" . bufname('%') . "' because of " .
                     \"custom user function.")
         return
@@ -371,7 +393,7 @@
             echom "gutentags: The tags file is already being updated, " .
                         \"please try again later."
         else
-            call gutentags#throw("Unknown queue mode: " . a:queue_mode)
+            call gutentags#throwerr("Unknown queue mode: " . a:queue_mode)
         endif
         return
     endif
--- a/autoload/gutentags/ctags.vim	Mon Oct 10 19:04:05 2016 -0300
+++ b/autoload/gutentags/ctags.vim	Sun Feb 19 20:00:13 2017 -0800
@@ -3,11 +3,34 @@
 " Global Options {{{
 
 let g:gutentags_ctags_executable = get(g:, 'gutentags_ctags_executable', 'ctags')
-let g:gutentags_tagfile = get(g:, 'gutentags_tagfile', 'tags')
-let g:gutentags_auto_set_tags = get(g:, 'gutentags_auto_set_tags', 1)
+let g:gutentags_ctags_tagfile = get(g:, 'gutentags_ctags_tagfile', 'tags')
+let g:gutentags_ctags_auto_set_tags = get(g:, 'gutentags_ctags_auto_set_tags', 1)
+
 let g:gutentags_ctags_options_file = get(g:, 'gutentags_ctags_options_file', '.gutctags')
 let g:gutentags_ctags_check_tagfile = get(g:, 'gutentags_ctags_check_tagfile', 0)
+let g:gutentags_ctags_extra_args = get(g:, 'gutentags_ctags_extra_args', [])
+let g:gutentags_ctags_post_process_cmd = get(g:, 'gutentags_ctags_post_process_cmd', '')
 
+let g:gutentags_ctags_exclude = get(g:, 'gutentags_ctags_exclude', [])
+let g:gutentags_ctags_exclude_wildignore = get(g:, 'gutentags_ctags_exclude_wildignore', 1)
+
+" Backwards compatibility.
+function! s:_handleOldOptions() abort
+    let l:renamed_options = {
+                \'gutentags_exclude': 'gutentags_ctags_exclude',
+                \'gutentags_tagfile': 'gutentags_ctags_tagfile',
+                \'gutentags_auto_set_tags': 'gutentags_ctags_auto_set_tags'
+                \}
+    for key in keys(l:renamed_options)
+        if exists('g:'.key)
+            let newname = l:renamed_options[key]
+            echom "gutentags: Option 'g:'".key." has been renamed to ".
+                        \"'g:'".newname." Please update your vimrc."
+            let g:[newname] = g:[key]
+        endif
+    endfor
+endfunction
+call s:_handleOldOptions()
 " }}}
 
 " Gutentags Module Interface {{{
@@ -17,11 +40,16 @@
 
 function! gutentags#ctags#init(project_root) abort
     " Figure out the path to the tags file.
+    " Check the old name for this option, too, before falling back to the
+    " globally defined name.
+    let l:tagfile = getbufvar("", 'gutentags_ctags_tagfile',
+                \getbufvar("", 'gutentags_tagfile', 
+                \g:gutentags_ctags_tagfile))
     let b:gutentags_files['ctags'] = gutentags#get_cachefile(
-                \a:project_root, g:gutentags_tagfile)
+                \a:project_root, l:tagfile)
 
     " Set the tags file for Vim to use.
-    if g:gutentags_auto_set_tags
+    if g:gutentags_ctags_auto_set_tags
         execute 'setlocal tags^=' . fnameescape(b:gutentags_files['ctags'])
     endif
 
@@ -37,13 +65,16 @@
 function! gutentags#ctags#generate(proj_dir, tags_file, write_mode) abort
     " Get to the tags file directory because ctags is finicky about
     " these things.
-    let l:prev_cwd = gutentags#pwd()
+    let l:prev_cwd = getcwd()
+    execute "chdir " . fnameescape(a:proj_dir)
+
     let l:tags_file_exists = filereadable(a:tags_file)
 
     if l:tags_file_exists && g:gutentags_ctags_check_tagfile
         let l:first_lines = readfile(a:tags_file, '', 1)
         if len(l:first_lines) == 0 || stridx(l:first_lines[0], '!_TAG_') != 0
-            call gutentags#throw("File ".a:tags_file." doesn't appear to be ".
+            call gutentags#throwerr(
+                        \"File ".a:tags_file." doesn't appear to be ".
                         \"a ctags file. Please delete it and run ".
                         \":GutentagsUpdate!.")
             return
@@ -51,14 +82,15 @@
     endif
 
     if empty(g:gutentags_cache_dir)
-        " If we don't use the cache directory, let's just use the tag filename
-        " as specified by the user, and change the working directory to the
-        " project root.
-        " Note that if we don't do this and pass a full path, `ctags` gets
-        " confused if the paths have spaces -- but not if you're *in* the
-        " root directory.
+        " If we don't use the cache directory, we can pass relative paths
+        " around.
+        "
+        " Note that if we don't do this and pass a full path for the project
+        " root, some `ctags` implementations like Exhuberant Ctags can get
+        " confused if the paths have spaces -- but not if you're *in* the root 
+        " directory, for some reason...
         let l:actual_proj_dir = '.'
-        let l:actual_tags_file = g:gutentags_tagfile
+        let l:actual_tags_file = fnamemodify(a:tags_file, ':.')
         call gutentags#chdir(fnameescape(a:proj_dir))
     else
         " else: the tags file goes in a cache directory, so we need to specify
@@ -82,6 +114,14 @@
         else
             let l:file_list_cmd = gutentags#get_project_file_list_cmd(l:actual_proj_dir)
             if !empty(l:file_list_cmd)
+                let l:suffopts = matchstrpos(l:file_list_cmd, '///')
+                if l:suffopts[1] > 0
+                    let l:suffoptstr = strpart(l:file_list_cmd, l:suffopts[2])
+                    let l:file_list_cmd = strpart(l:file_list_cmd, 0, l:suffopts[1])
+                    if l:suffoptstr == 'absolute'
+                        let l:cmd .= ' -A'
+                    endif
+                endif
                 let l:cmd .= ' -L ' . '"' . l:file_list_cmd. '"'
             endif
         endif
@@ -91,6 +131,12 @@
             " Omit --recursive if this project uses a file list command.
             let l:cmd .= ' -o "' . gutentags#get_res_file('ctags_recursive.options') . '"'
         endif
+        if !empty(g:gutentags_ctags_extra_args)
+            let l:cmd .= ' -O '.shellescape(join(g:gutentags_ctags_extra_args))
+        endif
+        if !empty(g:gutentags_ctags_post_process_cmd)
+            let l:cmd .= ' -P '.shellescape(g:gutentags_ctags_post_process_cmd)
+        endif
         let l:proj_options_file = a:proj_dir . '/' .
                     \g:gutentags_ctags_options_file
         if filereadable(l:proj_options_file)
@@ -98,10 +144,12 @@
                         \a:proj_dir, l:proj_options_file)
             let l:cmd .= ' -o "' . l:proj_options_file . '"'
         endif
-        for ign in split(&wildignore, ',')
-            let l:cmd .= ' -x ' . '"' . ign . '"'
-        endfor
-        for exc in g:gutentags_exclude
+        if g:gutentags_ctags_exclude_wildignore
+            for ign in split(&wildignore, ',')
+                let l:cmd .= ' -x ' . '"' . ign . '"'
+            endfor
+        endif
+        for exc in g:gutentags_ctags_exclude
             let l:cmd .= ' -x ' . '"' . exc . '"'
         endfor
         if g:gutentags_pause_after_update
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/autoload/gutentags/gtags_cscope.vim	Sun Feb 19 20:00:13 2017 -0800
@@ -0,0 +1,196 @@
+" gtags_cscope module for Gutentags
+
+if !has('cscope')
+	throw "Can't enable the gtags-cscope module for Gutentags, this Vim has ".
+				\ "no support for cscope files."
+endif
+
+" Global Options {{{
+
+if !exists('g:gutentags_gtags_executable')
+	let g:gutentags_gtags_executable = 'gtags'
+endif
+
+if !exists('g:gutentags_gtags_dbpath')
+	let g:gutentags_gtags_dbpath = ''
+endif
+
+if !exists('g:gutentags_gtags_options_file')
+	let g:gutentags_gtags_options_file = '.gutgtags'
+endif
+
+if !exists('g:gutentags_gtags_cscope_executable')
+	let g:gutentags_gtags_cscope_executable = 'gtags-cscope'
+endif
+
+if !exists('g:gutentags_auto_add_gtags_cscope')
+	let g:gutentags_auto_add_gtags_cscope = 1
+endif
+
+" }}}
+
+" Gutentags Module Interface {{{
+
+let s:added_db_files = {}
+let s:job_db_files = []
+
+function! s:add_db(db_file) abort
+	if filereadable(a:db_file)
+		call gutentags#trace(
+					\"Adding cscope DB file: " . a:db_file)
+		set nocscopeverbose
+		execute 'cs add ' . fnameescape(a:db_file)
+		set cscopeverbose
+		let s:added_db_files[a:db_file] = 1
+	else
+		call gutentags#trace(
+					\"Not adding cscope DB file because it doesn't " .
+					\"exist yet: " . a:db_file)
+	endif
+endfunction
+
+function! gutentags#gtags_cscope#init(project_root) abort
+	let l:db_path = gutentags#get_cachefile(
+				\ a:project_root, g:gutentags_gtags_dbpath )
+    let l:db_path = gutentags#stripslash(l:db_path)
+    let l:db_file = l:db_path . '/GTAGS'
+    let l:db_file = gutentags#normalizepath(l:db_file)
+
+	if !isdirectory(l:db_path)
+		call mkdir(l:db_path, 'p')
+	endif
+
+	let b:gutentags_files['gtags_cscope'] = l:db_file
+
+	execute 'set cscopeprg=' . fnameescape(g:gutentags_gtags_cscope_executable)
+
+	" The combination of gtags-cscope, vim's cscope and global files is
+	" a bit flaky. Environment variables are safer than vim passing
+	" paths around and interpreting input correctly.
+	let $GTAGSDBPATH = l:db_path
+	let $GTAGSROOT = a:project_root
+
+	if g:gutentags_auto_add_gtags_cscope && !has_key(s:added_db_files, l:db_file)
+		let s:added_db_files[l:db_file] = 0
+		call s:add_db(l:db_file)
+	endif
+endfunction
+
+function! gutentags#gtags_cscope#on_job_out(job, data) abort
+	call gutentags#trace(a:data)
+endfunction
+
+function! gutentags#gtags_cscope#on_job_exit(job, exit_val) abort
+	if a:exit_val != 0
+		echom "gutentags: gtags-cscope job failed :("
+		return
+	endif
+	if g:gutentags_auto_add_gtags_cscope
+		let l:idx = 0
+		let l:db_file = ''
+		for item in s:job_db_files
+			if item[0] == a:job
+				let l:db_file = item[1]
+				break
+			endif
+			let l:idx += 1
+		endfor
+		if l:db_file != ''
+			call s:add_db(l:db_file)
+			call remove(s:job_db_files, l:idx)
+		endif
+	endif
+endfunction
+
+function! s:get_unix_cmd(for_job, proj_options, db_path) abort
+	" Vim's `job_start` gets confused with quoted arguments on Unix,
+	" prefers lists.
+	if a:for_job
+		let l:cmd = [g:gutentags_gtags_executable] + a:proj_options
+		let l:cmd += ['--incremental', a:db_path]
+		return l:cmd
+	else
+		let l:cmd = gutentags#get_execute_cmd()
+		let l:cmd .= '"' . g:gutentags_gtags_executable . '"'
+		let l:cmd .= ' ' . join(a:proj_options, ' ')
+		let l:cmd .= ' --incremental '
+		let l:cmd .= ' "' . a:db_path . '" '
+		let l:cmd .= gutentags#get_execute_cmd_suffix()
+		return l:cmd
+	endif
+endfunction
+
+function! s:get_win32_cmd(for_job, proj_options, db_path) abort
+	" Win32 prefers strings either way.
+	let l:cmd = ''
+	if !a:for_job
+		let l:cmd = gutentags#get_execute_cmd()
+	endif
+	let l:cmd .= '"' . g:gutentags_gtags_executable . '"'
+	let l:cmd .= ' ' . join(a:proj_options, ' ')
+	let l:cmd .= ' --incremental '
+	let l:cmd .= ' "' . a:db_path . '"'
+	if !a:for_job
+		let l:cmd .= ' '
+		let l:cmd .= gutentags#get_execute_cmd_suffix()
+	endif
+	return l:cmd
+endfunction
+
+function! gutentags#gtags_cscope#generate(proj_dir, db_file, write_mode) abort
+	" gtags doesn't honour GTAGSDBPATH and GTAGSROOT, so PWD and dbpath
+	" have to be set
+	let l:db_path = fnamemodify(a:db_file, ':p:h')
+
+	let l:proj_options_file = a:proj_dir . '/' . g:gutentags_gtags_options_file
+	let l:proj_options = []
+	if filereadable(l:proj_options_file)
+		let l:proj_options = readfile(l:proj_options_file)
+	endif
+
+	let l:use_jobs = has('job')
+
+	let l:prev_cwd = getcwd()
+	execute "chdir " . fnameescape(a:proj_dir)
+	try
+		if has('win32')
+			let l:cmd = s:get_win32_cmd(l:use_jobs, l:proj_options, l:db_path)
+		else
+			let l:cmd = s:get_unix_cmd(l:use_jobs, l:proj_options, l:db_path)
+		endif
+
+		call gutentags#trace("Running: " . string(l:cmd))
+		call gutentags#trace("In:      " . getcwd())
+		if !g:gutentags_fake
+			if l:use_jobs
+				let l:job_opts = {
+							\'exit_cb': 'gutentags#gtags_cscope#on_job_exit',
+							\'out_cb': 'gutentags#gtags_cscope#on_job_out',
+							\'err_cb': 'gutentags#gtags_cscope#on_job_out'
+							\}
+				let l:job = job_start(l:cmd, job_opts)
+				call add(s:job_db_files, [l:job, a:db_file])
+			else
+				if !g:gutentags_trace
+					silent execute l:cmd
+				else
+					execute l:cmd
+				endif
+				if g:gutentags_auto_add_gtags_cscope
+					call s:add_db(a:db_file)
+				endif
+			endif
+
+			let l:full_gtags_file = fnamemodify(l:db_path, ':p')
+			call gutentags#add_progress('gtags_cscope', a:db_file)
+		else
+			call gutentags#trace("(fake... not actually running)")
+		endif
+		call gutentags#trace("")
+    finally
+        " Restore the previous working directory.
+        execute "chdir " . fnameescape(l:prev_cwd)
+    endtry
+endfunction
+
+" }}}
--- a/doc/gutentags.txt	Mon Oct 10 19:04:05 2016 -0300
+++ b/doc/gutentags.txt	Sun Feb 19 20:00:13 2017 -0800
@@ -108,7 +108,7 @@
 The following commands are only available in buffers that have been found to
 belong to a project that should be managed by Gutentags. See
 |gutentags_project_root| for how Gutentags figures out the project a file
-belongs to. When not project is found (i.e. the file is not under any of the
+belongs to. When no project is found (i.e. the file is not under any of the
 known project markers), Gutentags is disabled for that buffer, and the
 following commands and remarks don't apply.
 
@@ -117,10 +117,10 @@
 "`.notags`" at the root of the project.
 
 The tag file that Gutentags creates and manages will be named after
-|gutentags_tagfile|, relative to the project's root directory. When Gutentags
-finds a valid project root, it will prepend the tag file's path to 'tags',
-unless |gutentags_auto_set_tags| is set to 0. This is to make sure Vim will use
-that file first.
+|gutentags_ctags_tagfile|, relative to the project's root directory. When
+Gutentags finds a valid project root, it will prepend the tag file's path to
+'tags', unless |gutentags_ctags_auto_set_tags| is set to 0. This is to make
+sure Vim will use that file first.
 
 If a file managed by Gutentags is opened and no tag file already exists,
 Gutentags will start generating it right away in the background, unless 
@@ -227,6 +227,18 @@
                         don't.
                         Defaults to 1.
 
+                                                *gutentags_dont_load*
+g:gutentags_dont_load
+                        Prevents Gutentags from loading at all on Vim startup.
+
+                        The difference between this and |gutentags_enabled| is
+                        that |gutentags_enabled| can be turned on and off in
+                        the same Vim session -- Gutentags as a plugin stays
+                        loaded and will keep track of what happened while it
+                        was disabled. However, |gutentags_dont_load| only
+                        works on Vim startup and will prevent Gutentags from
+                        loading at all, as if it wasn't there.
+
                                                 *gutentags_ctags_executable*
 g:gutentags_ctags_executable
                         Specifies the ctags executable to launch.
@@ -237,13 +249,13 @@
                         Specifies the ctags executable to launch for a project
                         of type {type}. See |gutentags_project_info| for more
                         information.
-                        IMPORTANT: piease see |gutentags-ctags-requirements|.
+                        IMPORTANT: please see |gutentags-ctags-requirements|.
                         Example: >
                          let g:gutentags_ctags_executable_ruby = 'foobar'
 <
 
-                                                *gutentags_tagfile*
-g:gutentags_tagfile
+                                                *gutentags_ctags_tagfile*
+g:gutentags_ctags_tagfile
                         Specifies the name of the tag file to create. This
                         will be appended to the project's root. See
                         |gutentags_project_root| for how Gutentags locates the
@@ -258,8 +270,8 @@
                         in the current file's directory and its parent
                         directories. If it finds any of those markers,
                         Gutentags will be enabled for the project, and a tags
-                        file named after |gutentags_tagfile| will be created at
-                        the project root.
+                        file named after |gutentags_ctags_tagfile| will be 
+                        created at the project root.
                         Defaults to `[]` (an empty |List|).
                         A list of default markers will be appended to the
                         user-defined ones unless
@@ -302,17 +314,25 @@
                         Note: when set, the called implementation will most 
                         likely ignore |g:gutentags_project_root|.
 
-                                                *gutentags_exclude*
-g:gutentags_exclude
+                                                *gutentags_ctags_exclude*
+g:gutentags_ctags_exclude
                         A list of file patterns to pass to the
                         |gutentags_ctags_executable| so that they will be
                         excluded from parsing for the tags generation.
-                        Defaults to `[]` (an empty |List|).  Patterns defined
-                        in 'wildignore' will also be given as exclude patterns
-                        to the `ctags` executable.
+                        See also |gutentags_ctags_exclude_wildignore|.
+                        Defaults to `[]` (an empty |List|).
 
-                                                *gutentags_auto_set_tags*
-g:gutentags_auto_set_tags
+                                                *gutentags_ctags_exclude_wildignore*
+g:gutentags_ctags_exclude_wildignore
+                        When 1, Gutentags will automatically pass your
+                        'wildignore' file patterns to the 
+                        |gutentags_ctags_executable| so that they are ignored.
+                        Set also |gutentags_ctags_exclude| to pass custom
+                        patterns.
+                        Defaults to 1.
+
+                                                *gutentags_ctags_auto_set_tags*
+g:gutentags_ctags_auto_set_tags
                         If set to 1, Gutentags will automatically prepend
                         'tags' with the exact path to the tag file for the
                         current project. See |gutentags_project_root| for how
@@ -387,15 +407,23 @@
                         part of the project.
                         Defaults to 0.
                         
-                                            *gutentags_enabled_user_func*
-g:gutentags_enabled_user_func
+                                            *gutentags_init_user_func*
+g:gutentags_init_user_func
                         When set to a non-empty string, it is expected to be
                         the name of a function that will be called when a file
                         is opened in a project. The function gets passed the
                         path of the file and if it returns 0, Gutentags won't
                         be enabled for that file.
-                        You can use this also to manually set `b:gutentags_root`
-                        (see |gutentags_project_root|).
+
+                        You can use this to manually set buffer-local
+                        settings:
+                        
+                        * `b:gutentags_ctags_tagfile` (see |gutentags_ctags_tagfile|).
+
+                        This setting was previously called 
+                        `gutentags_enabled_user_func`. The old setting is
+                        still used as a fallback.
+
                         Defaults to "".
 
                                             *gutentags_define_advanced_commands*
--- a/plat/unix/update_tags.sh	Mon Oct 10 19:04:05 2016 -0300
+++ b/plat/unix/update_tags.sh	Sun Feb 19 20:00:13 2017 -0800
@@ -8,7 +8,9 @@
 TAGS_FILE=tags
 PROJECT_ROOT=
 FILE_LIST_CMD=
+FILE_LIST_CMD_IS_ABSOLUTE=0
 UPDATED_SOURCE=
+POST_PROCESS_CMD=
 PAUSE_BEFORE_EXIT=0
 
 
@@ -20,15 +22,19 @@
     echo "    -t [file=tags]: The path to the ctags file to update"
     echo "    -p [dir=]:      The path to the project root"
     echo "    -L [cmd=]:      The file list command to run"
+    echo "    -A:             Specifies that the file list command returns "
+    echo "                    absolute paths"
     echo "    -s [file=]:     The path to the source file that needs updating"
     echo "    -x [pattern=]:  A pattern of files to exclude"
     echo "    -o [options=]:  An options file to read additional options from"
+    echo "    -O [params=]:   Parameters to pass to ctags"
+    echo "    -P [cmd=]:      Post process command to run on the tags file"
     echo "    -c:             Ask for confirmation before exiting"
     echo ""
 }
 
 
-while getopts "h?e:x:t:p:L:s:o:c" opt; do
+while getopts "h?e:x:t:p:L:s:o:O:P:cA" opt; do
     case $opt in
         h|\?)
             ShowUsage
@@ -49,6 +55,9 @@
         L)
             FILE_LIST_CMD=$OPTARG
             ;;
+        A)
+            FILE_LIST_CMD_IS_ABSOLUTE=1
+            ;;
         s)
             UPDATED_SOURCE=$OPTARG
             ;;
@@ -58,6 +67,12 @@
         o)
             CTAGS_ARGS="$CTAGS_ARGS --options=$OPTARG"
             ;;
+        O)
+            CTAGS_ARGS="$CTAGS_ARGS $OPTARG"
+            ;;
+        P)
+            POST_PROCESS_CMD=$OPTARG
+            ;;
     esac
 done
 
@@ -88,7 +103,7 @@
 
 if [ $INDEX_WHOLE_PROJECT -eq 1 ]; then
     if [ -n "${FILE_LIST_CMD}" ]; then
-        if [ "${PROJECT_ROOT}" = "." ]; then
+        if [ "${PROJECT_ROOT}" = "." ] || [ $FILE_LIST_CMD_IS_ABSOLUTE -eq 1 ]; then
             $FILE_LIST_CMD > "${TAGS_FILE}.files"
         else
             # If using a tags cache directory, use absolute paths
@@ -107,6 +122,12 @@
     $CTAGS_EXE -f "$TAGS_FILE.temp" $CTAGS_ARGS --append "$UPDATED_SOURCE"
 fi
 
+if [ "$POST_PROCESS_CMD" != "" ]; then
+    echo "Running post process"
+    echo "$POST_PROCESS_CMD \"$TAGS_FILE.temp\""
+    $POST_PROCESS_CMD "$TAGS_FILE.temp"
+fi
+
 echo "Replacing tags file"
 echo "mv -f \"$TAGS_FILE.temp\" \"$TAGS_FILE\""
 mv -f "$TAGS_FILE.temp" "$TAGS_FILE"
--- a/plat/win32/update_tags.cmd	Mon Oct 10 19:04:05 2016 -0300
+++ b/plat/win32/update_tags.cmd	Sun Feb 19 20:00:13 2017 -0800
@@ -10,7 +10,9 @@
 set TAGS_FILE=tags
 set PROJECT_ROOT=
 set FILE_LIST_CMD=
+set FILE_LIST_CMD_IS_ABSOLUTE=0
 set UPDATED_SOURCE=
+set POST_PROCESS_CMD=
 set PAUSE_BEFORE_EXIT=0
 set LOG_FILE=
 
@@ -41,6 +43,10 @@
     shift
     goto :LoopParseArgs
 )
+if [%1]==[-A] (
+    set FILE_LIST_CMD_IS_ABSOLUTE=1
+    goto :LoopParseArgs
+)
 if [%1]==[-s] (
     set UPDATED_SOURCE=%~2
     shift
@@ -60,6 +66,16 @@
     shift
     goto :LoopParseArgs
 )
+if [%1]==[-O] (
+    set CTAGS_ARGS=%CTAGS_ARGS% %~2
+    shift
+    goto :LoopParseArgs
+)
+if [%1]==[-P] (
+    set POST_PROCESS_CMD=%~2
+    shift
+    goto :LoopParseArgs
+)
 echo Invalid Argument: %1
 goto :Usage
 
@@ -93,7 +109,11 @@
     set CTAGS_ARGS=%CTAGS_ARGS% "%PROJECT_ROOT%"
     if not ["%FILE_LIST_CMD%"]==[""] (
         echo Running custom file lister >> %LOG_FILE%
-        if ["%PROJECT_ROOT%"]==["."] (
+        set use_raw_list=0
+        if ["%PROJECT_ROOT%"]==["."] set use_raw_list=1
+        if ["%FILE_LIST_CMD_IS_ABSOLUTE%"]==["1"] set use_raw_list=1
+        rem No idea why we need to use delayed expansion here to make it work :(
+        if ["!use_raw_list!"]==["1"] (
             echo call %FILE_LIST_CMD% ^> %TAGS_FILE%.files >> %LOG_FILE%
             call %FILE_LIST_CMD% > %TAGS_FILE%.files
         ) else (
@@ -115,6 +135,16 @@
     goto :Unlock
 )
 
+if not ["%POST_PROCESS_CMD%"]==[""] (
+    echo Running post process >> %LOG_FILE%
+    echo call %POST_PROCESS_CMD% %TAGS_FILE%.temp >> %LOG_FILE%
+    call %POST_PROCESS_CMD% %TAGS_FILE%.temp >> %LOG_FILE% 2>&1
+    if ERRORLEVEL 1 (
+        echo ERROR: Post process returned non-zero code. >> %LOG_FILE%
+        goto :Unlock
+    )
+)
+
 echo Replacing tags file >> %LOG_FILE%
 echo move /Y "%TAGS_FILE%.temp" "%TAGS_FILE%" >> %LOG_FILE%
 move /Y "%TAGS_FILE%.temp" "%TAGS_FILE%" >> %LOG_FILE% 2>&1
@@ -150,6 +180,8 @@
 echo    -t [file=tags]: The path to the ctags file to update
 echo    -p [dir=]:      The path to the project root
 echo    -L [cmd=]:      The file list command to run
+echo    -A:             Specifies that the file list command returns
+echo                    absolute paths
 echo    -s [file=]:     The path to the source file that needs updating
 echo    -l [log=]:      The log file to output to
 echo    -o [options=]:  An options file to read additional options from
--- a/plugin/gutentags.vim	Mon Oct 10 19:04:05 2016 -0300
+++ b/plugin/gutentags.vim	Sun Feb 19 20:00:13 2017 -0800
@@ -4,6 +4,10 @@
 
 " Globals {{{
 
+if (&cp || get(g:, 'gutentags_dont_load', 0))
+    finish
+endif
+
 if v:version < 704
     echoerr "gutentags: this plugin requires vim >= 7.4."
     finish
@@ -11,7 +15,7 @@
 
 let g:gutentags_debug = get(g:, 'gutentags_debug', 0)
 
-if (exists('g:loaded_gutentags') || &cp) && !g:gutentags_debug
+if (exists('g:loaded_gutentags') && !g:gutentags_debug)
     finish
 endif
 if (exists('g:loaded_gutentags') && g:gutentags_debug)
@@ -24,21 +28,23 @@
 let g:gutentags_background_update = get(g:, 'gutentags_background_update', 1)
 let g:gutentags_pause_after_update = get(g:, 'gutentags_pause_after_update', 0)
 let g:gutentags_enabled = get(g:, 'gutentags_enabled', 1)
-let g:gutentags_enabled_user_func = get(g:, 'gutentags_enabled_user_func', '')
 let g:gutentags_modules = get(g:, 'gutentags_modules', ['ctags'])
 
+let g:gutentags_init_user_func = get(g:, 'gutentags_init_user_func', 
+            \get(g:, 'gutentags_enabled_user_func', ''))
+
 let g:gutentags_add_default_project_roots = get(g:, 'gutentags_add_default_project_roots', 1)
 let g:gutentags_project_root = get(g:, 'gutentags_project_root', [])
 if g:gutentags_add_default_project_roots
     let g:gutentags_project_root += ['.git', '.hg', '.svn', '.bzr', '_darcs', '_FOSSIL_', '.fslckout']
 endif
-let g:gutentags_project_root_finder = ''
+
+let g:gutentags_project_root_finder = get(g:, 'gutentags_project_root_finder', '')
 
 let g:gutentags_project_info = get(g:, 'gutentags_project_info', [])
 call add(g:gutentags_project_info, {'type': 'python', 'file': 'setup.py'})
 call add(g:gutentags_project_info, {'type': 'ruby', 'file': 'Gemfile'})
 
-let g:gutentags_exclude = get(g:, 'gutentags_exclude', [])
 let g:gutentags_exclude_project_root = get(g:, 'gutentags_exclude_project_root', ['/usr/local'])
 let g:gutentags_resolve_symlinks = get(g:, 'gutentags_resolve_symlinks', 0)
 let g:gutentags_generate_on_new = get(g:, 'gutentags_generate_on_new', 1)
@@ -48,7 +54,7 @@
 
 if !exists('g:gutentags_cache_dir')
     let g:gutentags_cache_dir = ''
-else
+elseif !empty(g:gutentags_cache_dir)
     " Make sure we get an absolute/resolved path (e.g. expanding `~/`), and
     " strip any trailing slash.
     let g:gutentags_cache_dir = fnamemodify(g:gutentags_cache_dir, ':p')