How I use Vim

This is my .vimrc file. 
There are many like it, but this one is mine.

Outline

Introduction

I've used vim as my primary editor/IDE for the past 10 years. Back then I was writing data-analysis code over an ssh session to hosts in the SLAC computing center in California while sitting several thousand miles away in front of a terminal in the UK and a friendly post-doc showed me this nifty looking editor that he was using...

Since then I've been tempted away by a few shiny IDEs but always give up and come back to the venerable editor (one exception to this is intellij as it's a wonderful refactoring-engine for Java. By comparison Pycharm is rubbish IMHO).

And so I thought it might be useful to post about my .vimrc file explaining what the various plugins and configuration options do. Since I've been writing a lot of python over the past year there's a bias here.

This scope of this post creeped up but it is mainly:

  • a walk-through of my .vimrc file (anything not explained is hopefully obvious from the comments)
  • a litany of the useful vim-plugins therein and how/why to use them
  • some general vim tips

Installation

If you want to skip to the goods you can clone my dot-files repo and run vim.sh to download and install all of the plugins below.

Updating to a more recent version of vim is usually trivial though, for Debian/Ubuntu you can do:

sudo add-apt-repository ppa:jonathonf/vim
sudo apt update
sudo apt install vim

If you don't have vim-8 installed all the plugins except ALE will work anyway.

Plugins

Vundle

Let's start with Vundle: a plugin manager for vim that also fetches plugins straight from Github. We start by setting the runtime-path (where Vundle will download the plugins files).

set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()

Plugin 'gmarik/Vundle.vim'

Navigating the local filesystem

NERDTree

NERDTree is for exploring the file-system and is sometimes useful for jumping between files in your current project. Personally I don't like this being open on-startup.

Plugin 'scrooloose/nerdtree'

" Open/close NERDTree Tabs with 
let NERDTreeDirArrows=0 
" To have NERDTree not open on startup
let g:nerdtree_tabs_open_on_console_startup = 0 

A few highlights:

  • to open a new NERDTree tab use :NERDTree
  • to open a file under the cursor in a v-split pane hit s.
  • closes like a normal vim tab

NERD-tree

ctrlp

ctrlp is the most useful way to navigate between files while working on a project IMHO.

Plugin 'ctrlp/ctrlp.vim'

" search ctrlp with regex by default
let g:ctrlp_regexp_search = 1
let g:ctrlp_clear_cache_on_exit = 0

Quite simply, press Ctrl+p while in normal mode to open a buffer that will match to filenames in the directory you're in (and recursively in it's sub-directories). The options I've set will:

  • allow you to use regex to match filenamese
  • cache the directory index (F5 to refresh). This is useful if like me you ever have to work with a shared NFS mounts on which the indexing operation can be sluggish

ctrlp

Version control with Git

vim-fugitive

The vim-fugitive repo says it better than I could:

I'm not going to lie to you; fugitive.vim may very well be the best Git wrapper of all time

As someone that uses vim-fugitive to interface with git every day I don't consider this an understatement. This is a large topic but my top highlights are:

  • :GCommit, :Gpush, :Gpull wrap git {commit|push|pull}
  • :Gblame: opens a vertical-split window with git-blame info, and you can then open a commit and see the diff in another bugger
  • :Gdiff: see diff output for the current file.
  • You can pass any command directly to git by starting a command with :Git, for example add the current file to the change-set with :Git add path/to/current/file or just :Git add %
  • we're using fugitive to display the git branch in the status line with the lightline plugin (see below).
Plugin 'tpope/vim-fugitive'

fugitive

vim-gitgutter

vim-gitgutter complements fugitive by displaying the git sign for lines that have added/removed/updated in the current file (using the output git diff)

Plugin 'airblade/vim-gitgutter'

gitgutter

Bonus: configure git to use vimdiff

vimdiff is a diff-tool that opens a vertical-split window in vim. I find it much easier to see what's changed than when using git's in-built diff tool. Here we jump to my .gitconfig:

[diff]
    tool = vimdiff
[difftool]
    prompt = false
[alias]
    d = difftool

We can now look at the output of git diff in vimdiff. For example, to diff the curreent index with two commits ago you can do

git d HEAD~2

Highlights of this method is that when navigating the file in either window:

  • the files can be edited as if they were normally opened files in vim
  • "dp" will put the change under the current cursor to the other file
  • "do" with obtain the change from the other file and apply it to the cursor position in the current file

vimdiff

Status Bar

lightline

lightline allows you to configure a snazzy status bar (at the bottom of the window). The snippet below will show:

  • a color-scheme named wombat for the status-bar itself
  • the vim-mode (INSERT/NORMAL/VISUAL)
  • the git-branch if the file in the current buffer is part of a git repo (more on this later)
  • the python-virtualenv in use (more on this later).
Plugin 'itchyny/lightline.vim'

" set lightline to include git-branch
let g:lightline = {
      \ 'colorscheme': 'wombat',
      \ 'active': {
      \   'left': [ [ 'mode', 'paste' ],
      \             [ 'gitbranch', 'readonly', 'filename', 'modified' ] ,
      \             [ 'venv', 'readonly'] ]
      \ },
      \ 'component_function': {
      \   'gitbranch': 'fugitive#head',
      \   'venv': 'virtualenv#statusline'
      \ },
      \ }

" Always show statusbar
set laststatus=2

This produces the following status bar:

lightline status bar

