Skip to content

Instantly share code, notes, and snippets.

@tcarland
Last active March 4, 2018 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tcarland/32c285fb6230d1c18de65f48e9bd6ce5 to your computer and use it in GitHub Desktop.
Save tcarland/32c285fb6230d1c18de65f48e9bd6ce5 to your computer and use it in GitHub Desktop.
Configuring Vim for exuberant-ctags

Configuring Vim for ctags and Scala

This document configures Vim or GVim for auto-completion using Vim OmniComplete (built-in) and exuberant-ctags.

It should be noted that the exuberant-ctags project seems a bit dated, and potentially Universal Ctags is a better choice ctags.io.

  • Install exuberant-ctags:

    This document configurs

apt-get install exuberant-ctags
  • Install vim-pathogen

This makes installing vim plugins cleaner by placing plugins in .vim/bundle/

  $ cd ~/.vim
  $ mkdir autoload bundle
  $ cd autoload
  $ wget https://raw.githubusercontent.com/tpope/vim-pathogen/master/autoload/pathogen.vim
  • Configure vim for pathogen

Add the pathogen configuration to .vimrc

" pathogen
call pathogen#infect()
call pathogen#helptags()

" vim settings:
filetype plugin indent on
syntax on
  • Install the Scala plugin

The plugin should downloaded and placed in .vim/bundle/.

vim-scala can be found here: https://github.com/derekwyatt/vim-scala

  • Configure ctags

Ctags works by indexing all include paths and supports most languages. At the time of this document, this does not include Scala, but thanks to this https://leonard.io/blog/2013/04/editing-scala-with-vim/ we have settings to support scala by adding the following to ~/.ctags

-langdef=scala
--langmap=scala:.scala
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private[^ ]*|pro
tected)?[ \t]*class[ \t]+([a-zA-Z0-9_]+)/\4/c,classes/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private[^ ]*|pro
tected)?[ \t]*object[ \t]+([a-zA-Z0-9_]+)/\4/c,objects/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private[^ ]*|pro
tected)?[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*case class[ \t]+([a-zA-Z0
-9_]+)/\6/c,case classes/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private[^ ]*|pro
tected)?[ \t]*case object[ \t]+([a-zA-Z0-9_]+)/\4/c,case objects/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private[^ ]*|pro
tected)?[ \t]*trait[ \t]+([a-zA-Z0-9_]+)/\4/t,traits/
--regex-scala=/^[ \t]*type[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy|private[^ ]*(\[[a-z]*\])*
|protected)[ \t]*)*def[ \t]+([a-zA-Z0-9_]+)/\4/m,methods/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy|private[^ ]*|protected)[ 
\t]*)*val[ \t]+([a-zA-Z0-9_]+)/\3/l,constants/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy|private[^ ]*|protected)[ 
\t]*)*var[ \t]+([a-zA-Z0-9_]+)/\3/l,variables/
--regex-scala=/^[ \t]*package[ \t]+([a-zA-Z0-9_.]+)/\1/p,packages/

We also add our excludes for ctags via this file to simplify our ctag commands a bit:

--exclude=target
--exclude=examples
--exclude=.git
--exclude=.svn
--exclude=.hg
--exclude=node_modules
--exclude=bundle.js
--exclude=*.js.map
--exclude=*.min.*
--exclude=*.swp
--exclude=*.bak
--exclude=*.tar.*

You can validate this entry by running ctags --list-maps both before and after editing .ctags file.

Build Ctags index files
  • Create the directory ~/.vim/tags to store the ctag files we generate next.

  • Create the ctags build script

First we define a list of include projects that we would want to index. In this example, there are a few C++ libraries that I use extensively in other projects. I want to index these for auto-complete. There are also external projects that I want to index, which often require having the -dev version of packages installed.

ctags-build.sh

#!/bin/bash
#

TAGPATH="${HOME}/.vim/tags"

cd $TAGPATH
echo "Building ctags in ${TAGPATH}"


# --------------------
#  system libs

# c++
$(ctags-exuberant -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q \
  --language-force=C++ -f cpp /path/to/cpp_src)

