I’ve been using Tim Pope’s effortless
ctags with git blog post to keep my tags file up to date. The gist
of it is to keep your tags file in .git/tags
(if you have
the excellent vim-fugitive installed
vim is configured to look there) and update your tags file whenever the
working tree changes. This comes in two parts: a script to update
.git/tags
, and hooks to call that script.
Following Tim Pope’s advice, and the advice of some of his commenters, I ended up with a script to update the tags that looked something like this:
#! /bin/sh
GITDIR=$(git rev-parse --git-dir)
TAGSFILE=tags.$$
mkdir $GITDIR/tags_lock 2>/dev/null || exit 0
trap "rmdir $GITDIR/tags_lock; rm $GITDIR/$TAGSFILE" EXIT
ctags --tag-relative -Rf $GITDIR/$TAGSFILE --exclude=$GITDIR
mv $GITDIR/$TAGSFILE $GITDIR/tags
This uses exuberant ctags
to generate the tags file, and uses directory based locking1 so that a large rebase does not
start tons of processes. git rev-parse --git-dir
gets the
git directory, and using it makes this work with submodules2.
This works great for the languages that exuberant ctags supports, but unfortunately haskell is not one of those languages. This means we need to add in support for haskell tags.
The haskell wiki lists some possible solutions.
.ghci
file, but we
can’t rely on that.We could simply append the tags produced by hasktags to the tags from
ctags, but vim expects tags files to be sorted (so it can binary
search them). We must append then sort (using
LC_COLLATE=C
as advised here).
# exuberant ctags
ctags --tag-relative -Rf $GITDIR/$TAGSFILE --exclude=$GITDIR
# hasktags
if which hasktags > /dev/null ; then
OLD_DIR=$(pwd)
(cd $GITDIR && hasktags -c -x --ignore-close-implementation -a -f $TAGSFILE $OLD_DIR)
LC_COLLATE=C sort $GITDIR/$TAGSFILE -o $GITDIR/$TAGSFILE
fi
Explanation of hasktags options:
-c
means generate a vim (not emacs) format tags
file,-x
means generate additional information,--ignore-close-implementation
avoids tagging both type
signatures and implementations if the implementation is near the type
signature.-a
means append-f
specifies output fileFull script available as a gist
Thanks Rich Healy.↩︎