How I boosted my Vim

A few weeks ago, I felt inspired by articles from Jeff Kreeftmeijer and Armin Ronacher. I took some time to configure and fine-tune my Vim environment. A lot of new stuff made it into my .vimrc file and my .vim directory. This blog post is a summary describing what I’ve added and how I use it in my daily work.

Before doing anything else, make sure you have the following line in your .vimrc file:

" This must be first, because it changes other options as side effect
set nocompatible

Step 0: make the customization process easier

Before starting configuring, it’s useful to install pathogen. Plugins in Vim are files that you drop in subdirectories of your .vim/ directory. Many plugins exist of only a single file that should be dropped in .vim/plugin, but some exist of multiple files. For example, they come with documentation, or ship syntax files. In those cases, files need to be dropped into .vim/doc and .vim/syntax. This makes it difficult to remove the plugin afterwards. After installing pathogen, you can simply unzip a plugin distribution into .vim/bundle/myplugin, under which the required subdirectories are created. Removing the plugin, then, is as simple as removing the myplugin directory.

So, download pathogen.vim, move it into the .vim/autoload directory (create it if necessary) and add the following lines to your .vimrc, to activate it:

" Use pathogen to easily modify the runtime path to include all
" plugins under the ~/.vim/bundle directory
call pathogen#helptags()
call pathogen#runtime_append_all_bundles()

Next, I’ve remapped the leader key to , (comma) instead of the default \ (backslash), just because I like it better. Since in Vim’s default configuration, almost every key is already mapped to a command, there needs to be some sort of standard “free” key where you can place custom mappings under. This is called the “mapleader”, and can be defined like this:

" change the mapleader from \ to ,
let mapleader=","

Once that is done, this is a little tweak that is a time-saver while you’re building up your .vimrc. Here, we start using the leader key:

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

This effectively maps the ,ev and ,sv keys to edit/reload .vimrc. (I got this from Derek Wyatt’s .vimrc file.)

Change Vim behaviour

One particularly useful setting is hidden. Its name isn’t too descriptive, though. It hides buffers instead of closing them. This means that you can have unwritten changes to a file and open a new file using :e, without being forced to write or undo your changes first. Also, undo buffers and marks are preserved while the buffer is open. This is an absolute must-have.

set hidden

These are some of the most basic settings that you probably want to enable, too:

set nowrap        " don't wrap lines
set tabstop=4     " a tab is four spaces
set backspace=indent,eol,start
                  " allow backspacing over everything in insert mode
set autoindent    " always set autoindenting on
set copyindent    " copy the previous indentation on autoindenting
set number        " always show line numbers
set shiftwidth=4  " number of spaces to use for autoindenting
set shiftround    " use multiple of shiftwidth when indenting with '<' and '>'
set showmatch     " set show matching parenthesis
set ignorecase    " ignore case when searching
set smartcase     " ignore case if search pattern is all lowercase,
                  "    case-sensitive otherwise
set smarttab      " insert tabs on the start of a line according to
                  "    shiftwidth, not tabstop
set hlsearch      " highlight search terms
set incsearch     " show search matches as you type

There is a lot more goodness in my .vimrc file, which is put in there with a lot of love. I’ve commented most of it, too. Feel free to poke around in it.

Also, I like Vim to have a large undo buffer, a large history of commands, ignore some file extensions when completing names by pressing Tab, and be silent about invalid cursor moves and other errors.

set history=1000         " remember more commands and search history
set undolevels=1000      " use many muchos levels of undo
set wildignore=*.swp,*.bak,*.pyc,*.class
set title                " change the terminal's title
set visualbell           " don't beep
set noerrorbells         " don't beep

Oh, and man… never ever let Vim write a backup file! They did that in the 70’s. Use modern ways for tracking your changes, for God’s sake.

set nobackup
set noswapfile

