My .vimrc

Kevin Guillaumond

May 22, 2021

I’ve been using vim as my main editor for about two years now, and I thought I’d explain the cool parts of my config here.

Getting started with vim is difficult. As I’m sure many people before me I’ve done, I started by copying a basic config from the Internet. Not everything made sense but things were at least usable. I also read VIM and Python – A Match Made in Heaven. There are some good ideas there.

My full vimrc can be found on SourceHut, along with some language-specific configs.

Interestingly, I probably won’t be using a vimrc file for very long. Neovim (the fork of vim that I’m actually using) can be configured in Lua, starting at version 0.5. I’m currently getting my config ready for neovim 0.5, which brings a lot of cool features to vim. My vim config will then live in init.lua but I’ll keep my vimrc file around, for the times when neovim 0.5 isn’t available.

let mapleader = ","
let g:mapleader = ","

I set my leader to ,. Some people prefer to set it to the space bar because it’s accessible from either hand.

General plugins

Plug 'junegunn/vim-plug'

VimPlug is my plugin manager. I used to use Vundle but that has been abandonned some time ago. VimPlug is very similar. With neovim 0.5 I’ll probably move to a Lua-based manager, such as paq-nvim.

Plug 'scrooloose/nerdtree'     " View of the file system

NERDTree is the first plugin I’ve installed, because I was missing the file explorer view that IDEs have. I have since learned that vim has this functionality built-in, so this plugin may not be necessary.

Here’s my config for it. I think it’s pretty self-explanatory. I do my best to add a comment to every line in my vim config!

" Open NERDTree by default
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif

" Shortcut to open NERDTree
nnoremap <leader>ne :NERDTreeToggle<Enter>

" Ignore some files
let NERDTreeIgnore=['\.pyc$', '\~$']

" Automatically close NERDTree when you open a file
let NERDTreeQuitOnOpen = 1

" Automatically close a tab if the only remaining window is NERDTree
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
Plug 'morhetz/gruvbox'         " Color scheme
Plug 'ctrlpvim/ctrlp.vim'      " Fuzzy search for files
Plug 'vim-airline/vim-airline' " Status line at the bottom
Plug 'mileszs/ack.vim'         " ack/ag in vim

gruvbox is quite a nice color scheme. I’ve used minimalist before, but this is a clear improvement.

CtrlP is actually not a plugin I use a lot, even though I think it would make me a bit more efficient. I’m looking to replace it with telescope.nvim in neovim 0.5.

vim-airline is a nice status line that just works. One day, I’ll replace it with a custom one in Lua. One day…

ack.vim is just a wrapper over ag. My config for it could be improved, to make it a bit more project-aware:

nnoremap <leader>aa :Ack!<space>

" Search for word under cursor (overwrites p registry)
nnoremap <leader>aw "pyiw:Ack!<space><C-R>p<cr>

" Search for selection (overwrites p registry)
vnoremap <leader>as "py:Ack!<space><C-R>p<cr>

if executable('ag')
  let g:ackprg = 'ag --vimgrep --path-to-ignore ~/.ignore --follow'
Plug 'embear/vim-localvimrc'   " Local vimrc files for project-specific settings

This one is super nice. At work, different projects have different settings. This plugin allow me to have an .lvimrc file at the root of the project. Any setting in that file overrides the setting in the base vimrc for every file of the project. A must have.

Language-agnotic programming plugins

Plug 'vim-syntastic/syntastic' " Syntax checker

Integrates syntax checkers. I use pylint and flake8 for Python.

Plug 'tpope/vim-surround'      " Act on surrounding things like quotes and HTML tags
Plug 'tpope/vim-repeat'        " Repeat certain commands such as surround
Plug 'tpope/vim-commentary'    " Comment/uncomment code
Plug 'AndrewRadev/sideways.vim' " Move function arguments left and right

vim-surround adds s as a “vim noun” for surrounding things. For example, cs'" changes surrounding ' to ". ds" would then delete the quotes, etc. Something I no longer want to live without! vim-repeat allows these custom actions to be repeated using ., so pressing . after something like ds" does what you expect.

vim-commentary adds gc as a “vim verb” to comment/uncomment code: gcc comment the current line, g} comments until the end of the paragraph, g$ until the end of the file, etc. Also something I no longer want to live without!

vim-sideways allows to move arguments within an argument list, for example when you want to update [1, 2, 3] to be [1, 3, 2]. It’s not often useful but very appreciated when it is.

Plug 'janko/vim-test'          " Run tests

" Using ,tj because ,tn is used by tabs
nmap <silent> <leader>tj :TestNearest<CR>
nmap <silent> <leader>tf :TestFile<CR>
nmap <silent> <leader>ts :TestSuite<CR>
nmap <silent> <leader>tl :TestLast<CR>
nmap <silent> <leader>tg :TestVisit<CR>

This plugin makes it easy to run tests without leaving vim. Unfortunately I was already using ,tn to create a new vim tab, so I use ,tj to run the test that’s nearest to the cursor.

