Permalink
Browse files

Auto Tag plugin

  • Loading branch information...
arthurgeek committed Sep 9, 2011
1 parent bcf08b3 commit 4408b2744cc61238349bb1952d71b24781e49814
Showing with 205 additions and 0 deletions.
  1. +205 −0 plugin/autotag.vim
View
@@ -0,0 +1,205 @@
+" 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

0 comments on commit 4408b27

Please sign in to comment.