There have been some passionate responses about this in comments, so a warning may be appropriate here. If you care about recovering after a Vim or terminal emulator crash, or you often load huge files into memory, do not disable the swapfile. I personally save/commit so often that the swap file adds nothing. Sometimes I conciously kill a terminal forcefully, and I only find the swap file recovery process annoying.

Use file type plugins

Vim can detect file types (by their extension, or by peeking inside the file). This enabled Vim to load plugins, settings or key mappings that are only useful in the context of specific file types. For example, a Python syntax checker plugin only makes sense in a Python file. Finally, indenting intelligence is enabled based on the syntax rules for the file type.

filetype plugin indent on

To set some file type specific settings, you can now use the following:

autocmd filetype python set expandtab

To remain compatible with older versions of Vim that do not have the autocmd functions, always wrap those functions inside a block like this:

if has('autocmd')
    ...
endif

Enable syntax highlighting

Somewhat related to the file type plugins is the syntax highlighting of different types of source files. Vim uses syntax definitions to highlight source code. Syntax definitions simply declare where a function name starts, which pieces are commented out and what are keywords. To color them, Vim uses colorschemes. You can load custom color schemes by placing them in .vim/colors, then load them using the colorscheme command. You have to try what you like most. I like mustang a lot.

if &t_Co >= 256 || has("gui_running")
   colorscheme mustang
endif

if &t_Co > 2 || has("gui_running")
   " switch syntax highlighting on, when the terminal has colors
   syntax on
endif

In this case, mustang is only loaded if the terminal emulator Vim runs in supports at least 256 colors (or if you use the GUI version of Vim).

Hint: if you’re using a terminal emulator that can show 256 colors, try setting TERM=xterm-256color in your terminal configuration or in your shell’s .rc file.

Change editing behaviour

When you write a lot of code, you probably want to obey certain style rules. In some programming languages (like Python), whitespace is important, so you may not just swap tabs for spaces and even the number of spaces is important.

Vim can highlight whitespaces for you in a convenient way:

set list
set listchars=tab:>.,trail:.,extends:#,nbsp:.

This line will make Vim set out tab characters, trailing whitespace and invisible spaces visually, and additionally use the # sign at the end of lines to mark lines that extend off-screen. For more info, see :h listchars.

In some files, like HTML and XML files, tabs are fine and showing them is really annoying, you can disable them easily using an autocmd declaration:

autocmd filetype html,xml set listchars-=tab:>.

One caveat when setting listchars: if nothing happens, you have probably not enabled list, so try :set list, too.

Pasting large amounts of text into Vim

Every Vim user likes to enable auto-indenting of source code, so Vim can intelligently position you cursor on the next line as you type. This has one big ugly consequence however: when you paste text into your terminal-based Vim with a right mouse click, Vim cannot know it is coming from a paste. To Vim, it looks like text entered by someone who can type incredibly fast :) Since Vim thinks this is regular key strokes, it applies all auto-indenting and auto-expansion of defined abbreviations to the input, resulting in often cascading indents of paragraphs.

There is an easy option to prevent this, however. You can temporarily switch to “paste mode”, simply by setting the following option:

set pastetoggle=<F2>

Then, when in insert mode, ready to paste, if you press <F2>, Vim will switch to paste mode, disabling all kinds of smartness and just pasting a whole buffer of text. Then, you can disable paste mode again with another press of <F2>. Nice and simple. Compare paste mode disabled vs enabled:

Another great trick I read in a reddit comment is to use <C-r>+ to paste right from the OS paste board. Of course, this only works when running Vim locally (i.e. not over an SSH connection).

Enable the mouse

While using the mouse is considered a deadly sin among Vim users, there are a few features about the mouse that can really come to your advantage. Most notably—scrolling. In fact, it’s the only thing I use it for.

Also, if you are a rookie Vim user, setting this value will make your Vim experience definitively feel more natural.

To enable the mouse, use:

set mouse=a

However, this comes at one big disadvantage: when you run Vim inside a terminal, the terminal itself cannot control your mouse anymore. Therefore, you cannot select text anymore with the terminal (to copy it to the system clipboard, for example).

