comparison autoload/gutentags/ctags.vim @ 252:56dc6f8e5472

Use tag-relative paths in ctags when needed. This is necessary when the tags file isn't generated at the project root.
author Ludovic Chabant <ludovic@chabant.com>
date Sat, 26 Oct 2019 01:17:19 -0700
parents 36dabe30ab6e
children ec292bfbd633
comparison
equal deleted inserted replaced
251:e61d20280c6c 252:56dc6f8e5472
76 76
77 function! gutentags#ctags#generate(proj_dir, tags_file, gen_opts) abort 77 function! gutentags#ctags#generate(proj_dir, tags_file, gen_opts) abort
78 let l:write_mode = a:gen_opts['write_mode'] 78 let l:write_mode = a:gen_opts['write_mode']
79 79
80 let l:tags_file_exists = filereadable(a:tags_file) 80 let l:tags_file_exists = filereadable(a:tags_file)
81 let l:tags_file_relative = fnamemodify(a:tags_file, ':.') 81
82 let l:tags_file_is_local = len(l:tags_file_relative) < len(a:tags_file) 82 " If the tags file exists, we may want to do a sanity check to prevent
83 83 " weird errors that are hard to troubleshoot.
84 if l:tags_file_exists && g:gutentags_ctags_check_tagfile 84 if l:tags_file_exists && g:gutentags_ctags_check_tagfile
85 let l:first_lines = readfile(a:tags_file, '', 1) 85 let l:first_lines = readfile(a:tags_file, '', 1)
86 if len(l:first_lines) == 0 || stridx(l:first_lines[0], '!_TAG_') != 0 86 if len(l:first_lines) == 0 || stridx(l:first_lines[0], '!_TAG_') != 0
87 call gutentags#throw( 87 call gutentags#throw(
88 \"File ".a:tags_file." doesn't appear to be ". 88 \"File ".a:tags_file." doesn't appear to be ".
90 \":GutentagsUpdate!.") 90 \":GutentagsUpdate!.")
91 return 91 return
92 endif 92 endif
93 endif 93 endif
94 94
95 " Get a tags file path relative to the current directory, which
96 " happens to be the project root in this case.
97 " Since the given tags file path is absolute, and since Vim won't
98 " change the path if it is not inside the current directory, we
99 " know that the tags file is "local" (i.e. inside the project)
100 " if the path was shortened (an absolute path will always be
101 " longer than a true relative path).
102 let l:tags_file_relative = fnamemodify(a:tags_file, ':.')
103 let l:tags_file_is_local = len(l:tags_file_relative) < len(a:tags_file)
104 let l:use_tag_relative_opt = 0
105
95 if empty(g:gutentags_cache_dir) && l:tags_file_is_local 106 if empty(g:gutentags_cache_dir) && l:tags_file_is_local
96 " If we don't use the cache directory, we can pass relative paths 107 " If we don't use the cache directory, we can pass relative paths
97 " around. 108 " around.
98 " 109 "
99 " Note that if we don't do this and pass a full path for the project 110 " Note that if we don't do this and pass a full path for the project
100 " root, some `ctags` implementations like Exhuberant Ctags can get 111 " root, some `ctags` implementations like Exhuberant Ctags can get
101 " confused if the paths have spaces -- but not if you're *in* the root 112 " confused if the paths have spaces -- but not if you're *in* the root
102 " directory, for some reason... (which we are, our caller in 113 " directory, for some reason... (which will be the case, we're running
103 " `autoload/gutentags.vim` changed it). 114 " the jobs from the project root).
104 let l:actual_proj_dir = '.' 115 let l:actual_proj_dir = '.'
105 let l:actual_tags_file = l:tags_file_relative 116 let l:actual_tags_file = l:tags_file_relative
117
118 let l:tags_file_dir = fnamemodify(l:actual_tags_file, ':h')
119 if l:tags_file_dir != '.'
120 " Ok so now the tags file is stored in a subdirectory of the
121 " project root, instead of at the root. This happens if, say,
122 " someone set `gutentags_ctags_tagfile` to `.git/tags`, which
123 " seems to be fairly popular.
124 "
125 " By default, `ctags` writes paths relative to the current
126 " directory (the project root) but in this case we need it to
127 " be relative to the tags file (e.g. adding `../` in front of
128 " everything if the tags file is `.git/tags`).
129 "
130 " Thankfully most `ctags` implementations support an option
131 " just for this.
132 let l:use_tag_relative_opt = 1
133 endif
106 else 134 else
107 " else: the tags file goes in a cache directory, so we need to specify 135 " else: the tags file goes in a cache directory, so we need to specify
108 " all the paths absolutely for `ctags` to do its job correctly. 136 " all the paths absolutely for `ctags` to do its job correctly.
109 let l:actual_proj_dir = a:proj_dir 137 let l:actual_proj_dir = a:proj_dir
110 let l:actual_tags_file = a:tags_file 138 let l:actual_tags_file = a:tags_file
161 endif 189 endif
162 endif 190 endif
163 for exc in g:gutentags_ctags_exclude 191 for exc in g:gutentags_ctags_exclude
164 let l:cmd += ['-x', '"' . exc . '"'] 192 let l:cmd += ['-x', '"' . exc . '"']
165 endfor 193 endfor
194 if l:use_tag_relative_opt
195 let l:cmd += ['-r']
196 endif
166 if g:gutentags_pause_after_update 197 if g:gutentags_pause_after_update
167 let l:cmd += ['-c'] 198 let l:cmd += ['-c']
168 endif 199 endif
169 if g:gutentags_trace 200 if g:gutentags_trace
170 let l:cmd += ['-l', '"' . l:actual_tags_file . '.log"'] 201 let l:cmd += ['-l', '"' . l:actual_tags_file . '.log"']