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).
- Apprentice is a nice dark, low-contrast colourscheme
- Fugitive is a git wrapper
- Unimpaired adds a lot of [<key> ]<key> bindings
- Surround gives a mapping to surrounding text-objects
- Commentary gives a mapping to comment
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