Blog

The Vimrc Antiques Roadshow

Last week, I gave a talk at Vim London about Vim's configuration file. We examined my .vimrc, Nic West's, Tim Mower's, Arturo Herrero's, James Cooke's, and Oliver Caldwell's. We also had a look at Drew Neil's during the Q&A.

The basics

Vim reads a configuration file called ~/.vimrc when it starts. You don't have to keep all your configuration in one file; several people put settings in other files (such as ~/.vim/bundle) and add source ~/.vim/bundle to their .vimrc. You can run vim -u filename to read a different settings file; nobody at the meeting used that, but some people use it to manage different settings across projects. You can do this automatically with set exrc and set secure.

Good habits

  • Add a comment with a URL when copying settings to your .vimrc from an online article.
  • Don't be afraid to ask Vim for :help.
  • Keep your .vimrc in source control. As well as keeping track of what you add and remove, it makes it easier to keep your files in sync between several different machines (such as home & work).
  • Bind your most used commands to the Fx keys; they're unused in Vim, so are free for your own use.
  • Use a tool to manage your Vim plugins; Vundle is preferable to Pathogen because it saves you from the horrible world of Git submodules.
  • Remember that Github won't show non-printable characters, so if you're browsing .vimrcs you might miss important details.

Modernising vim & making it more sensible

