Haskell IDE: VIM


One of the most popular questions among Haskellers is the «Which editor to use as an IDE?». Obvious options are: Emacs (specifically, with the SpaceMacs extension installed), JetBrains IDEA, Atom, Vim, SublimeText, and probably other.

I worked some time with JetBrains IDEA. It has really nice support of Haskell. Although as for me, IDEA is too JVM-like: eats many RAM and CPU, making my notebook sometimes too heat.

After tasting Atom, I had very weird emotions: it seems to be very promising product, but I couldn’t make it work nice.

Emacs is a really great tool. Especially, when installed SpaceMacs extension. Although, by some reason sometimes it stucked on my MacBook consuming 100% of CPU and not responding. And more, after installing all these nice plugins with spacemacs, it becomes almost as much heavy-weight as JetBrains IDEA. Yet, I couldn’t configure Emacs so that it could be possible to work with projects and workspaces - every time you need do all these magic for opening files you closed yesterday…

I have very nice impression about SublimeText. It is really nice! After some short configuration, it is pleasure to work with this software.

Now VIM. I often use it for editing some minor stuff, like patching configuration files or editing some simple texts. But I never used it as an full-featured IDE. I tried, but it was always a big fail. Every time it was a session of pain, trying to make it work as kind of IDE. Nevertheless, it seems I managed to sort it out, and now I am pretty happy with current VIM configuration. Can’t say it is a full-featured IDE, but last weekends I successfully had been working on a Haskell pet-project, and I got much pleasure dealing with VIM during this activity. Finally!…

So, here in this article I share my notes and thoughts on configuring VIM as a Haskell IDE. Since I am not a VIM-expert, most of the ideas are stolen from other authors (but I keep references to the original sources). Nevertheless, I also added some valuable (as to me) improvements in the config, that makes it all even better.

Now, let’s start…


First of all, I recommend to start from the terrific article of Stephen Diehl Vim and Haskell in 2016 - it gives basic steps for installing VIM and plugins. As a note for myself, I am duplicating the plugins list here:

cd ~/.vim/bundle
$ git clone https://github.com/eagletmt/ghcmod-vim.git
$ git clone https://github.com/eagletmt/neco-ghc
$ git clone https://github.com/ctrlpvim/ctrlp.vim.git
$ git clone https://github.com/scrooloose/syntastic.git
$ git clone https://github.com/tomtom/tlib_vim.git
$ git clone https://github.com/MarcWeber/vim-addon-mw-utils.git
$ git clone https://github.com/garbas/vim-snipmate.git
$ git clone https://github.com/scrooloose/nerdtree.git
$ git clone https://github.com/scrooloose/nerdcommenter.git
$ git clone https://github.com/godlygeek/tabular.git
$ git clone https://github.com/ervandew/supertab.git
$ git clone https://github.com/Shougo/neocomplete.vim.git

Basic VIM configuration

Next, in the article Stephen provides his own VIM configuration. Despite on the config is pretty good and enough for most cases, I made some changes to make VIM even more comfortable. So, here is my VIM config:

syntax on
filetype plugin indent on

set hidden
set nocompatible
set number
set nowrap
set showmode
set tw=80
set smartcase
set smarttab
set smartindent
set autoindent
set softtabstop=2
set shiftwidth=2
set expandtab
set incsearch
set mouse=a
set history=1000
set clipboard=unnamedplus,autoselect
set laststatus=2
set completeopt=menuone,menu,longest

set wildignore+=*\\tmp\\*,*.swp,*.swo,*.zip,.git,.cabal-sandbox
set wildmode=longest,list,full
set wildmenu
set completeopt+=longest

set t_Co=256

set cmdheight=1

execute pathogen#infect()

map <Leader>s :SyntasticToggleMode<CR>

set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*

let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 0
let g:syntastic_check_on_open = 0
let g:syntastic_check_on_wq = 0

map <silent> tw :GhcModTypeInsert<CR>
map <silent> ts :GhcModSplitFunCase<CR>
map <silent> tq :GhcModType<CR>
map <silent> te :GhcModTypeClear<CR>

let g:SuperTabDefaultCompletionType = '<c-x><c-o>'

