# HG changeset patch # User Ludovic Chabant # Date 1572077839 25200 # Node ID 56dc6f8e54720ca9e9bbe535d4bac10aff29f689 # Parent e61d20280c6c49010f8bd399defba5ffc7a30672 Use tag-relative paths in ctags when needed. This is necessary when the tags file isn't generated at the project root. diff -r e61d20280c6c -r 56dc6f8e5472 autoload/gutentags/ctags.vim --- a/autoload/gutentags/ctags.vim Fri Oct 25 23:52:12 2019 -0700 +++ b/autoload/gutentags/ctags.vim Sat Oct 26 01:17:19 2019 -0700 @@ -78,9 +78,9 @@ let l:write_mode = a:gen_opts['write_mode'] let l:tags_file_exists = filereadable(a:tags_file) - let l:tags_file_relative = fnamemodify(a:tags_file, ':.') - let l:tags_file_is_local = len(l:tags_file_relative) < len(a:tags_file) + " If the tags file exists, we may want to do a sanity check to prevent + " weird errors that are hard to troubleshoot. 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 @@ -92,6 +92,17 @@ endif endif + " Get a tags file path relative to the current directory, which + " happens to be the project root in this case. + " Since the given tags file path is absolute, and since Vim won't + " change the path if it is not inside the current directory, we + " know that the tags file is "local" (i.e. inside the project) + " if the path was shortened (an absolute path will always be + " longer than a true relative path). + let l:tags_file_relative = fnamemodify(a:tags_file, ':.') + let l:tags_file_is_local = len(l:tags_file_relative) < len(a:tags_file) + let l:use_tag_relative_opt = 0 + if empty(g:gutentags_cache_dir) && l:tags_file_is_local " If we don't use the cache directory, we can pass relative paths " around. @@ -99,10 +110,27 @@ " 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... (which we are, our caller in - " `autoload/gutentags.vim` changed it). + " directory, for some reason... (which will be the case, we're running + " the jobs from the project root). let l:actual_proj_dir = '.' let l:actual_tags_file = l:tags_file_relative + + let l:tags_file_dir = fnamemodify(l:actual_tags_file, ':h') + if l:tags_file_dir != '.' + " Ok so now the tags file is stored in a subdirectory of the + " project root, instead of at the root. This happens if, say, + " someone set `gutentags_ctags_tagfile` to `.git/tags`, which + " seems to be fairly popular. + " + " By default, `ctags` writes paths relative to the current + " directory (the project root) but in this case we need it to + " be relative to the tags file (e.g. adding `../` in front of + " everything if the tags file is `.git/tags`). + " + " Thankfully most `ctags` implementations support an option + " just for this. + let l:use_tag_relative_opt = 1 + endif else " else: the tags file goes in a cache directory, so we need to specify " all the paths absolutely for `ctags` to do its job correctly. @@ -163,6 +191,9 @@ for exc in g:gutentags_ctags_exclude let l:cmd += ['-x', '"' . exc . '"'] endfor + if l:use_tag_relative_opt + let l:cmd += ['-r'] + endif if g:gutentags_pause_after_update let l:cmd += ['-c'] endif diff -r e61d20280c6c -r 56dc6f8e5472 plat/unix/update_tags.sh --- a/plat/unix/update_tags.sh Fri Oct 25 23:52:12 2019 -0700 +++ b/plat/unix/update_tags.sh Sat Oct 26 01:17:19 2019 -0700 @@ -24,6 +24,7 @@ echo " -t [file=tags]: The path to the ctags file to update" echo " -p [dir=]: The path to the project root" echo " -l [file=]: The path to a log file" + echo " -r Use tag-relative paths" echo " -L [cmd=]: The file list command to run" echo " -A: Specifies that the file list command returns " echo " absolute paths" @@ -37,7 +38,7 @@ } -while getopts "h?e:x:t:p:l:L:s:o:O:P:cA" opt; do +while getopts "h?e:x:t:p:l:L:s:o:O:P:rcA" opt; do case $opt in h|\?) ShowUsage @@ -73,6 +74,9 @@ o) CTAGS_ARGS="$CTAGS_ARGS --options=$OPTARG" ;; + r) + CTAGS_ARGS="$CTAGS_ARGS --tag-relative=yes" + ;; O) CTAGS_ARGS="$CTAGS_ARGS $OPTARG" ;; diff -r e61d20280c6c -r 56dc6f8e5472 plat/win32/update_tags.cmd --- a/plat/win32/update_tags.cmd Fri Oct 25 23:52:12 2019 -0700 +++ b/plat/win32/update_tags.cmd Sat Oct 26 01:17:19 2019 -0700 @@ -66,6 +66,11 @@ shift goto :LoopParseArgs ) +if [%1]==[-r] ( + set CTAGS_ARGS=%CTAGS_ARGS% --tag-relative=yes + shift + goto :LoopParseArgs +) if [%1]==[-O] ( set CTAGS_ARGS=%CTAGS_ARGS% %~2 shift @@ -180,12 +185,16 @@ echo -e [exe=ctags]: The ctags executable to run echo -t [file=tags]: The path to the ctags file to update echo -p [dir=]: The path to the project root +echo -l [log=]: The log file to output to +echo -r Use tag-relative paths 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 -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.