Linting and syntax highlighting

Many people use syntastic for syntax highlighting in vim. It has one drawback which is that it runs synchonously in the main UI thread. ALE (Asynchronous Lint Engine) is arguably an asynchronous successor.

ale

ALE let's you specify specific linters for different languages. Below I've specified flake8 for linting and autopep8 for fixing syntax "errors".

Plugin 'w0rp/ale'

" pip install flake8
let g:ale_linters = {'python': ['flake8']}
let g:ale_fixers = {'python': ['remove_trailing_lines', 'trim_whitespace', 'autopep8']}

Note:

  • this assumes flake8 and autopep8 are already installed
  • any config for either in ~/.config/pep8 or ~/.config/flake8 will be respected.
  • the linting is done asynchronously
  • to apply the fixer (in this case autopep8) use the command :ALEFix

This produces:

ale

Python

Here are a few plugins that are great for python specifically.

jedi-vim

jedi is probably the best auto-completion library for Python that I've ever used (including Pycharm). jedi-vim requires that your vim binary was compiled with the python/python3 option but that's pretty much guaranteed unless you're compiling vim yourself.

" ------ jedi-python ------"
Plugin 'davidhalter/jedi-vim'

let g:jedi#popup_on_dot = 0
map <Leader>b Oimport pdb; pdb.set_trace() # BREAKPOINT<C-c>

Anyway, this is another large topic but here are a few highlights:

  • autocomplete (C-x-o)
  • jump-to variable/method/function/class definition (leader+g)
    • this works with defined on PYTHONPATH (including in your virtual-env) but not egg files weirdly)
  • find-usages (leader+f)
  • jump-to method/class/function/variable declaration (leader+d)
  • rename (leader+r)
  • show docstring with K
  • As a bonus: leader+b is remapped to add a pdb-breakpoint.

Below shows a few of these in action:

jedi

vim-virtualenv

vim-virtualenv allows you to set the python-virtualenv used in vim (and by extension jedi-vim). You can set/unset it with :VirtualEnvActivate virtual_env_name or :VirtualEnvDeactivate.

tagbar

Personally I find tags of limited use, but they're handy for exploring a new or otherwise un-familiar codebase. Here we use tagbar.

" --- C-tags integration --- "
Plugin 'majutsushi/tagbar'

Note, this requires ctags or similar to be installed, so for Debian/Ubuntu:

sudo apt-get install ctags

Then we can toggle the tagbar window with :Tagbar and navigate code at a higher level of abstraction, as shown below.

tagbar

Other useful plugins

Honourary mention to vim-go and rust.vim which provide great integration for those languages too.

Also, for keeping a work-log or wiki I can't recommend vimwiki enough: it is like an even-better org-mode ;-)

persistent-undo

This isn't a plugin but something I find useful for essentially caching the list of updates to a file such that if you close and re-open a file you can undo the last few edits (note, most vim distros in the wild will be compiled with the persistent_undo")

" Keep undo history across sessions by storing it in a file
if has('persistent_undo')
    let undo_dir = expand('$HOME/.vim/undo_dir')
    if !isdirectory(undo_dir)
        call mkdir(undo_dir, "", 0700)
    endif
    set undodir=$HOME/.vim/undo_dir
    set undofile
endif

Colours

It's possible to set the colour-scheme directly in vim but these days most terminals (terminator for linux and iTerm2 for mac) have solarized colour schemes baked in. Once set, vim will use these and the job is done.

tmux

On a different note, tmux is a wonderful way to multiplex teminal sessions and I find it complements vim very nicely.

I could probably fill an equally lengthy post about tmux.

vim miscellany

Again, this is a much larger topic but here are a few tricks I find useful:

  • :sp and :vs will split the current window horizontally/vertically
  • gg=G will auto-indent the entire file
  • e# navigates to the previously opened file in the current buffer
  • vim macros are pretty rad
  • you can use % as a shortcut for the current file-path in any command in command mode e.g. get it's md5-hash :! md5sum %
  • you can read from stdin via a UNIX pipe with vim -, e.g.
>> curl example.com | vim -

Motivation

Warning: this section is opinionated.

You might ask: why bother with all this? Surely [insert GUI-based IDE + whatever else] is good enough?

Well, it may be good enough. But often when working on some data-analysis or building some service what matters far more than the length of time spent working is how long I can spend in a state of flow. This usually means being focussing on one thing; being un-distracted. Using this editor is a great way of staying focussed and minimising the operational overheads of software engineering.

Things I find good for staying focussed:

  • Keeping my eyes fixed on one application
  • Having things like auto-complete and linters
  • Using as few keystrokes as possible for common tasks (eg. VCS commands, running tests)

Conversely, these have the opposite effect:

  • Navigating menus
  • Using a mouse at all
  • Switching to another terminal window or (much) worse a web-GUI

So in a way these plugins and hotkeys are a way of making it easier to stay in the flow.

vim-8 is awesome

Most package managers will distribute binary versions of vim 7.4.XXXX which is fine. There are many reasons to update to vim version 8.X is but perhaps the biggest is that it allows tasks to be performed outside the main UI thread. All of the plugins we'll discuss will work fine with either version except for the ALE plugin that requires version 8+. Also, certain commonly-enabled compilation flags (python and persistent_undo are assumed).

Wrapping up

Putting it altogether, what I focus on while working usually looks something like this.

full working environment

If you've made it this far I hope found it useful.

Go Top