Mercurial > vim-gutentags
changeset 3:60adce96ac2d
Lots of changes:
* Add Unix script for tag file generation.
* Add status-line indicator.
* More options to customize Autotags behaviour.
* Use 'wildignore' to exclude things from ctags.
* Generate tag file in a project missing it.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 20 Jul 2014 14:25:09 -0700 |
parents | d073ca33c5b8 |
children | 512eaa56c7db |
files | plat/unix/update_tags.sh plat/win32/update_tags.cmd plugin/autotags.vim |
diffstat | 3 files changed, 222 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/plat/unix/update_tags.sh Sun Jul 20 14:21:43 2014 -0700 +++ b/plat/unix/update_tags.sh Sun Jul 20 14:25:09 2014 -0700 @@ -0,0 +1,81 @@ +#!/bin/sh + +set -e + +PROG_NAME=$0 +CTAGS_EXE=ctags +CTAGS_ARGS= +TAGS_FILE=tags +UPDATED_SOURCE= +PAUSE_BEFORE_EXIT=0 + + +ShowUsage() { + echo "Usage:" + echo " $PROG_NAME <options>" + echo "" + echo " -e [exe=ctags]: The ctags executable to run" + echo " -t [file=tags]: The path to the ctags file to update" + echo " -s [file=]: The path to the source file that needs updating" + echo " -x [pattern=]: A pattern of files to exclude" + echo "" +} + + +while getopts "h?e:x:t:s:l:" opt; do + case $opt in + h|\?) + ShowUsage + exit 0 + ;; + e) + CTAGS_EXE=$OPTARG + ;; + x) + CTAGS_ARGS="$CTAGS_ARGS --exclude=$OPTARG" + ;; + t) + TAGS_FILE=$OPTARG + ;; + s) + UPDATED_SOURCE=$OPTARG + ;; + p) + PAUSE_BEFORE_EXIT=1 + ;; + esac +done + +shift $((OPTIND - 1)) + +if [[ "$1" -ne "" ]]; then + echo "Invalid Argument: $1" + exit 1 +fi + +echo "Locking tags file..." +echo "locked" > "$TAGS_FILE.lock" + +if [[ -f "$TAGS_FILE" ]]; then + if [[ "$UPDATED_SOURCE" != "" ]]; then + echo "Removing references to: $UPDATED_SOURCE" + echo "grep -v $UPDATED_SOURCE \"$TAGS_FILE\" > \"$TAGS_FILE.filter\"" + grep -v $UPDATED_SOURCE "$TAGS_FILE" > "$TAGS_FILE.filter" + mv "$TAGS_FILE.filter" "$TAGS_FILE" + CTAGS_ARGS="$CTAGS_ARGS --append $UPDATED_SOURCE" + fi +fi + +echo "Running ctags" +echo "$CTAGS_EXE -R -f \"$TAGS_FILE\" $CTAGS_ARGS" +$CTAGS_EXE -R -f "$TAGS_FILE" $CTAGS_ARGS + +echo "Unlocking tags file..." +rm -f "$TAGS_FILE.lock" + +echo "Done." + +if [[ $PAUSE_BEFORE_EXIT -eq 1 ]]; then + read -p "Press ENTER to exit..." +fi +
--- a/plat/win32/update_tags.cmd Sun Jul 20 14:21:43 2014 -0700 +++ b/plat/win32/update_tags.cmd Sun Jul 20 14:25:09 2014 -0700 @@ -13,26 +13,26 @@ :ParseArgs if [%1]==[] goto :DoneParseArgs -if [%1]==[--exe] ( +if [%1]==[-e] ( set CTAGS_EXE=%~2 shift goto :LoopParseArgs ) -if [%1]==[--tags] ( +if [%1]==[-t] ( set TAGS_FILE=%~2 shift goto :LoopParseArgs ) -if [%1]==[--source] ( +if [%1]==[-s] ( set UPDATED_SOURCE=%~2 shift goto :LoopParseArgs ) -if [%1]==[--pause] ( +if [%1]==[-p] ( set PAUSE_BEFORE_EXIT=1 goto :LoopParseArgs ) -if [%1]==[--log] ( +if [%1]==[-l] ( set LOG_FILE=%~2 shift goto :LoopParseArgs @@ -91,8 +91,9 @@ echo Usage: echo %~n0 ^<options^> echo. -echo --exe [exe=ctags]: The ctags executable to run -echo --tags [file=tags]: The path to the ctags file to update -echo --source [file=]: The path to the source file that needs updating +echo -e [exe=ctags]: The ctags executable to run +echo -t [file=tags]: The path to the ctags file to update +echo -s [file=]: The path to the source file that needs updating +echo -l [log=]: The log file to output to echo.
--- a/plugin/autotags.vim Sun Jul 20 14:21:43 2014 -0700 +++ b/plugin/autotags.vim Sun Jul 20 14:25:09 2014 -0700 @@ -17,7 +17,7 @@ let g:loaded_autotags = 1 if !exists('g:autotags_trace') - let g:autotags_trace = 1 + let g:autotags_trace = 0 endif if !exists('g:autotags_fake') @@ -45,6 +45,22 @@ endif let g:autotags_project_root += ['.git', '.hg', '.bzr', '_darcs'] +if !exists('g:autotags_exclude') + let g:autotags_exclude = [] +endif + +if !exists('g:autotags_generate_on_missing') + let g:autotags_generate_on_missing = 1 +endif + +if !exists('g:autotags_generate_on_write') + let g:autotags_generate_on_write = 1 +endif + +if !exists('g:autotags_auto_set_tags') + let g:autotags_auto_set_tags = 1 +endif + " }}} " Utilities {{{ @@ -111,25 +127,43 @@ " Setup autotags for the current buffer. function! s:setup_autotags() abort - call s:trace("Scanning buffer '" . bufname('%') . "' for autotags setup...") - if exists('b:autotags_file') + if exists('b:autotags_file') && !g:autotags_debug + " This buffer already has autotags support. return endif + + " Try and file what tags file we should manage. + call s:trace("Scanning buffer '" . bufname('%') . "' for autotags setup...") try let b:autotags_file = s:get_tagfile_for(expand('%:h')) catch /^autotags\:/ + call s:trace("Can't figure out what tag file to use... no autotags support.") return endtry + " We know what tags file to manage! Now set things up. call s:trace("Setting autotags for buffer '" . bufname('%') . "' with tagfile: " . b:autotags_file) + " Set the tags file for Vim to use. + if g:autotags_auto_set_tags + execute 'setlocal tags^=' . b:autotags_file + endif + + " Autocommands for updating the tags on save. let l:bn = bufnr('%') execute 'augroup autotags_buffer_' . l:bn execute ' autocmd!' - execute ' autocmd BufWritePost <buffer=' . l:bn . '> if g:autotags_enabled|call s:update_tags(0, 1)|endif' + execute ' autocmd BufWritePost <buffer=' . l:bn . '> call s:write_triggered_update_tags()' execute 'augroup end' + " Miscellaneous commands. command! -buffer -bang AutotagsUpdate :call s:manual_update_tags(<bang>0) + + " If the tags file doesn't exist, start generating it now. + if g:autotags_generate_on_missing && !filereadable(b:autotags_file) + call s:trace("Generating missing tags file: " . b:autotags_file) + call s:update_tags(1, 0) + endif endfunction augroup autotags_detect @@ -148,6 +182,7 @@ endif let s:update_queue = [] +let s:maybe_in_progress = [] " Get how to execute an external command depending on debug settings. function! s:get_execute_cmd() abort @@ -162,11 +197,27 @@ endif endfunction +" Get the suffix for how to execute an external command. +function! s:get_execute_cmd_suffix() abort + if has('win32') + return '' + else + return ' &' + endif +endfunction + " (Re)Generate the tags file for the current buffer's file. function! s:manual_update_tags(bang) abort call s:update_tags(a:bang, 0) endfunction +" (Re)Generate the tags file for a buffer that just go saved. +function! s:write_triggered_update_tags() abort + if g:autotags_enabled && g:autotags_generate_on_write + call s:update_tags(0, 1) + endif +endfunction + " Update the tags file for the current buffer's file. " write_mode: " 0: update the tags file if it exists, generate it otherwise. @@ -180,7 +231,6 @@ " is specified, it will go to the autotags-defined file. function! s:update_tags(write_mode, queue_mode, ...) abort " Figure out where to save. - let l:tags_file = 0 if a:0 == 1 let l:tags_file = a:1 else @@ -214,22 +264,38 @@ try " Build the command line. let l:cmd = s:get_execute_cmd() . s:runner_exe - let l:cmd .= ' --exe "' . g:autotags_executable . '"' - let l:cmd .= ' --tags "' . fnamemodify(l:tags_file, ':t') . '"' + let l:cmd .= ' -e "' . g:autotags_executable . '"' + let l:cmd .= ' -t "' . fnamemodify(l:tags_file, ':t') . '"' if a:write_mode == 0 && filereadable(l:tags_file) " CTags specifies paths relative to the tags file with a `./` " prefix, so we need to specify the same prefix otherwise it will " think those are different files and we'll end up with duplicate " entries. let l:rel_path = s:normalizepath('./' . expand('%:.')) - let l:cmd .= ' --source "' . l:rel_path . '"' + let l:cmd .= ' -s "' . l:rel_path . '"' endif + for ign in split(&wildignore, ',') + let l:cmd .= ' -x ' . ign + endfor + for exc in g:autotags_exclude + let l:cmd .= ' -x ' . exc + endfor if g:autotags_trace - let l:cmd .= ' --log "' . fnamemodify(l:tags_file, ':t') . '.log"' + if has('win32') + let l:cmd .= ' -l "' . fnamemodify(l:tags_file, ':t') . '.log"' + else + let l:cmd .= ' > "' . fnamemodify(l:tags_file, ':t') . '.log"' + endif endif + let l:cmd .= s:get_execute_cmd_suffix() + + " Run the background process. call s:trace("Running: " . l:cmd) call s:trace("In: " . l:work_dir) if !g:autotags_fake + " Flag this tags file as being in progress + call add(s:maybe_in_progress, fnamemodify(l:tags_file, ':p')) + if !g:autotags_trace silent execute l:cmd else @@ -257,7 +323,7 @@ " }}} -" Toggles {{{ +" Toggles and Miscellaneous Commands {{{ command! AutotagsToggleEnabled :let g:autotags_enabled=!g:autotags_enabled command! AutotagsToggleTrace :call autotags#trace() @@ -308,5 +374,61 @@ echom "" endfunction +function! autotags#inprogress() + echom "autotags: generations in progress:" + for mip in s:maybe_in_progress + echom mip + endfor + echom "" +endfunction + " }}} +" Statusline Functions {{{ + +" Prints whether a tag file is being generated right now for the current +" buffer in the status line. +" +" Arguments can be passed: +" - args 1 and 2 are the prefix and suffix, respectively, of whatever output, +" if any, is going to be produced. +" (defaults to empty strings) +" - arg 3 is the text to be shown if tags are currently being generated. +" (defaults to 'TAGS') +" +function! autotags#statusline(...) abort + if !exists('b:autotags_file') + " This buffer doesn't have autotags. + return '' + endif + + " Figure out what the user is customizing. + let l:gen_msg = 'TAGS' + if a:0 >= 0 + let l:gen_msg = a:1 + endif + + " To make this function as fast as possible, we first check whether the + " current buffer's tags file is 'maybe' being generated. This provides a + " nice and quick bail out for 99.9% of cases before we need to this the + " file-system to check the lock file. + let l:abs_tag_file = fnamemodify(b:autotags_file, ':p') + let l:found = index(s:maybe_in_progress, l:abs_tag_file) + if l:found < 0 + return '' + endif + " It's maybe generating! Check if the lock file is still there. + if !filereadable(l:abs_tag_file . '.lock') + call remove(s:maybe_in_progress, l:found) + return '' + endif + " It's still there! So probably `ctags` is still running... + " (although there's a chance it crashed, or the script had a problem, and + " the lock file has been left behind... we could try and run some + " additional checks here to see if it's legitimately running, and + " otherwise delete the lock file... maybe in the future...) + return l:gen_msg +endfunction + +" }}} +