(last updated: 28/07/2007)
Apart from all the general support of a portable, programmable, programmer's editor (type :help in Vim, or browse the docs online), Vim specifically provides support for editing source code, with predefined settings for over a hundred types of source. We can use and augment that functionality for Haskell-specific editing, and this is a little tour of what is available in my own Vim setup. To begin with, Vim supports Haskell syntax highlighting out of the box (:help syntax), as well as several methods for text folding (:help folding):

[syntax highlighting and folding]

By setting 'include' and 'includeexpr', we can teach Vim (in 'vimfiles/ftplugin/haskell.vim') to recognize import declarations, and to translate them into filenames (:help 'include'; :help 'includeexpr'; :help :checkpath). In a normal GHC installation, many library files will not be available in source form, but the files for your current project will be, and if you have sources for other imports, you can tell Vim where to find them (:help 'path'). Here, ':checkpath!' tells us which modules are imported, recursively, and which of those have associated source files:

[finding imported files]

Vim can then use import relations to search in all imported files, or to suggest completions wrt to imported files, or to jump from an import declaration to an imported file (:help gf). Here, we have positioned the cursor on 'Syntax' in the import declaration, and have used 'CTRL-W_CTRL-F' to open the imported file in a split window (:help :split). both horizontal and vertical splits are available, as are tab pages (:help :tab).

[opening imported files]

Here is an example of using insert-mode completion wrt to imported files (:help i_CTRL-N). Note that these suggestions come from words in the current and imported files:

[opening imported files]

Here we have placed the cursor on 'ruleS' and have asked Vim to display lines that contain the word under the cursor (:help [I ), which is useful for peeking at definitions and uses. Again, lines are found in the current and imported files:

[searching imported files]

Another standard tool is quickfix mode (:help quickfix), which is mostly an integrated edit-compile-edit cycle, but also used for other functions, such as searches where we want to visit and fix hits one by one. For that, we need to tell Vim how each compiler is used (:help 'makeprg'), and how to extract information from a compiler's output (:help 'errorformat'). If we do that for ghc in 'vimfiles/compiler/ghc.vim', then we can tell Vim to use that compiler for Haskell files (:help :compiler; you'll need to add the line 'au BufEnter *.hs compiler ghc' to your vimrc). Here, we have erroneously replaced a return by a Just, then called ':make' and ':copen'. Hitting the return key on an error message in the quickfix window takes us directly to the location given in that error message:

[quickfix mode]

Then, of course, there are tag files (:help 'tags'), which we can generate by external tools, such as hasktags or, in recent ghcs, 'ghc -e :ctags Main.hs' ('vimfiles/compiler/ghc.vim' maps '_ct' to the latter). Once we have a tags file for our project, we gain access to another group of Vim functionality, such as jumping to the definition of the keyword under the cursor (:help CTRL-] ), which builds a navigatable stack of tags you have visited, or opening a preview window for a tag definition (:help :ptag), or using insert-mode completion wrt to tags (:help i_CTRL-X_CTRL-] ). Here, we have just used ':ptag keyW' to open a preview on the declaration of the class method keyW:

[tag preview]

Next, some more goodies defined in 'vimfiles/compiler/ghc.vim'. Vim can ask ghc to browse the current and imported modules, and store the type information away for later use for the type of an identifier (if you need to update the stored information, use :GHCReload). For instance, we can position the cursor on an identifier and ask for its type by hitting '_t', or we can place the cursor on the identifier of a definition and hit '_T' to have a type declaration added, as shown here for the definition of no_eval:

[add type declaration]

Here, we have positioned the cursor on 'MonadPlus', and have hit '_si' to ask ghci for information

[info MonadPlus]

We can also use the browse information for insert-mode completion wrt identifiers in imported modules, using one of Vim's user-defined completions (:help i_CTRL-X_CTRL-O). Unlike i_CTRL-N, which is based on words in imported source files, i_CTRL-X_CTRL-O is more Haskell-aware, thanks to ghci's :browse command:

[import completion2]

Next, some goodies based on Haddock's HTML files for the libraries, defined in 'vimfiles/ftplugin/haskell_doc.vim'. First, in your vimrc, set g:haddock_browser to your webrowser of choice, then edit some Haskell file, call ':DocSettings', and check whether you are happy with what the script has found (g:haddock_browser will be called to display HTML docs, s:libraries should point to your local copy of the haddock files, and s:haddock_indexfile should be a place where vim can cache the information it gathers from the HTML files, so that it only has to do that once per version of the libraries; if you're happy with the settings, :DocIndex will populate the index, and :ExportDocIndex will store it for future use ). Next, we can position the cursor on '>>=', hit '_?', and select 'Control.Monad' as one of the possible sources from the popup menu, and Vim will start g:haddock_browser (Opera here) to display the page and entry for 'Control.Monad.>>=' in package base:

[haddock] [opera]

We could use the Haddock information to fully qualify the identifier under the curser ('_.'), or to add an import declaration for it ('_i' for importing a single identifier or '_im' for importing a whole module). And, of course, it forms the basis for yet-another-insert-mode completion (:help i_CTRL-X_CTRL-U). This time, we do not complete wrt to imported source files or imported modules or tag files, but wrt all identifiers in the libraries that occur in Haddock's indices (so if you complete to an identifier from a module you haven't imported yet, you might want to follow up with '_im' to bring it into scope):

[haddock completion]

That's all for now, though it is certainly not all Vim can do for Haskell hackers. To get some idea, browse the scripts/plugins/tips at vim.org, as well as the online documentation (especially the sections on effective editing and on working programs). Some of the many useful tips and scripts that are relevant to Haskell editing are Align.vim (to align your definitons on '|' and '=') and Surround.vim (to wrap stuff in {},(),[],'',"" and the like). Also be sure to read up on vimdiff, if you want to compare test outputs, or revisions of source code.