if has("gui_running")
  imap <c-space> <c-r>=SuperTabAlternateCompletion("\<lt>c-x>\<lt>c-o>")<cr>
else " no gui
  if has("unix")
    inoremap <Nul> <c-r>=SuperTabAlternateCompletion("\<lt>c-x>\<lt>c-o>")<cr>

let g:haskellmode_completion_ghc = 1
autocmd FileType haskell setlocal omnifunc=necoghc#omnifunc

map <Leader>n :NERDTreeToggle<CR>

let g:haskell_tabular = 1

vmap a= :Tabularize /=<CR>
vmap a; :Tabularize /::<CR>
vmap a- :Tabularize /-><CR>

map <silent> <Leader>t :CtrlP()<CR>
noremap <leader>b<space> :CtrlPBuffer<cr>
let g:ctrlp_custom_ignore = '\v[\/]dist$'

map <Leader>n <plug>NERDTreeTabsToggle<CR>

let g:airline#extensions#tabline#enabled = 1

noremap <leader>1 1gt
noremap <leader>2 2gt
noremap <leader>3 3gt
noremap <leader>4 4gt
noremap <leader>5 5gt
noremap <leader>6 6gt
noremap <leader>7 7gt
noremap <leader>8 8gt
noremap <leader>9 9gt

" control-space menus custom coloring
hi CtrlSpaceSearch guifg=#eeeeee guibg=#303030 gui=bold ctermfg=255 ctermbg=236 term=bold cterm=bold
hi CtrlSpaceSelected guifg=#eeeeee guibg=#303030 gui=bold ctermfg=255 ctermbg=17 term=bold cterm=bold
hi CtrlSpaceNormal guifg=#eeeeee guibg=#303030 gui=bold ctermfg=255 ctermbg=28 term=bold cterm=bold
hi CtrlSpaceStatus guifg=#eeeeee guibg=#303030 gui=bold ctermfg=255 ctermbg=31 term=bold cterm=bold

" autocompletion menu custom coloring
hi PMenuSel guifg=#eeeeee guibg=#303030 gui=bold ctermfg=255 ctermbg=17 term=none cterm=none
hi PMenu guifg=#eeeeee guibg=#303030 gui=bold ctermfg=255 ctermbg=28 term=none cterm=none

" Easy align interactive
vnoremap <silent> <Enter> :EasyAlign<cr>

My .vimrc file can be found on my Github page

Additional VIM plugins

In addition to the Stepehn’s original plugins list, I installed a couple of more. Here they are:

cd ~/.vim/bundle
git clone git://github.com/airblade/vim-gitgutter.git
git clone https://github.com/junegunn/vim-easy-align.git
git clone https://github.com/vim-ctrlspace/vim-ctrlspace.git
git clone https://github.com/vim-airline/vim-airline.git
  1. GiGutter gently marks modified lines of your Git-controlled code
  2. EasyAlign allows you to align codeparts in a pretty and easy way
  3. ControlSpace works as a file/project/workspace manager
  4. AirLine makes very nice and informative status bar

Organizing a workspace/project

For this task we have the Control-Space VIM plugin installed. This plugin allows saving and restoring VIM workspace sessions - so you can open and configure your project windows, then save the workspace and shutdown the machine with no worries. Then you can switch the machine back on, start VIM, and restore the workspace so that it will be in exactly the same state as you left it last time.

Using Control-Space, you also can handle all your file-related operations. So you even would not need to use NerdTree plugin.

It is not reasonable to duplicate here all Control-Space relevant shortcuts and configurations, so I highly recommend to visit the plugin’s home page and read a bit on how to use it - it could really make your developer’s life a bit easier and more comfortable.

Some shortcuts

\1 - go to tab #1
\2 - go to tab #2
\n - go to tab #n (up to 9)

tw - insert type for declaration
tq - query type of the expression under cursor
a= - align on equal sign
\t - open fuzzy file finder

ctrl-space - the control space plugin’s multifunctional menu (? is for help then)
ctrl-space w - save and open workspaces

ctrl-w arrow - go to the split pane
enter space - align selected code enter 2 space - align code by the second column

Final words

I hope you found this information useful. Feel free to share your experience on «Haskell + VIM».