(Day 23 of 30 Days of Blogging)
Ctags is the plugin-free way to do code navigation in vim.
For single projects it works great out of the box. Just build your ctags file and point vim at it. But what about when you have multiple distinct project directories but still need to frequently jump around between them? That calls for multiple ctags index files, and managing that can be a bit of a hassle.
So I wrote a little script called ctags-update
that builds an index and puts it in a special cache
directory. Vim uses that cache directory to load tags. When I’m done working on a project, I run
ctags-remove
to remove it from the cache.
Here’s ctags-update
:
#!/bin/sh -e
#
# Adds project tags to the global index.
tags_db="$HOME/.cache/vim-ctags"
# project_root=`git rev-parse --show-toplevel`
project_root="$PWD"
flattened=`echo $project_root | sed 's!/!%!g'`
# It's in a weird subdirectory with a single file called tags because the vim "tags" option doesn't
# support wildcards in the form ~/.cache/vim-ctags/*
mkdir -p "$tags_db"/"$flattened"
# Remember: Paths in the tags file must be absolute
if [ -d "$project_root/.git" ]; then
# Include only files tracked in git
git ls-files | awk -v pwd="$PWD/" '{print pwd $0}'
else
# Otherwise include ALL files
find "$project_root"/ -type f
fi | ctags -L - -f "$tags_db"/"$flattened"/tags
echo "Updated ctags for $project_root, to undo run ctags-remove."
Running this will place a tags file in ~/.cache/vim-ctags
. To remove it, just delete it, or use
ctags-remove
:
# project_root=`git rev-parse --show-toplevel`
project_root="$PWD"
tags_db="$HOME/.cache/vim-ctags"
flattened=`echo $project_root | sed 's!/!%!g'`
rm -r "$tags_db"/"$flattened"
And lastly configure vim to use the ctags cache directory:
set tags=$HOME/.cache/vim-ctags/*/tags
Now you just need to call ctags-update
whenever your code changes, but even that can be automated
away with git hooks. Once that’s
all set up, ctags fades into the background and you never have think about it.