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.
EMACS
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.
THIS GUIDE HAS BEEN UPDATED 2019-10-05 FOR LATEST DOOM-EMACS AS THE INSTALL IS SIGNIFICANTLY EASIER NOW
DOOM-EMACS
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 https://github.com/hlissner/doom-emacs ~/.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
.
CUSTOMIZING DOOM-EMACS
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 )
(global-display-line-numbers-mode))
;; company-mode auto-completion, to turn off use :company-complete
(require 'company)
(setq company-idle-delay 0.2
company-minimum-prefix-length 3)
USING DOOM-EMACS
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:
- command mode - accessed via hitting
escape
- cut/pasting, deleting/comments lines, running commands, etc. - insertion mode - accessed many ways but usually via
i
for insert ora
for append from visual mode.
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
clipboard
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
.
Haskell
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.
Customization
They joke that Emacs is like an OS so there is so much here. E.g. adding the following to your config.el:
`(map!
(:leader
:desc "Undo Tree Visualize" :n "z" #'undo-tree-visualize))
adds Space-z to open the undo tree visualizer. Note: ctrl-x u
still works.