dotar/vim/plugin/autotag.vim
2011-11-17 16:00:49 -06:00

206 lines
6.1 KiB
VimL

" Increment the number below for a dynamic #include guard
let s:autotag_vim_version=1
if exists("g:autotag_vim_version_sourced")
if s:autotag_vim_version == g:autotag_vim_version_sourced
finish
endif
endif
let g:autotag_vim_version_sourced=s:autotag_vim_version
" This file supplies automatic tag regeneration when saving files
" There's a problem with ctags when run with -a (append)
" ctags doesn't remove entries for the supplied source file that no longer exist
" so this script (implemented in python) finds a tags file for the file vim has
" just saved, removes all entries for that source file and *then* runs ctags -a
if has("python")
python << EEOOFF
import os
import string
import os.path
import fileinput
import sys
import vim
import time
# Just in case the ViM build you're using doesn't have subprocess
if sys.version < '2.4':
def do_cmd(cmd, cwd):
old_cwd=os.getcwd()
os.chdir(cwd)
(ch_in, ch_out) = os.popen2(cmd)
for line in ch_out:
pass
os.chdir(old_cwd)
import traceback
def format_exc():
return ''.join(traceback.format_exception(*list(sys.exc_info())))
else:
import subprocess
def do_cmd(cmd, cwd):
p = subprocess.Popen(cmd, shell=True, stdout=None, stderr=None, cwd=cwd)
from traceback import format_exc
def echo(str):
str=str.replace('\\', '\\\\')
str=str.replace('"', "'")
vim.command("redraw | echo \"%s\"" % str)
def diag(verbosity, threshold, msg, args = None):
if msg and args:
msg = msg % args
if verbosity >= threshold:
echo(msg)
def goodTag(line, excluded):
if line[0] == '!':
return True
else:
f = string.split(line, '\t')
if len(f) > 3 and not f[1] in excluded:
return True
return False
class AutoTag:
__maxTagsFileSize = 1024 * 1024 * 7
__threshold = 1
def __init__(self):
self.tags = {}
self.excludesuffix = [ "." + s for s in vim.eval("g:autotagExcludeSuffixes").split(".") ]
verbosity = long(vim.eval("g:autotagVerbosityLevel"))
self.verbosity = verbosity if verbosity > 0 else 0
self.sep_used_by_ctags = '/'
self.ctags_cmd = vim.eval("g:autotagCtagsCmd")
self.tags_file = str(vim.eval("g:autotagTagsFile"))
self.count = 0
def findTagFile(self, source):
self.__diag('source = "%s"' % (source, ))
( drive, file ) = os.path.splitdrive(source)
while file:
file = os.path.dirname(file)
#self.__diag('drive = "%s", file = "%s"' % (drive, file))
tagsFile = os.path.join(drive, file, self.tags_file)
#self.__diag('tagsFile "%s"' % tagsFile)
if os.path.isfile(tagsFile):
st = os.stat(tagsFile)
if st:
size = getattr(st, 'st_size', None)
if size is None:
self.__diag("Could not stat tags file %s" % tagsFile)
return None
if AutoTag.__maxTagsFileSize and size > AutoTag.__maxTagsFileSize:
self.__diag("Ignoring too big tags file %s" % tagsFile)
return None
return tagsFile
elif not file or file == os.sep or file == "//" or file == "\\\\":
#self.__diag('bail (file = "%s")' % (file, ))
return None
return None
def addSource(self, source):
if not source:
self.__diag('No source')
return
if os.path.basename(source) == self.tags_file:
self.__diag("Ignoring tags file %s" % (self.tags_file,))
return
(base, suff) = os.path.splitext(source)
if suff in self.excludesuffix:
self.__diag("Ignoring excluded suffix %s for file %s" % (source, suff))
return
tagsFile = self.findTagFile(source)
if tagsFile:
relativeSource = source[len(os.path.dirname(tagsFile)):]
if relativeSource[0] == os.sep:
relativeSource = relativeSource[1:]
if os.sep != self.sep_used_by_ctags:
relativeSource = string.replace(relativeSource, os.sep, self.sep_used_by_ctags)
if self.tags.has_key(tagsFile):
self.tags[tagsFile].append(relativeSource)
else:
self.tags[tagsFile] = [ relativeSource ]
def stripTags(self, tagsFile, sources):
self.__diag("Stripping tags for %s from tags file %s", (",".join(sources), tagsFile))
backup = ".SAFE"
input = fileinput.FileInput(files=tagsFile, inplace=True, backup=backup)
try:
for l in input:
l = l.strip()
if goodTag(l, sources):
print l
finally:
input.close()
try:
os.unlink(tagsFile + backup)
except StandardError:
pass
def updateTagsFile(self, tagsFile, sources):
tagsDir = os.path.dirname(tagsFile)
self.stripTags(tagsFile, sources)
if self.tags_file:
cmd = "%s -f %s -a " % (self.ctags_cmd, self.tags_file)
else:
cmd = "%s -a " % (self.ctags_cmd,)
for source in sources:
if os.path.isfile(os.path.join(tagsDir, source)):
cmd += " '%s'" % source
self.__diag("%s: %s", (tagsDir, cmd))
do_cmd(cmd, tagsDir)
def rebuildTagFiles(self):
for (tagsFile, sources) in self.tags.items():
self.updateTagsFile(tagsFile, sources)
def __diag(self, msg, args = None):
diag(self.verbosity, AutoTag.__threshold, msg, args)
EEOOFF
function! AutoTag()
python << EEOOFF
try:
if long(vim.eval("g:autotagDisabled")) == 0:
at = AutoTag()
at.addSource(vim.eval("expand(\"%:p\")"))
at.rebuildTagFiles()
except:
diag(1, -1, format_exc())
EEOOFF
if exists(":TlistUpdate")
TlistUpdate
endif
endfunction
if !exists("g:autotagDisabled")
let g:autotagDisabled=0
endif
if !exists("g:autotagVerbosityLevel")
let g:autotagVerbosityLevel=0
endif
if !exists("g:autotagExcludeSuffixes")
let g:autotagExcludeSuffixes="tml.xml.text.txt"
endif
if !exists("g:autotagCtagsCmd")
let g:autotagCtagsCmd="ctags"
endif
if !exists("g:autotagTagsFile")
let g:autotagTagsFile="tags"
endif
augroup autotag
au!
autocmd BufWritePost,FileWritePost * call AutoTag ()
augroup END
endif " has("python")
" vim:shiftwidth=3:ts=3