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'
endif
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>')
else
call CocAction('doHover')
endif
endfunction
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'}
else
Plug 'vim-python/python-syntax'
endif
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
" https://stackoverflow.com/a/42078499/
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)
endfun
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
endif
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!