# wxWidgets
$(ctags-exuberant -R --sort=yes --c++-kinds=+p --fields=+iaS --extra=+q \
  --language-force=C++ -f wx /usr/include/wx-3.0/)

# libxml2
$(ctags-exuberant -R --sort=yes --c++-kinds=+p --fields=+iaS --extra=+q \
  --language-force=C++ -f libxml2 /usr/include/libxml2/)

# --------------------
# local projects

$(ctags-exuberant -R --sort=yes --c++-kinds=+p --fields=+iaS --extra=+q \
  --language-force=C++ -f tcanetpp /home/tca/src/github/tcanetpp/)

$(ctags-exuberant -R --sort=yes --c++-kinds=+p --fields=+iaS --extra=+q \
  --language-force=C++ -f tcaxmlpp /home/tca/src/github/tcaxmlpp/)

$(ctags-exuberant -R --sort=yes --c++-kinds=+p --fields=+iaS --extra=+q \
  --language-force=C++ -f tcajson /home/tca/src/github/tcajson/)

Technically, if --language-force= is not set, ctags will automatically discover, so this is generally not needed.

So, as another example, we use a Apache Spark based library spark-hbase-client. In this case, we will index the project and Apache Spark, both scala projects, by adding the following to our script.

# spark 2.3.0
$(ctags-exuberant -R --sort=yes --exclude=*.js -f spark-2.3.0 /opt/hadoop/src/spark-2.3.0/)

# spark-hbase-client
$(ctags-exuberant -R --sort=yes -f spark-hbase-client /home/tca/src/github/spark-hbase-client/)

Running this script should now generate ctag files in ~/.vim/tags/. Each of this directories should be added to your .vimrc using set tags+=~/.vim/tags/tagname. The .vimrc example below demonstrates this.

  • Configure .vimrc

Lastly, we configure Vim for omnicomplete. There are other, newer vim plugins, such as neocomplete, but...this is not it. For clarity, the following is a complete .vimrc:

set tags+=~/.vim/tags/cpp
set tags+=~/.vim/tags/wx
set tags+=~/.vim/tags/libxml2
set tags+=~/.vim/tags/tcanetpp
set tags+=~/.vim/tags/tcaxmlpp
set tags+=~/.vim/tags/tcajson
set tags+=~/.vim/tags/spark-hbase-client
set tags+=~/.vim/tags/spark-2.3.0

" build .tags for current project via Ctrl-F12
map <C-F12> :!ctags-exuberant -R --sort=yes -f ./.tags<CR>

" OmniCppComplete
let OmniCpp_NamespaceSearch = 1
let OmniCpp_GlobalScopeSearch = 1
let OmniCpp_ShowAccess = 1
let OmniCpp_ShowPrototypeInAbbr = 1 " show function parameters
let OmniCpp_MayCompleteDot = 1 " autocomplete after .
let OmniCpp_MayCompleteArrow = 1 " autocomplete after ->
let OmniCpp_MayCompleteScope = 1 " autocomplete after ::
let OmniCpp_DefaultNamespaces = ["std", "_GLIBCXX_STD", "tcanetpp"]
" automatically open and close the popup menu / preview window
au CursorMovedI,InsertLeave * if pumvisible() == 0|silent! pclose|endif
set completeopt=menuone,menu,longest,preview

" pathogen
call pathogen#infect()
call pathogen#helptags()

" settings
set ofu=syntaxcomplete#Complete
set nocompatible
set expandtab
set sw=4
set vb
set sb
set si
set nocp
set history=50
set ruler
set showcmd
set cmdheight=2
set guifont=Inconsolata-g\ Medium\ 8
colors desert
filetype plugin on

Now completion targets should be offered <C-n> and <C-p> (next or previous match) and open declaration via <Ctrl-]> and <Ctrl-T> to get back.

Tagbar

Another cool plugin https://majutsushi.github.io/tagbar/. Just download the package and extract to ~/.vim/bundle (I rename it to tagbar). Add the following to .vimrc to enable:

nmap <F8> :TagbarToggle<CR>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment