I have recently started programming Erlang again, and I also decided to retrain myself as a terminal Emacs user (I'm nostalgic for the '80s and my old glorious green and black terminal :P).
Switching to an editor for me requires having auto-completion and auto-lint working in the languages I use, or I get very cross fast.
I haven't found any complete and recent guide for setting up Emacs for Erlang, so I'm calling this guide "Modern".
You'll probably want to setup package management with Cask and pallet for your Emacs, follow this guide for that.
I assume you have a clean ~/.emacs
file and that you'll put any git repos we'll clone in ~/.emacs.d
.
The first choice to make is: EDTS (more like an IDE) or a self-made setup?
EDTS
I tried EDTS, but I get the huge slowdown he mentions in the README.md, so that's a no-go for me. Also I don't really like to have all the choices already made, I prefer to figure out myself what functionality I want.
I posted a guide on how to install EDTS, because I found it a bit treacherous.
Self-made
So, to get syntax highlighting, lint and autocomplete, the packages we need are:
- erlang-mode, it should be in your Erlang install (how to install Erlang with kerl if you don't have one)
- distel
- popup
- company
- flycheck
- flycheck-tip
- company-distel
Install deps
The first thing you'll want to do is hit M-x package-list-packages
and install:
- popup
- company
- flycheck
- flycheck-tip
or you can put them in your Cask
file and do a cask install
from the cli.
erlang-mode
Find where your Erlang mode is. If you installed Erlang following my guide it will be wherever you installed the kerl build, and then: <erl-dir>/lib/tools-<version>/emacs
.
I usually install kerl builds following the pattern ~/.erlangs/<version>
.
Once you have that path, add this to your .emacs
or init.el
, or equivalent file:
(setq load-path (cons "<erl-dir>/lib/tools-<version>/emacs" load-path))
(require 'erlang-start)
(setq erlang-root-dir "<erl-dir>/")
(setq exec-path (cons "<erl-dir>/bin" exec-path))
(setq erlang-man-root-dir "<erl-dir>/man")
Check that it worked by opening an Erlang file, you should see "Erlang" in the mode, and it should syntax highlight properly.
Flycheck
You should have Flycheck installed from before, so add these lines to your .emacs
or equivalent:
(require 'flycheck)
(flycheck-define-checker erlang-otp
"An Erlang syntax checker using the Erlang interpreter."
:command ("erlc" "-o" temporary-directory "-Wall"
"-I" "../include" "-I" "../../include"
"-I" "../../../include" source)
:error-patterns
((warning line-start (file-name) ":" line ": Warning:" (message) line-end)
(error line-start (file-name) ":" line ": " (message) line-end)))
(add-hook 'erlang-mode-hook
(lambda ()
(flycheck-select-checker 'erlang-otp)
(flycheck-mode)))
If you open an Erlang file now and start typing, errors (highlighted in red) and warnings (highlighted in yellow) should show up and you should have a "FlyC" in the modes.
Flycheck has a lot of functionality, to learn more this is a good article.
Tip: C-c ! l
will give you a list of all your errors and warnings.
Flycheck tip
If you'd like to get the messages from flycheck to show up as tooltips, use flycheck-tip.
You installed it as a package, so it should be sufficient to add this to your .emacs
or equivalent:
(require 'flycheck-tip)
(flycheck-tip-use-timer 'verbose)
You can find more options at its github page.
If you open an Erlang file with some errors and warnings now, they should show as a tooltip when your cursor is on them.
Distel
Installing Distel requires cloning it from its github repo to ~/.emacs.d/distel
or anywhere you prefer.
You'll to go to the director, hit make
, it will compile the Erlang code. You might need to add it to your Erlang code paths, depending on your Erlang install.
If you want the docs, cd doc && make info && sudo make install
.
info distel
to read them.
Then add the path to your .emacs
file, require and setup:
(push "~/.emacs.d/distel/elisp/" load-path)
(require 'distel)
(distel-setup)
To make your life easier you'll probably want to give it a default node name:
;; prevent annoying hang-on-compile
(defvar inferior-erlang-prompt-timeout t)
;; default node name to emacs@localhost
(setq inferior-erlang-machine-options '("-sname" "emacs"))
;; tell distel to default to that node
(setq erl-nodename-cache
(make-symbol
(concat
"emacs@"
;; Mac OS X uses "name.local" instead of "name", this should work
;; pretty much anywhere without having to muck with NetInfo
;; ... but I only tested it on Mac OS X.
(car (split-string (shell-command-to-string "hostname"))))))
(taken from this post)
Distel runs Erlang nodes, and has a lot of functionality, you should look at the docs to learn it.
The main commands you need to get started are:
C-c C-z
for starting the nodeM-.
when the cursor is on a function to show its definitionM-TAB
to autocomplete
Unless a node is started, most functionality won't work, so start a node first.
I suggest you try whether that worked now. Autocomplete is a bit cumbersome, because it shows in a different buffer.
We'll fix that now.
Auto complete
Last but not least, getting auto complete to work conveniently is not really documented anywhere that I could find.
We need to setup the company
package we installed before:
(add-hook 'after-init-hook 'global-company-mode)
added to your ~/.emacs
will activate company for all buffers.
Now it needs a source to autocomplete from, and company-distel is the package for that. You have to clone it from github, as before in ~/.emacs.d/
will do.
Then add this to your .emacs
:
(push "~/.emacs.d/company-distel/" load-path)
(require 'company-distel)
(with-eval-after-load 'company
(add-to-list 'company-backends 'company-distel))
(require 'company-distel-frontend)
At this point your autocomplete from Distel will show up in a convenient popup. If it doesn't, try M-x company-complete
, and that should give it a push.
Watch out if you use company-mode
for more than one language, you'll likely need to hook it to the mode, instead of just adding it to the backends list:
(add-hook 'erlang-mode-hook
(lambda ()
(setq company-backends '(company-distel))))
That's all, hopefully it worked. If not please let me know.
Comments? Give me a shout at @lambda_cat.
To get the latest post updates subscribe to the LambdaCat newsletter.
You can support my writing on LambdaCat's Patreon.