changeset 19:d48b0e48283b

Add support for storing tags files out of the way.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 31 Aug 2014 21:32:24 -0700
parents b13e1141aa5c
children bd136cb41034
files plat/unix/update_tags.sh plat/win32/update_tags.cmd plugin/autotags.vim
diffstat 3 files changed, 55 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/plat/unix/update_tags.sh	Thu Aug 21 13:25:03 2014 -0700
+++ b/plat/unix/update_tags.sh	Sun Aug 31 21:32:24 2014 -0700
@@ -6,6 +6,7 @@
 CTAGS_EXE=ctags
 CTAGS_ARGS=
 TAGS_FILE=tags
+PROJECT_ROOT=
 UPDATED_SOURCE=
 PAUSE_BEFORE_EXIT=0
 
@@ -16,6 +17,7 @@
     echo ""
     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 "    -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" 
@@ -23,7 +25,7 @@
 }
 
 
-while getopts "h?e:x:t:s:" opt; do
+while getopts "h?e:x:t:p:s:" opt; do
     case $opt in 
         h|\?)
             ShowUsage
@@ -38,6 +40,9 @@
         t)
             TAGS_FILE=$OPTARG
             ;;
+        p)
+            PROJECT_ROOT=$OPTARG
+            ;;
         s)
             UPDATED_SOURCE=$OPTARG
             ;;
@@ -70,8 +75,8 @@
 fi
 
 echo "Running ctags"
-echo "$CTAGS_EXE -R -f \"$TAGS_FILE.temp\" $CTAGS_ARGS"
-$CTAGS_EXE -R -f "$TAGS_FILE.temp" $CTAGS_ARGS
+echo "$CTAGS_EXE -R -f \"$TAGS_FILE.temp\" $CTAGS_ARGS $PROJECT_ROOT"
+$CTAGS_EXE -R -f "$TAGS_FILE.temp" $CTAGS_ARGS $PROJECT_ROOT
 
 echo "Replacing tags file"
 echo "mv -f \"$TAGS_FILE.temp\" \"$TAGS_FILE\""
--- a/plat/win32/update_tags.cmd	Thu Aug 21 13:25:03 2014 -0700
+++ b/plat/win32/update_tags.cmd	Sun Aug 31 21:32:24 2014 -0700
@@ -8,6 +8,7 @@
 set CTAGS_EXE=ctags
 set CTAGS_ARGS=
 set TAGS_FILE=tags
+set PROJECT_ROOT=
 set UPDATED_SOURCE=
 set PAUSE_BEFORE_EXIT=0
 set LOG_FILE=
@@ -29,6 +30,11 @@
     shift
     goto :LoopParseArgs
 )
+if [%1]==[-p] (
+    set PROJECT_ROOT=%~2
+    shift
+    goto :LoopParseArgs
+)
 if [%1]==[-s] (
     set UPDATED_SOURCE=%~2
     shift
@@ -77,8 +83,8 @@
 )
 
 echo Running ctags >> %LOG_FILE%
-echo "%CTAGS_EXE%" -R -f "%TAGS_FILE%.temp" %CTAGS_ARGS% >> %LOG_FILE%
-"%CTAGS_EXE%" -R -f "%TAGS_FILE%.temp" %CTAGS_ARGS%
+echo "%CTAGS_EXE%" -R -f "%TAGS_FILE%.temp" %CTAGS_ARGS% %PROJECT_ROOT% >> %LOG_FILE%
+"%CTAGS_EXE%" -R -f "%TAGS_FILE%.temp" %CTAGS_ARGS% %PROJECT_ROOT%
 
 echo Replacing tags file >> %LOG_FILE%
 echo move /Y "%TAGS_FILE%.temp" "%TAGS_FILE%" >> %LOG_FILE%
@@ -105,6 +111,7 @@
 echo.
 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    -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/autotags.vim	Thu Aug 21 13:25:03 2014 -0700
+++ b/plugin/autotags.vim	Sun Aug 31 21:32:24 2014 -0700
@@ -73,6 +73,16 @@
     let g:autotags_auto_set_tags = 1
 endif
 