To be able to have the best of both worlds, I wrote this simple Vim plugin: vim-togglemouse. It maps <F12> to toggle your mouse “focus” between Vim and the terminal.

Small plugins like these are really useful, yet have the additional benefit of lowering the barrier of learning the Vim scripting language. At the core, this plugin exists of only one simple function:

fun! s:ToggleMouse()
    if !exists("s:old_mouse")
        let s:old_mouse = "a"
    endif

    if &mouse == ""
        let &mouse = s:old_mouse
        echo "Mouse is for Vim (" . &mouse . ")"
    else
        let s:old_mouse = &mouse
        let &mouse=""
        echo "Mouse is for terminal"
    endif
endfunction

Get efficient: shortcut mappings

The following trick is a really small one, but a super-efficient one, since it strips off two full keystrokes from almost every Vim command:

nnoremap ; :

For example, to save a file, you type :w normally, which means:

  1. Press and hold Shift
  2. Press ;
  3. Release the Shift key
  4. Press w
  5. Press Return

This trick strips off steps 1 and 3 for each Vim command. It takes some times for your muscle memory to get used to this new ;w command, but once you use it, you don’t want to go back!

I also find this key binding very useful, since I like to reformat paragraph text often. Just set your cursor inside a paragraph and press Q (or select a visual block and press Q).

" Use Q for formatting the current paragraph (or selection)
vmap Q gq
nmap Q gqap

If you are still getting used to Vim and want to force yourself to stop using the arrow keys, add this:

map <up> <nop>
map <down> <nop>
map <left> <nop>
map <right> <nop>

If you like long lines with line wrapping enabled, this solves the problem that pressing down jumpes your cursor “over” the current line to the next line. It changes behaviour so that it jumps to the next row in the editor (much more natural):

nnoremap j gj
nnoremap k gk

When you start to use Vim more professionally, you want to work with multiple windows open. Navigating requires you to press C-w first, then a navigation command (h, j, k, l). This makes it easier to navigate focus through windows:

" Easy window navigation
map <C-h> <C-w>h
map <C-j> <C-w>j
map <C-k> <C-w>k
map <C-l> <C-w>l

Tired of clearing highlighted searches by searching for “ldsfhjkhgakjks”? Use this:

nmap <silent> ,/ :nohlsearch<CR>

I used to have it mapped to :let @/=""<CR>, but some users kindly pointed out that it is better to use :nohlsearch, because it keeps the search history intact.

It clears the search buffer when you press ,/

Finally, a trick by Steve Losh for when you forgot to sudo before editing a file that requires root privileges (typically /etc/hosts). This lets you use w!! to do that after you opened the file already:

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

Use plugins

Ah, finally. Arrived at the magical stuff that is Vim plugins. This is a listing of the Vim plugins I depend on most and that really offer added value when you work with Vim every day.

Almost any person I know who owns a Mac has at least tried or purchased the TextMate editor. It is a great programmer’s editor that has a lot of nice features, but of course, lacks Vim-style navigation :)

Some of its features have inspired Vim plugin developers to clone the awesomeness. TextMate’s best two features (super-quick file opening and snippets) have been “ported” to Vim plugins.

Command-T: TextMate-style file opening NERDTree explorer

The NERDTree plugin is an absolute must for almost any Vim user. For those who don’t know it yet, NERDTree is a visual file browser that allows you to quickly open files by navigating onto it and pressing Return.

You can open the NERDTree using the :NERDTree command, or by using :NERDTreeToggle. To close the tree window, use :NERDTreeClose.

I have I’ve mapped some shortcuts to these commands, for quick access to the list:

nmap ,n :NERDTreeClose<CR>:NERDTreeToggle<CR>
nmap ,m :NERDTreeClose<CR>:NERDTreeFind<CR>
nmap ,N :NERDTreeClose<CR>