Most .vimrcs contain some settings to smooth over some foibles and legacy features:

  • set nocompatible tells Vim to forget about Vi compatibility. Interestingly, as soon as you create a ~/.vimrc this option gets set automatically.
  • set hidden allows for hidden buffers - basically stopping Vim whining when you open more than one file.
  • set ttyfast might also be on by default, depending on your $TERM environment variable. When on, Vim will update your screen in bigger batches.
  • set backspace=indent,eol,start enables backspacing over everything, like every modern editor ever.
  • nmap j gj and nmap k gk make j/k move the cursor up/down by lines on the screen, not lines in the file. Navigation feels more natural when using word wrap this way.
  • au BufRead,BufNewFile *.md set filetype=markdown sets foo.md files to be Markdown, not Modula2.
  • You can get better tab completion for Vim commands if you set wildmenu. You may also like to set wildmode=list:longest, and you can ignore certain files - like Python compiled files - with set wildignore=*.pyc.
  • You can set a mark in Vim with ma, and jump back to that line with 'a. If you want to back to that exact cursor position, you can use `a, but that's harder to press. You can swap ` and ' with nnoremap ' ` and nnoremap ` '.
  • Normally Vim will scroll the screen when the cursor hits the first/last line. You can make it scroll 3 lines earlier with set scrolloff=3. Nic went as far as to set scrolloff=15.

Views & Sessions

Vim supports views, which save the cursor position & code folds between editing sessions (along with a few other settings). I've used an autocommand to automatically save and load a view whenever I edit a file:

au BufWinLeave ?* silent mkview
au BufWinEnter ?* silent loadview

Vim also has a sessions feature, which saves the whole editing session - everything in the views, along with the open buffers, window layout, tabs, etc. Oliver has bound F7 and F8 to save/load a session:

nnoremap <F7> :mksession! .quicksave.vim<CR>
nnoremap <F8> :source .quicksave.vim<CR>

I recommended he move them to non-neighbouring keys, to make it harder to accidentally hit the wrong key & save an empty session.

Plugins and other tools

The most interesting plugins were:

  • CtrlP, a fuzzy-finder for navigating projects.
  • Vim-endwise, to add end automatically in Ruby.
  • Vim-numbertoggle will show you relative line numbers in normal mode and absolute line numbers in insert mode. This makes it easier to write multiple line-spanning motions. You can use set number to always show line numbers and set relativenumber to always show relative numbers.
  • Vim-unimpaired adds some navigation commands to the [] keys.
  • Easymotion turns motions into a multiple-choice option.

Some tools that people use with Vim include:

  • Ack (and the similar Ag, AKA "The Silver Searcher"). They're grep-like tools that have useful features like respecting your .gitignore file. You can tell Vim to use ag for its built-in grep, as well as telling CtrlP to use it too:

    if executable('ag')
      set grepprg=ag\ --nogroup\ --nocolor
      let g:ctrlp_user_command = 'ag %s -l --nocolor -g ""'
    endif
    
  • Screen and tmux remain popular. Plugins like vim-tmux-navigator and tmuxline provide some Vim integration.

  • Git is used by everyone for source control, often with the vim-fugitive plugin.

Search and search highlighting

Vim can highlight search results as you type:

set hlsearch
set incsearch

set ignorecase makes searching case insensitive; set smartcase makes searching case insensitive unless you use any capital letters. If you find yourself using substitutions a lot then you might want to set gdefault to make replacement global without having to add the g flag.

Refreshing

I've found that Vim sometimes messes up syntax highlighting or forgets the filetype. I've bound F5 to refresh highlighting and filetype detection:

noremap <F5> <esc>:syntax sync fromstart<cr>:filetype detect<cr>
inoremap <F5> <esc>:syntax sync fromstart<cr>:filetype detect<cr>a

Oliver used his F5 key to regenerate his ctags:

command! GenerateTags call system('ctags -Rf ./.tags --python-kinds=-i --exclude=.git `cat .srclist`') | echo
nnoremap <F5> :GenerateTags<CR>

You could combine these if you wanted to.

Swapfiles, backups, and undo

Vim can create backups when you write files, save your undo history between sessions, and uses a swap file to track changes when running.

Just about everybody tells Vim to put these files in their own directories. At the very least, you won't have to add them to your .gitignore files that way:

set undodir=~/.vim/tmp/undo/
set backupdir=~/.vim/tmp/backup/
set directory=~/.vim/tmp/swap/

It seems like a good idea to make those directories if they don't already exist:

if !isdirectory(expand(&undodir))
  call mkdir(expand(&undodir), "p")
endif
if !isdirectory(expand(&backupdir))
  call mkdir(expand(&backupdir), "p")
endif
if !isdirectory(expand(&directory))
  call mkdir(expand(&directory), "p")
endif

Turn on persistent undo with set undofile. Turn backups on with set backup. Some people turn off swapfiles with set noswapfile; Vim speeds up, but you're promising that Vim will always shut down cleanly & you'll never open the same file in two different Vim instances.

Avoiding the escape key, and other personal taste issues

Some people like to avoid the escape key, and use keystrokes like jj and jk instead. Tim forced himself to learn this by remapping his Esc to a no-op:

noremap <Esc> <Nop>
inoremap jk <Esc>
inoremap jj <Nop>

We also mentioned the influence of the ADM-3A, a common terminal used when Vi was written. Its Escape was located where modern Tab keys are and its tilde key was labelled "Home". This led to the use of ~ as a shortcut for the home directory. It also had arrows on h, j, k, and l - which is why they're used for navigation in Vim and other programs.

James' .vimrc swapped : for ;, to cut down on shift usage:

nnoremap ; :
nnoremap : ;

But James recommended against this, as when he uses other programs with Vim mappings his muscle memory is basically useless.

Obeying coding conventions

If your coding style guide specifies a maximum line length, you can set colorcolumn=80 to add a stripe at the 80 column mark.

You can show hidden characters (like trailing whitespace and tabs) with custom symbols. Here's James':

set list 
set listchars=eol:,tab:▷\ ,

Shortcuts for stripping trailing whitespace were also popular: nnoremap <F2> :%s/\s\+$//e<CR>

Micro-optimisations

If you find yourself performing a repetitive task, it's worth finding a way to optimise it. Nic wrote a function that copies a path to his clipboard, so he could paste it easily into a VM. Tim had a snippet that var_dump()s the variable under the cursor (a PHP way of printing out variables for debugging): nmap dvd viwy<Esc>odie(var_dump());<Esc>hhP

James likes to use Ctrl+j as a shortcut for :tabedit:

nnoremap <C-j> :tabe

The trailing space is important so you can start typing the filename immediately.

Oliver bound leader z to replace the misspelling under the cursor with the first suggested fix: nnoremap <leader>z 1z=

Arturo added a mapping for :w!! to save the current file via sudo:

cmap w!! %!sudo tee > /dev/null %

Highlight words you want to avoid

It's good practice to avoid words like "obviously", "just", & "simply" when writing educational articles. You can use a custom highlighter to make them stand out.

Miscellaneous

  • set matchtime=2 determines how long Vim will highlight matching brackets, in tenths of a second.
  • You can use vim folds to hide code in long files by "folding" it up into one line.
  • Searching Github for ':wq' gives 7.1 million results.
  • set autoread will reload the file if it changes. It's not tail -f, though: you have to run a shell command or invoke :checktime to make Vim re-check the file.
  • James recommended Bare-bones navigation, a previous talk by Kris Jenkins.
  • Oliver had an embedded Python program in his .vimrc to automatically set up his virtualenv. I'd keep this in a dedicated script and call it from the .vimrc instead.
  • set nostartofline keeps the cursor in place when you re-indent code. Sadly, this doesn't move the cursor with the indent so it's not as useful as it sounds.
  • zz moves the line under the cursor to the middle of the screen, which is useful when coding in front of an audience. zt moves the current line to the top. You can also use set cursorline to underline the current line, which can also help an audience follow along (or a presenter to follow their notes).
  • Text objects are awesome and you should definitely learn them.

The mysterious pink ping pong balls

After the talk, Tim wrote in about the Ctrl + l mapping we failed to decipher. He had some bugfixes and an explanation: inoremap <C-R> @@@<Esc>hhkywjl?@@@<CR>P/@@@<CR>3s lets you use Ctrl + r to copy the previous line word-by-word.


Thanks to Drew for organising Vim London and to Skimlinks for hosting the meetup.