In this installment, we are going to set up vim for Haskell development. If you don’t want to use vim, you can skip this post entirely. On the other hand, if you do want to use vim or are at least curious about trying it out (like me), then keep reading.
Chances are, if you do any kind of programming in a unix-like environment, you already know that vim is a text editor. Its proponents claim that proficiency in vim enables you to code faster than in any other editor. As for myself, my programming experience is mostly in IDEs, so I’m a veritable vim newbie. When I first started experimenting in vim not too long ago, I found the number of configuration options and plugins to be overwhelming. In fact, I’ve had to scrap several earlier version of this post as I found new combinations to try! So, this post will explore just one possible vim configuration for Haskell development, and to be honest it’s one with which I have limited experience so far. Still, I expect the baseline discussed here to be a good starting point for pretty much anybody.
As time goes on, I will likely change my vim configuration to better suit my needs as I discover them. I plan to keep my vim configuration version controlled, so if you are curious about the latest version you can check it out. Also, this post is not a tutorial about how to use vim, but rather how to configure it for Haskell. If you want practice with basic vim controls, you might want to try out the free levels of vim-adventures.
General Vim Options
Vim configuration is controlled through a the ~/.vimrc
file. This file is processed when vim first starts up and allows the user to configure vim in a huge number of ways. Just wrapping your head around all the various options can be overwhelming. Configuring vim means building this vimrc file to our liking.
Installing Vundle for Managing Plugins
One of the things that makes vim a popular editor choice is huge number of plugins available to customize your text editing experience. Downloading plugins is easy, but to get vim to recognize your plugins, you have to mess with vim’s runtimepath
variable. This can get pretty tedious, but thankfully there are plugin managers that will do the work for us. Vundle is one such declarative plugin manager, which fits with our NixOS theme.
Installing Vundle is a breeze. First, execute the following command:
#!bash
git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim
This will make a bundle
directory under which we will install our various plugins. We’re not done yet, though. We also need to add the following to the top of our .vimrc
file to run Vundle at startup. The comments are mine and optional
#!vim
" ========= VUNDLE CONFIG ===========
set nocompatible
filetype off
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
Plugin 'gmarik/Vundle.vim'
" LIST PLUGINS HERE
" VUNDLE CLEANUP
call vundle#end()
filetype plugin indent on
Essentially, this code is declaring that the Vundle plugin will manage itself. One downside of Vundle, however, is that the plugins must have a github repository to be managed. If this is a problem for you, check out the alternative pathogen.
Installing General Utility Plugins
Next, we’ll install some utility plugins for vim, which will also demonstrate how to install plugins using Vundle generally. The plugins I’m choosing are vim-sensible, vim-unimpaired, and syntastic. Vim-sensible touts itself as being a standard set of defaults on which pretty much everyone can agree. Vim-unimpaired adds lots of key bindings to make tasks like navigating through compiler errors, for example, a lot easier. Syntastic runs syntax checkers and displays the errors in plain view. Simply add the following lines to the .vimrc
file in the section I labeled LIST PLUGINS HERE
.
#!vim
" LIST PLUGINS HERE
Plugin 'tpope/vim-unimpaired'
Plugin 'tpope/vim-sensible'
Plugin 'scrooloose/syntastic'
let g:syntastic_always_populate_loc_list=1
" A Haskell plugin we'll install later is 'dag/vim2hs',
" but installing it now is fine, too.
Save the file, (re)load vim, and enter :PluginInstall
. Vundle will set up the path to only use the plugins you’ve declared in .vimrc
, kind of like NixOS does! Cool. A split screen should show up indicating the status of the selected plugins. If you ever want to add or remove plugins, just change the listed plugins in the .vimrc
file and run :PluginInstall
again.
The line let g:syntastic_always_populate_loc_list=1
configures syntastic to put the errors in the vim locations list, which allows us to jump through the errors using the vim-unimpaired bindings of [L
, ]L
, [l
, and ]l
.
Adding Custom Options Directly
The above plugins do a good job of setting up some standard options, but everyone prefers their own twist on things. Mine is given below, which I put in my .vimrc
file after the Vundle settings. Each setting is commented to explain what’s going on.
#!vim
" ========== GENERAL VIM SETTINGS ==========
" Enable search highlighting
set hlsearch
" Enable line numbers
set number
" Use F11 to toggle between paste and nopaste
set pastetoggle=<F11>
" vim-sensible enables smarttab. Here, we configure the rest:
" Set the display size of \t characters
set tabstop=2
" When hitting , insert combination of \t and spaces for this width.
" This combination is deleted as if it were 1 \t when using backspace.
set softtabstop=2
" Set code-shifting width. Since smarttab is enabled, this is also the tab
" insert size for the beginning of a line.
set shiftwidth=2
" When inserting tab characters, use spaces instead
set expandtab
" Instead of failing command, present dialog if unsaved changes
set confirm
" Enable mouse in all modes
set mouse=a
" Map jk and kj to to exit insert mode. We need to use F11 to toggle to
" paste mode before pasting any string with jk or kj, then switch back. When
" inserting jk or kj manually, we will need to type the keys slowly so that
" the key mapping times out. Using jk or kj to escape is easier than many
" other alternatives.
ino jk <Esc>
ino kj <Esc>
" Set a vertical line for long line width. This will give us a visual
" indicator for cases in which line length is approaching 80 chars
set colorcolumn=80
" Set the command section height to 2 lines. Useful if notices (like syntastic) are shown on command lines
set cmdheight=2
Customizations for Haskell
Now we’ll add some new features for our vim installation specifically to work with Haskell.
ghcmod
Installing the syntastic plugin for syntax checking was only part of the story as syntastic only runs external syntax checkers and displays their results. So now we need a syntax checker. Enter ghcmod.
#!bash
nix-install haskellPackages.ghcMod
That’s it. Syntastic will recognize that ghcmod is installed and run it whenever a Haskell file is saved. To verify that it’s being recognized, open a Haskell file, type some Haskell code, then run :SyntasticInfo
, which will show what checkers syntastic plans to use for the file. You can also run the checkers explicitly with :SyntasticCheck
.
vim2hs
vim2hs is a vim plugin for Haskell syntax highlighting and linting, among other things. It seems more lightweight than the haskellmode-vim alternative plugin and was highly recommended in a reddit discussion about vim and Haskell. Let’s give it shot.
#!vim
Plugin 'dag/vim2hs'
Remember to re-run :PluginInstall
within vim after updating .vimrc
.
That’s it for the basic vim setup. Changing the color scheme, customizing the display, and other items related more toward personal taste are left for you to explore!