+if !exists('g:autotags_cache_dir')
+    let g:autotags_cache_dir = ''
+else
+    let g:autotags_cache_dir = s:stripslash(g:autotags_cache_dir)
+endif
+
+if g:autotags_cache_dir != '' && !isdirectory(g:autotags_cache_dir)
+    call mkdir(g:autotags_cache_dir, 'p')
+endif
+
 " }}}
 
 " Utilities {{{
@@ -122,9 +132,9 @@
 
 let s:known_tagfiles = []
 
-" Finds the tag file path for the given current directory
-" (typically the directory of the file being edited)
-function! s:get_tagfile_for(path) abort
+" Finds the first directory with a project marker by walking up from the given
+" file path.
+function! s:get_project_root(path) abort
     let l:path = s:stripslash(a:path)
     let l:previous_path = ""
     let l:markers = g:autotags_project_root[:]
@@ -134,7 +144,7 @@
     while l:path != l:previous_path
         for root in g:autotags_project_root
             if getftype(l:path . '/' . root) != ""
-                return simplify(fnamemodify(l:path, ':p') . g:autotags_tagfile)
+                return simplify(fnamemodify(l:path, ':p'))
             endif
         endfor
         let l:previous_path = l:path
@@ -143,6 +153,20 @@
     call s:throw("Can't figure out what tag file to use for: " . a:path)
 endfunction
 
+" Get the tag filename for a given project root.
+function! s:get_tagfile(root_dir) abort
+    let l:tag_path = s:stripslash(a:root_dir) . '/' . g:autotags_tagfile
+    if g:autotags_cache_dir != ""
+        " Put the tag file in the cache dir instead of inside the
+        " projet root.
+        let l:tag_path = g:autotags_cache_dir . '/' .
+                    \tr(l:tag_path, '\/:', '---')
+        let l:tag_path = substitute(l:tag_path, '/\-', '/', '')
+    endif
+    let l:tag_path = s:normalizepath(l:tag_path)
+    return l:tag_path
+endfunction
+
 " Setup autotags for the current buffer.
 function! s:setup_autotags() abort
     if exists('b:autotags_file') && !g:autotags_debug
@@ -153,7 +177,8 @@
     " Try and find 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'))
+        let b:autotags_root = s:get_project_root(expand('%:h'))
+        let b:autotags_file = s:get_tagfile(b:autotags_root)
     catch /^autotags\:/
         call s:trace("Can't figure out what tag file to use... no autotags support.")
         return
@@ -260,8 +285,10 @@
     " Figure out where to save.
     if a:0 == 1
         let l:tags_file = a:1
+        let l:proj_dir = fnamemodify(a:1, ':h')
     else
         let l:tags_file = b:autotags_file
+        let l:proj_dir = b:autotags_root
     endif
     
     " Check that there's not already an update in progress.
@@ -292,14 +319,11 @@
         " Build the command line.
         let l:cmd = s:get_execute_cmd() . s:runner_exe
         let l:cmd .= ' -e "' . g:autotags_executable . '"'
-        let l:cmd .= ' -t "' . fnamemodify(l:tags_file, ':t') . '"'
+        let l:cmd .= ' -t "' . l:tags_file . '"'
+        let l:cmd .= ' -p "' . l:proj_dir . '"'
         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 .= ' -s "' . l:rel_path . '"'
+            let l:full_path = expand('%:p')
+            let l:cmd .= ' -s "' . l:full_path . '"'
         endif
         for ign in split(&wildignore, ',')
             let l:cmd .= ' -x ' . ign
@@ -315,9 +339,9 @@
         endif
         if g:autotags_trace
             if has('win32')
-                let l:cmd .= ' -l "' . fnamemodify(l:tags_file, ':t') . '.log"'
+                let l:cmd .= ' -l "' . l:tags_file . '.log"'
             else
-                let l:cmd .= ' > "' . fnamemodify(l:tags_file, ':t') . '.log" 2>&1'
+                let l:cmd .= ' > "' . l:tags_file . '.log" 2>&1'
             endif
         else
             if !has('win32')