Mercurial > vim-gutentags
view autoload/gutentags/ctags.vim @ 135:4c9e2de7d46a
Rename ctags.options to ctags_recursive.options
According to https://github.com/ludovicchabant/vim-gutentags/issues/33,
ctags' --recursive option was moved to an option file to allow it to be
overridden by user options files. This change makes it clear what the
purpose of this options file is.
author | Stephen Kent <smkent@smkent.net> |
---|---|
date | Fri, 22 Jul 2016 19:25:01 -0700 |
parents | 6f15299869fc |
children | 286e5b3095d0 |
line wrap: on
line source
" Ctags module for Gutentags " 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_options_file = get(g:, 'gutentags_ctags_options_file', '.gutctags') let g:gutentags_ctags_check_tagfile = get(g:, 'gutentags_ctags_check_tagfile', 0) " }}} " Gutentags Module Interface {{{ let s:runner_exe = gutentags#get_plat_file('update_tags') let s:unix_redir = (&shellredir =~# '%s') ? &shellredir : &shellredir . ' %s' function! gutentags#ctags#init(project_root) abort " Figure out the path to the tags file. let b:gutentags_files['ctags'] = gutentags#get_cachefile( \a:project_root, g:gutentags_tagfile) " Set the tags file for Vim to use. if g:gutentags_auto_set_tags execute 'setlocal tags^=' . fnameescape(b:gutentags_files['ctags']) endif " Check if the ctags executable exists. if g:gutentags_enabled && executable(expand(g:gutentags_ctags_executable, 1)) == 0 let g:gutentags_enabled = 0 echoerr "Executable '".g:gutentags_ctags_executable."' can't be found. " \."Gutentags will be disabled. You can re-enable it by " \."setting g:gutentags_enabled back to 1." endif endfunction 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 = getcwd() 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 ". \"a ctags file. Please delete it and run ". \":GutentagsUpdate!.") return endif 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. let l:actual_proj_dir = '.' let l:actual_tags_file = g:gutentags_tagfile execute "chdir " . fnameescape(a:proj_dir) 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. let l:actual_proj_dir = a:proj_dir let l:actual_tags_file = a:tags_file endif try " Build the command line. let l:cmd = gutentags#get_execute_cmd() . s:runner_exe let l:cmd .= ' -e "' . s:get_ctags_executable(a:proj_dir) . '"' let l:cmd .= ' -t "' . l:actual_tags_file . '"' let l:cmd .= ' -p "' . l:actual_proj_dir . '"' if a:write_mode == 0 && l:tags_file_exists let l:cur_file_path = expand('%:p') if empty(g:gutentags_cache_dir) let l:cur_file_path = fnamemodify(l:cur_file_path, ':.') endif let l:cmd .= ' -s "' . l:cur_file_path . '"' endif " Pass the Gutentags recursive options file before the project " options file, so that users can override --recursive. let l:cmd .= ' -o "' . gutentags#get_res_file('ctags_recursive.options') . '"' let l:proj_options_file = a:proj_dir . '/' . \g:gutentags_ctags_options_file if filereadable(l:proj_options_file) let l:proj_options_file = s:process_options_file( \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 let l:cmd .= ' -x ' . '"' . exc . '"' endfor if g:gutentags_pause_after_update let l:cmd .= ' -c' endif if g:gutentags_trace if has('win32') let l:cmd .= ' -l "' . l:actual_tags_file . '.log"' else let l:cmd .= ' ' . printf(s:unix_redir, '"' . l:actual_tags_file . '.log"') endif else if !has('win32') let l:cmd .= ' ' . printf(s:unix_redir, '/dev/null') endif endif let l:cmd .= gutentags#get_execute_cmd_suffix() call gutentags#trace("Running: " . l:cmd) call gutentags#trace("In: " . getcwd()) if !g:gutentags_fake " Run the background process. if !g:gutentags_trace silent execute l:cmd else execute l:cmd endif " Flag this tags file as being in progress let l:full_tags_file = fnamemodify(a:tags_file, ':p') call gutentags#add_progress('ctags', l:full_tags_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 " }}} " Utilities {{{ " Get final ctags executable depending whether a filetype one is defined function! s:get_ctags_executable(proj_dir) abort "Only consider the main filetype in cases like 'python.django' let l:ftype = get(split(&filetype, '\.'), 0, '') let l:proj_info = gutentags#get_project_info(a:proj_dir) let l:type = get(l:proj_info, 'type', l:ftype) let exepath = exists('g:gutentags_ctags_executable_{l:type}') \ ? g:gutentags_ctags_executable_{l:type} : g:gutentags_ctags_executable return expand(exepath, 1) endfunction function! s:process_options_file(proj_dir, path) abort if empty(g:gutentags_cache_dir) " If we're not using a cache directory to store tag files, we can " use the options file straight away. return a:path endif " See if we need to process the options file. let l:do_process = 0 let l:proj_dir = gutentags#stripslash(a:proj_dir) let l:out_path = gutentags#get_cachefile(l:proj_dir, 'options') if !filereadable(l:out_path) call gutentags#trace("Processing options file '".a:path."' because ". \"it hasn't been processed yet.") let l:do_process = 1 elseif getftime(a:path) > getftime(l:out_path) call gutentags#trace("Processing options file '".a:path."' because ". \"it has changed.") let l:do_process = 1 endif if l:do_process == 0 " Nothing's changed, return the existing processed version of the " options file. return l:out_path endif " We have to process the options file. Right now this only means capturing " all the 'exclude' rules, and rewrite them to make them absolute. " " This is because since `ctags` is run with absolute paths (because we " want the tag file to be in a cache directory), it will do its path " matching with absolute paths too, so the exclude rules need to be " absolute. let l:lines = readfile(a:path) let l:outlines = [] for line in l:lines let l:exarg_idx = matchend(line, '\v^\-\-exclude=') if l:exarg_idx < 0 call add(l:outlines, line) continue endif " Don't convert things that don't look like paths. let l:exarg = strpart(line, l:exarg_idx + 1) let l:do_convert = 1 if l:exarg[0] == '@' " Manifest file path let l:do_convert = 0 endif if stridx(l:exarg, '/') < 0 && stridx(l:exarg, '\\') < 0 " Filename let l:do_convert = 0 endif if l:do_convert == 0 call add(l:outlines, line) continue endif let l:fullp = l:proj_dir . gutentags#normalizepath('/'.l:exarg) let l:ol = '--exclude='.l:fullp call add(l:outlines, l:ol) endfor call writefile(l:outlines, l:out_path) return l:out_path endfunction " }}}