Plug 'tpope/vim-fugitive'      " git integration
Plug 'airblade/vim-gitgutter'  " Shows git diff in the 'gutter' (sign column)

I don’t use vim-fugitive too much - it’s mostly to use git blame from the editor. vim-gitgutter shows you a marker for lines you’ve added/changed/removed compared to what’s checked in git.

Something like gitlinker.nvim would also be useful, to create shareable git permalinks. I often find myself wanting to share a link to a block of code, and currently my best option is to open GitHub and navigate to the file that I already have open in vim.

Plug 'neoclide/coc.nvim', {'branch': 'release'}  " Intellisense engine 
Plug 'ludovicchabant/vim-gutentags'  " Keep tags files up to date

" Use K to show documentation in preview window.
nnoremap <silent> K :call <SID>show_documentation()<CR>

function! s:show_documentation()
  if (index(['vim','help'], &filetype) >= 0)
    execute 'h '.expand('<cword>')
    call CocAction('doHover')

coc.nvim is a Language Server Protocol client that I really don’t use to its full potential. Autocompletion works well out of the box. I haven’t taken the time to fine tune it, but I’m looking to replace it with Neovim 0.5’s built-in LSP client.

I really like the idea of overloading K to show the docs of whatever is under the cursor, while keeping the default behaviour (showing vim help) as a backup.

vim-gutentags manages the tag files, but I also haven’t spent too much time configuring it, so a lot of the time I can’t navigate to the tag I want. Things should get better (at least easier to configure) with Neovim’s LSP client.

Python-specific plugins

" Better syntax highlighting
if has('nvim')
  Plug 'numirias/semshi', {'do': ':UpdateRemotePlugins'}
  Plug 'vim-python/python-syntax'
Plug 'nvie/vim-flake8'           " Python style checker

semshi is the reason I went from vim to neovim, because it’s such an improvement. It uses different colors for method parameters vs member variables, shows unused parameters and undefined variables, etc.

It doesn’t support Python 2, which I suppose is another motivation to make things work in Python 3.

Random cool things

" Quickly edit/reload the vimrc file
nmap <silent> <leader>ev :e ~/.vimrc<CR>
nmap <silent> <leader>sv :so ~/.vimrc<CR>

Gotta make it easier to work on the vim config :)

" Show the number of the current line and the relative number of the others
set number
set relativenumber

" Show absolute numbers when in insert mode or losing focus
:augroup numbertoggle
:  autocmd!
:  autocmd BufEnter,FocusGained,InsertLeave * set relativenumber
:  autocmd BufLeave,FocusLost,InsertEnter   * set norelativenumber
:augroup END

It’s probably well-known at this point, but having relative numbers is great. I like this config because it uses relative numbers when and only when it makes sense.

" Visual mode pressing * or # searches for the current selection
vnoremap <silent> * :<C-u>call VisualSelection('', '')<CR>/<C-R>=@/<CR><CR>
vnoremap <silent> # :<C-u>call VisualSelection('', '')<CR>?<C-R>=@/<CR><CR>

This is great because it makes * and # work the way you expect in visual mode.

" Map j to gj so vim behaves as expected with wrapped lines
" But keep normal behaviour if doing something like 4j
nnoremap <expr> j v:count ? 'j' : 'gj'
nnoremap <expr> k v:count ? 'k' : 'gk'

" Smart way to move between windows
map <C-j> <C-W>j
map <C-k> <C-W>k
map <C-h> <C-W>h
map <C-l> <C-W>l

" Show list of tags if there are multiples matches
nnoremap <C-]> g<C-]>

Small navigation things that are difficult to live without, once you got used to them.

" Map Y to act like D and C, i.e. to yank until EOL, rather than act as yy,
" which is the default
map Y y$

" Don't write to yank buffer when deleting a single character
noremap x "_x
noremap X "_X

Small quality of life improvements.

" Delete trailing white space on save
fun! CleanExtraSpaces()
    let save_cursor = getpos(".")
    let old_query = getreg('/')
    silent! %s/\s\+$//e
    call setpos('.', save_cursor)
    call setreg('/', old_query)

I honestly don’t know how this works (also why I’m looking forward to moving to a Lua config), but it’s great.

" Enable folding with the spacebar
nnoremap <space> za

Some people use the spacebar as their leader key. I got used to this behaviour instead, for better or for worse.

" Remove the Windows ^M - when the encodings gets messed up
noremap <leader>m mmHmt:%s/<C-V><cr>//ge<cr>'tzt'm

Maddening when you don’t have it because it’s your vimrc that’s messed up…

" Quickly open a scratchpad for scribble
map <leader>q :e ~/scratchpad<cr>

Super useful!

if filereadable(glob("~/.vimrc.local"))
    source ~/.vimrc.local

For machine-specific vim config; it’s at the end of the file so local settings take precedence.

And that’s my vim config! Again, you can find the full file on SourceHut.

This has been working pretty well for me over the past two years, and I really like that my editor gets better over time. I’m also looking forward to having a config file ready for Neovim 0.5. Exciting times!