Hello,

The question is a classic on r/vim and comes occasionally on #vim on freenode : is my vimrc “good” and what should I do to make it “better” ? I am by no means a vim expert and I don’t really know what a “good” vimrc should be. So anything that I do here is not necessarily good ; I just want to explain why I made some decisions for my configuration.

For the context, I’m using vim as a text editor for C family code (including one big C++98 project)

Like a lot of people before me, I started by using a lot of plugins in vim, and keeping them up-to-date and installing them was something I deemed non-important that I left to plugin managers. After encountering my first plugin issue (how to properly handle out-of-source compilation databases using YCM), I thought that all that time spent looking into the behaviour of this plugin could be spent trying to understand how vim works and how I could use as few plugins as possible to avoid going through this again.

My current vimrc is always on Github, but this is not always streamlined so there is a little explanation for each of the big parts. Also, for a lot of plugins there is a fold for its specific options, and I decided not to talk about these, since it’s really detailed in their documentation. The point of this post is to explain some plugin choices.

Auto-source vimrc

augroup VimrcAutoSource
autocmd!
autocmd BufWritePost $MYVIMRC nested source $MYVIMRC
augroup END

This small snippet automatically sources my vimrc file when I write it to disk. Nothing much to say here, it’s just a convenience when I’m trying new settings in a split.

Plugin Manager

I’m still using a plugin manager today because, even though knowing how vim loads plugins is interesting, updating the plugins can be a chore. I chose to use Plug as a plugin manager because it also allows conditionnal loading, but I’m not using it yet. Since the loading command for plugins is mostly a github address, it’ll also be easier for you to check them out if you want to.

Plugins

I am currently loading 18 plugins each time I start up vim, and a few of them could certainly only be loaded for certain filetypes (namely Python and C-family). I’ll go quickly through each one.

Snippets

Plug 'SirVer/ultisnips'
Plug 'honza/vim-snippets'

I’m using Ultisnips because it looked like it was easier to create our own snippets. We are using a custom markup languauge at work which can be tedious at times, and having a handful of snippets makes editing files in this language a lot easier. honza/vim-snippets is a repository full of “default” snippets, that I still did not use, but it’s light and it’s good to know it’s here for when I don’t want to write the same boilerplate over and over.

Testing

Plug 'junegunn/vader.vim'

I installed this vimscript test framework when I submitted a pull request for another plugin I’m using (ale). Not much else to say, it does what it does and I will surely remove it as I don’t plan on needing it anytime soon.

Linting

Plug 'w0rp/ale'
Plug 'rhysd/vim-clang-format'
Plug 'tell-k/vim-autopep8'

Clang-format and vim-autopep8 are C-family and Python linters that also modify the buffer whenever I want thanks to autocommands. It’s a convenience to only concentrate on code.

The big linter I’m using is ALE, mostly for being an asynchronous :make wrapper that shows me mistakes before I try to compile. I used to use Syntastic but the async feature proved necessary quickly : I had issues with a project big enough so vim took 10 seconds to leave me in normal mode after opening a files. The main linters I use with ale are pylint, clang and clangcheck, vint and lacheck for latex files. Having a proper setting to use pylint or pylint-3 is the next step to enhance my experience with Python linting.

Completion plugins

Plug 'lifepillar/vim-mucomplete'
Plug 'Gagbo/clang_complete'
Plug 'lervag/vimtex'

I chose mucomplete for the completion engine because to me it seemed better integrated and easier to control than VCM.

This completion plugin works really well with clang\_complete (currently forked because I want a better support for out-of-source builds), which uses libclang capabilities (around LibTooling) to propose proper omni completion for C and C++. I used the tags-powered OmniCppComplete after YCM because I wanted to use an “as bare as possible” approach, but when I saw the 2 Gb tags file for /usr/include, I thought that a python-powered approach was better, since I really wanted to have context-aware code completion. Similarly, vimtex proposes context-aware completion when editing LaTeX files, and a very nice continuous compilation feature (which updates the pdf file on write).

Miscellaneous

Plug 'romainl/Apprentice'
Plug 'tpope/vim-fugitive'
Plug 'tpope/vim-unimpaired'
Plug 'tpope/vim-surround'
Plug 'tpope/vim-commentary'
Plug 'romainl/vim-qf'
Plug 'tommcdo/vim-lion'
Plug 'vim-scripts/a.vim'
Plug 'romainl/vim-cool'

All of these plugins add a functionality that I did not want to implement myself (and, for the most part, that I can’t implement myself).

motion/text-objects

  • qf enhances quickfix list
  • lion gives a mapping to arbitrarily align lines
  • a gives a mapping to switch between header

and implementation files

  • cool handles search highlighting

Set Commands

These commands are my “basics” of vim. They should not depend on the plugins I choose, but the plugins I want should depend on the settings I am using in this block. For the most part, the comments should be enough, there won’t be a lot of text.

Files loading

    " Helper files loading {{{2
    set exrc
    set secure
    set tags=tags;
    set path=.,/usr/include,**,,build;
    " 2}}}

These commands allow vim to use project local .vimrc configuration files, and also help find the right files for built-in commands.

