Doom-emacs + haskell + minimal vim

7 minute read Published: 2018-12-02

I've seen a few people on twitter recommend emacs for haskell, but then go on to say they don't know how to use emacs at all. I got into emacs (specifically spacemacs) when working through Programming Languages Part A on Coursera a few years back as it had a standard-ml mode. I've moved on from spacemacs to something called doom-emacs which is lovely and easy to setup and still has evil (vim) mode.

I have no idea how to use most of emacs-mode.


You will need to install emacs (>= 25.1) for this. I use emacs26. Figure out how to do this on whatever distribution you have. I've tested it on ubuntu/mac and had no problems other than having to compile it on mac.



Grab a copy of doom-emacs from here. We are going to skip the master branch and go straight to the develop branch.

git clone ~/.emacs.d
mkdir ~/.doom.d
cd ~/.emacs.d
git checkout develop
bin/doom install

This will get you a minimal setup going. Edit ~/doom.d/init.el and turn on uncomment the packages you want under :lang. for our purposes uncomment (haskell +intero)but feel free to turn on whatever you want. If you want to use Dante instead then do (haskell +dante) instead. Comments, in case it isn't obvious, are ;; Uncomment magit as well as it's lovely for working with git. Uncomment term too.

Save the file. Go back to your ~/.emacs.d dir and run bin/doom refresh.


This is much easier than it used to be. Put all your stuff in `~/.doom.d/config.el~ now. Some super fancy stuff can be found here. But I don't recommend loading it. Peruse for how to customize your own stuff. There is some docs around this on the doom-emacs github page.

I like line numbers, a certain font, and some settings for code completion so mine looks like

(setq doom-font (font-spec :family "Hasklig" :size 15))
(load-theme 'doom-palenight t)

(when (version<= "26.0.50" emacs-version )

;; company-mode auto-completion, to turn off use :company-complete
(require 'company)
(setq company-idle-delay 0.2
      company-minimum-prefix-length 3)


Fire up doom-emacs in a stack project and it will forever be in the list of projects you can access at startup or anytime pressing space p p. The space opens up a useful command menu around closing buffers (windows), opening new files, opening the file tree, etc.

In vim there are two modes:

There is a world bound to spacebar from visual mode, that brings up a menu. There is tons here so feel free to explore:

Some useful ones:

space b - buffer menu, lots of options for splitting windows, new windows, etc. 
space b k - kill buffer aka close window 
space b b - switch to another open file (you can search here for your open files) 
space m - major mode specific functions, in haskell this is usually intero related stuff, starting repls, etc.
space o p - open the file tree for this project. Hit ? when this pane is in
focus for more commands like c-f, c-d for creating files/dirs 

Minimal VIM

Some minimal vim commands are handy. There are a zillion of these but these are the ones I use on a daily basis:

Quitting and saving

:q - quit 
:q! - quit w/o saving 
:w - save 

For movement, use the arrow keys. Eventually you will get use to using hjkl to move around as many commands use those (h - left, j - down, k - up, l - right).

gg - go to top of file
G - to bottom of file 
#G - go to line #, e.g. 127G 

$ - to end of line
^ - to beginning of line 

i - enter insert mode (insert under cursor)
a - enter insert mode (append after cursor) 
o - add a line under cursor and enter insert mode
shift-o - add a line above cursor and enter insert mode 

dd - delete line 
d#direction - e.g. d4j - delete 4 lines down
d$ - delete from cursor pos to end of line 
d^ - delete from cursor pos to start of line 
dG - delete to end of file

gcc - comment current line (will put in lang. specific comment) 
g#direction - e.g. g3k - comment 3 lines up

Cutting and pasting is a little weird at first:

dd, d4j, etc. above are really cutting. Whatever you delete goes onto the
p - paste (while in command mode) 

Copying revolves around yanking:

v - visual selection to select an area you want
v#direction - highlight a block, e.g. v4j - highlight 4 lines down 
y - yank highlighted visual selection (copy) 

You don't always need to highlight a visual selection 

y$ - yank cursor to end of line 
y^ - yank cursor to beginning of line
Y - yank current line
y#dir - yank # of lines in whatever dir 

Most things stack, so gg (enter) yG will go to the top of file and yank the entire file, for instance.

Searching is it's own thing. No ctrl-f here. Use /whatyouaresearchingfor in command mode. E.g. /yank and hit enter. Go to next occurence by hitting n. There are many good docs on finding/replacing in vim.

Undo is also weird:

u - undo (in command mode) 

Redo is super weird. There is actually an entire undo-tree you can access via :undo-tree-visualize. Hell just hit :undo and press tab. It's a whole world. Go read the docs. To use undo-tree-visualize either type in :undo-tree-visualize or use the emacs binding for it, which it C-x u which means ctrl-x u. In your private module you can rebind this to something else, even something based off the space bar. Personally, I just use C-x u.


Go start doom-emacs in a stack project (emacs setup.hs) or whatever. Quit out of emacs, and you will notice next time you open emacs from anywhere it will be in your list of projects off the main menu (you can also switch projects via space p p). Intero will give you syntax highlighting / errors, I don't use it for much else than that (I have terminals open for ghcid, ghci). You can get fancy inside of emacs but I like to keep it simple. Useful commands which are emacs, not vim commands, which can always be rebound to something else:

ctrl-c ctrl-t - type under cursor 
ctrl-c tab    - small documentation about the type, like it's definition
:hoogle       - search hoogle for something, if you have it over a type and hit enter it will go search hoogle for whatever you are on.


They joke that Emacs is like an OS so there is so much here. E.g. adding the following to your config.el:

     :desc "Undo Tree Visualize"     :n  "z" #'undo-tree-visualize))

adds Space-z to open the undo tree visualizer. Note: ctrl-x u still works.