I am always curious about other people’s vim workflow, especially when it comes to project management and goto definitions with ctags. I have now used vim quite some time and want to share my personal workflow. This is about how to create custom local vim configuration files per project and how to manage all of your ctag files easily.

TL;DR

So basically what I do is:

Go to my project root

Create vim project file

Create ctag files

Start coding

All done automatically with a one-liner:

$ make-vim-project all

1. The whole story

1.1 Install Dependencies

As I am currently using a MacBook due to work, I have to deal with OSX and therefore of course use homebrew to install my stuff. So first I need to get the exuberant version of ctags.

brew install ctags-exuberant

1.2 Vim and ctags

I am trying to separate programming languages into different ctag files. For example, one file for c/c++ , one file for shell-scripts , one file for javascript and so on. For this to work, I need to tell vim where to look for the files. The vim section looks like this:

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " CTAGS/CSCOPE """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " Default/Generic tag file set tags=tags,.tags " Filetype specific tag files (This is used for global IDE tags) autocmd FileType c set tags=.tags_cpp,$HOME/.vim/tags/cpp autocmd FileType cpp set tags=.tags_cpp,$HOME/.vim/tags/cpp autocmd FileType css set tags=.tags_css,$HOME/.vim/tags/css autocmd FileType java set tags=.tags_java,$HOME/.vim/tags/java autocmd FileType javascript set tags=.tags_js,$HOME/.vim/tags/js autocmd FileType html set tags=.tags_html,$HOME/.vim/tags/html autocmd FileType php set tags=.tags_php,$HOME/.vim/tags/php autocmd FileType sh set tags=.tags_sh,$HOME/.vim/tags/sh

1.3 Vim and project files

Now I need a way to always tell vim where my project root is in order for it to look for the project specific ctag files. For this I am using local_vimrc via NeoBundle. Here is how to get it into vim.

" ---- PROJECT vimrc NeoBundle 'LucHermitte/lh-vim-lib', { \ 'name': 'lh-vim-lib' \} NeoBundle 'LucHermitte/local_vimrc', { \ 'depends': 'lh-vim-lib' \}

This plugin will check the root directory for a file called _vimrc_local.vim . The only thing I want to place into this file is the cd path, so it know the root of the project directory.:

$ cat /path/to/project/_vimrc_local.vim :cd /path/to/project

Whenever I open vim from within this project path, it will check if there a ctag files as defined in vim and ctags above.

1.4 Creating project and ctag files

The setup is almost complete and I just need to create the project and ctag files for every project in its root. So first creating the project file:

$ cd /path/to/project && echo ":cd $(pwd)" > _vimrc_local.vim

And then I will add the ctag files. Here is an example for a c/c++ project:

$ ctags -R -f .tags_cpp \ --file-scope=yes \ --sort=yes \ --c++-kinds=+p \ --fields=+iaS \ --extra=+q \ 2>/dev/null

This kind of sucks as I don’t want to issue those long commands every time I create a new project or update my ctags. So it needs to be automated or at least simplified.

1.5 Using a bash functions for project and ctag files

On the most simple form I just want to issue a single command which does everything for me. So I wrote a bash function make-vim-project :

$ make-vim-project Usage: make-vim-project <type> all Create ctags for every filetype web Create ctags for php, js, css and html cpp Create ctags for c/c++ shell Create ctags for bash/sh

Now I can create a c/c++ project easily by just typing this:

$ make-vim-project cpp

It will automatically create the _vimrc_local.vim as shown above and all c/c++ relevant ctag files. I also use this command once I update my project. So how does the function look and where do I put it?

First, it can be put anywhere in .bash_profile , .bashrc or any other custom bash file that is sourced by the main bash configuration file. Let’s have a look at the function itself:

#------------------------------------------------------ #-------- Vim Project make-vim-project() { local name dir name="_vimrc_local.vim" dir="$(pwd)" read -r -d '' USAGE <<-'EOF' Usage: make-vim-project <type> all Create ctags for every filetype web Create ctags for php, js, css and html cpp Create ctags for c/c++ shell Create ctags for bash/sh EOF if [ $# -ne 1 ]; then echo "$USAGE" return fi # CTAGS echo "Building ctags" if [ "$1" == "all" ]; then make-ctags make-ctags-css make-ctags-js make-ctags-html make-ctags-php make-ctags-sql make-ctags-shell make-ctags-cpp elif [ "$1" == "web" ]; then make-ctags-php make-ctags-html make-ctags-js make-ctags-css make-ctags-sql elif [ "$1" == "cpp" ]; then make-ctags-cpp elif [ "$1" == "shell" ]; then make-ctags-shell else echo "$USAGE" return fi # Vimrc echo "Creating local vimrc" echo ":cd ${dir}" >> "${name}" }

As you can see, the function just prints its usage, calls other make-ctags-* functions and creates the _vimrc_local.vim file. Have a look at the gist for the complete source of all other make-ctags-* functions:

cytopia/create-vim-project

Just for clarification, here is how one of the ctag functions will look:

make-ctags-cpp() { ctags -R -f .tags_cpp \ --file-scope=yes \ --sort=yes \ --c++-kinds=+p \ --fields=+iaS \ --extra=+q \ 2>/dev/null }

1.6 Project root

Let’s have a look what files are inside my project root after using make-vim-project all :

$ ls -la ... -rw-r--r-- 1 cytopia 1286676289 73381097 Oct 17 12:01 .tags -rw-r--r-- 1 cytopia 1286676289 72893221 Oct 17 12:02 .tags_cpp -rw-r--r-- 1 cytopia 1286676289 1776509 Oct 17 12:01 .tags_css -rw-r--r-- 1 cytopia 1286676289 409973 Oct 17 12:01 .tags_html -rw-r--r-- 1 cytopia 1286676289 64329626 Oct 17 12:01 .tags_js -rw-r--r-- 1 cytopia 1286676289 8989441 Oct 17 12:01 .tags_php -rw-r--r-- 1 cytopia 1286676289 6223 Oct 17 12:01 .tags_sh -rw-r--r-- 1 cytopia 1286676289 52748 Oct 17 12:01 .tags_sql -rw-r--r-- 1 cytopia 1286676289 32 Oct 17 12:02 _vimrc_local.vim

2. What next?

This workflow has evolved during over a year of vim experience and as my personal preference. I am still not quite satisfied with some manual work, especially for updating the ctags once you have added code. If any of you have some better workflows and/or can recommend other vim plugins that do the trick more automated, please let me know and share.

_