Backups and undo files

    " Backups and Undo File {{{2
    if has('vms')
        set nobackup                        " do not keep a backup file, use versions instead
    else
        set backup                          " keep a backup file (restore to previous version)
        set backupdir=./.backup,/tmp        " Hides the backup files if the folder is created
        set undofile                        " keep an undo file (undo changes after closing)
        set undodir=./.backup,/tmp          " Hides the backup files if the folder is created
    endif
    set wildignore+=~,*.o,*.obj,*.swp
    " 2}}}

Editor panel

    " Editor window options {{{2
    if &t_Co > 2 || has('gui_running')
        syntax on
        " Also switch on highlighting the last used search pattern.
        set hlsearch
    endif
    set autoindent
    set number
    set ruler        " show the cursor position all the time
    set scrolloff=5  " Start scrolling 5 lines from border
    set incsearch    " do incremental searching

    set diffopt=filler,vertical

    set foldmethod=marker
    set foldcolumn=3
    set foldlevelstart=999
    " 2}}}

Buffer options

    " Buffer options {{{2
    set hidden
    highlight ColorColumn ctermbg=magenta
    " call matchadd('ColorColumn', '\%81v', 100)
    set switchbuf=useopen,usetab,split
    set listchars=tab:»·,trail:·,nbsp:~
    set list
    " 2}}}

Statusline

    " StatusLine options {{{2
    set titlestring=%t%(\ %M%)%(\ (%{expand(\"%:~:h\")})%)
    set laststatus=2   "Always (=2) display a statusline
    set statusline=%{fugitive#statusline()}%f%m%r%h%w\ %y%<%=%{ALEGetStatusLine()}[%{&ff}][%p%%][Line\ %04l/%04L,Col\ %v]
    "                                      | | | | |   | | |                       |       |           |    |         |
    "                                      | | | | |   | | |                       |       |           |    |         +-- current column
    "                                      | | | | |   | | |                       |       |           |    +-- Number of lines
    "                                      | | | | |   | | |                       |       |           +-- current line
    "                                      | | | | |   | | |                       |       +-- current % into file
    "                                      | | | | |   | | |                       +-- current fileformat
    "                                      | | | | |   | | +-- Right align starting here
    "                                      | | | | |   | +-- truncate here if too long
    "                                      | | | | |   +-- current ft
    "                                      | | | | +-- preview flag in square brackets
    "                                      | | | +-- help flag in square brackets
    "                                      | | +-- readonly flag in square brackets
    "                                      | +-- modified flag in square brackets
    "                                      +-- Path to the file in the buffer, as typed or relative to current directory.

    " 2}}}

Command Window

    " Command window options {{{2
    set history=50     " keep 50 lines of command line history
    set showcmd        " display incomplete commands
    set wildmenu
    set wildmode=longest:full,full
    " 2}}}

Tabs, spaces and backspace

    " Tabulations and Keystrokes behaviour{{{2
    set mouse=a
    set mousemodel=popup
    set backspace=indent,eol,start

    set shiftwidth=4
    " Use sw value for sts
    set softtabstop=-1
    set smarttab
    set expandtab
    " 2}}}

Completion

    " Completion behaviour{{{2
    set completeopt+=menuone
    set completeopt+=menu
    set completeopt+=preview
    set completeopt+=noinsert

    " incl and tags are included as mucomplete chains so we can remove these from
    " <C-N> / <C-P> completion
    set complete-=i
    set complete-=t

    set shortmess+=c " less verbose vim during completion
    set noinfercase
    " 2}}}

Mappings and colour options

Those settings are mostly personal, <F8> is the ctags command to use with OmniCppComplete, and the myHelpers functions are copied from D. Conway and romainl

    " Mapping {{{1
    " Tag related {{{2
    map <C-p> :tab split<CR>:exec("tag ".expand("<cword>"))<CR>
    nnoremap gt <C-]>
    nnoremap <F8> :!ctags -R --sort=yes --c++-kinds=+pl --fields=+iaS --extra=+q .<CR><CR>
    " 2}}}

    " Buffer navigation {{{2
    nnoremap gb :ls<CR>:b<Space>
    nnoremap <PageUp>   :bprevious<CR>
    nnoremap <PageDown> :bnext<CR>
    " 2}}}

    " Window navigation {{{2
    map <C-h> <C-w>h
    map <C-j> <C-w>j
    map <C-k> <C-w>k
    map <C-l> <C-w>l

    " 2}}}

    " Search highlighting {{{2
    nnoremap <silent> n n:call myHelpers#HLNext(0.2)<CR>
    nnoremap <silent> N N:call myHelpers#HLNext(0.2)<CR>
    "  2}}}

    " US Keyboard keybinds {{{2
    noremap ; :
    noremap : ;
    " 2}}}
    " 1}}}

    " Colorschemes {{{1
    augroup MyColors
    autocmd!
        autocmd ColorScheme * call myHelpers#MyHighlights()
    augroup END

    colorscheme apprentice
    " 1}}}

    " Gui Options {{{1
    set guifont=Hack\ 11
    set guioptions+=i
    set guioptions-=T
    " 1}}}

The End

I hope you enjoyed the ride ! The next post should be my coming back to nand2tetris, hopefully soon. Stay safe, Gerry