You can add quick bookmarks to directories that you often visit (like project directories), which works really well. I have configured the following settings, which tells the plugin where the bookmark file is, which extensions to ignore, to show hidden files and to quit on open (which I like to have on, to have screen real estate for my code):

" Store the bookmarks file
let NERDTreeBookmarksFile=expand("$HOME/.vim/NERDTreeBookmarks")

" Don't display these kinds of files
let NERDTreeIgnore=[ '\.pyc$', '\.pyo$', '\.py\$class$', '\.obj$',
            \ '\.o$', '\.so$', '\.egg$', '^\.git$' ]

let NERDTreeShowBookmarks=1       " Show the bookmarks table on startup
let NERDTreeShowFiles=1           " Show hidden files, too
let NERDTreeShowHidden=1
let NERDTreeQuitOnOpen=1          " Quit on opening files from the tree
let NERDTreeHighlightCursorline=1 " Highlight the selected entry in the tree
let NERDTreeMouseMode=2           " Use a single click to fold/unfold directories
                                  " and a double click to open files

You can add quick bookmarks to directories that you often visit (like project directories), which works really well, too.

More documentation available at: the plugin page.

I used to have a whole discussion on the NERDTree explorer plugin here, but I was pointed towards Command-T by a few readers. Once I tried that plugin for a few minutes, it became clear that there would be no need for NERDTree anymore.

The name Command-T is a reference to the original shortcut for “Go to File” in TextMate, which opens the quick file opener. Setting up this plugin is a bit more tricky than usual, because some files need to be compiled, but the instructions on the website are very clear and simple. There’s even a screencast for Windows users.

The plugin registers itself under <leader>t (in my case that’s ,t). And if it does, it shows a list of all the files from the current directory and a search box in which you can type any character progression. By typing more characters, the list of files is narrowed down to contain only files that have that string as a subset. But here’s the real added value: you can type any sequence of characters that are in the file’s path, they don’t have to be subsequent characters. For example, if you have the following list of files:

foo/bar.py
foo/qux.py
tests/test_foo/test_bar.py
tests/test_foo/test_qux.py

You could type the sequence fb to select the file foo/bar.py, or tfb to select tests/test_foo/test_bar.py. As you can imagine, this is a huge time saver. There is much more goodness in there. For that, please refer to Wincent’s screencasts, or his website.

You can download the plugin at vim.org.

Note: On Vim instances that don’t have Ruby support enabled (type :version to check this), the Commant-T plugin won’t work. If it isn’t an option to recompile Vim to add Ruby support, the NERDTree explorer still is a good alternative.

Snipmate: TextMate-style snippets for Vim

Another killer feature of TextMate are the intelligent snippets: you type some text, press Tab and TextMate creates a snippet for you, with placeholders at key positions within the snippet. The first placeholder is selected, your overwrite it with the text you want, then press Tab to select the second placeholder, etc. This lets you enter code super fast.

Now it’s available to us Vim users, too, in the form of the snipMate plugin (dubbed after TextMate). There’s a great introductory screencast to get you excited about it.

Writing your own snippets

There are already lots of specific language plugins snippets for snipMate available, but writing your own is simple in case you ever miss functionality. Just create a file called ~/.vim/snippets/foo.snippet, where foo is the filetype you want to load the snippets for.

Then, declare your snippets. That’s really as easy as this:

snippet def
    def ${1:fname}(${2:arg}):
        ${3:pass}

If you declare this, you can simply use def<Tab> and it will expand to a Python function definition. The ${1:fname} means "put the first placeholder at this position, and fill it with a default value of “fname”.

Other cool plugins

In order to make the article not any more longer than it already is, here’s a list of other plugins that are really worth checking out (I use each of them regularly):

Other resources

Some of the resources from where I have collected inspiration for my .vimrc file, plugins, and tricks:

I hope you like these tips. Please add your comments below if you do, or if you have any Vim improvements or tips you’d like to bring on yourself. You can have a look at my full Vim configuration in my Github repo.

If you want to get in touch, I'm @nvie on Twitter.