Distel = Emacs erlang-mode++
Monday, May 28, 2007
There are a number of different editor options for people wanting to develop Erlang code (see here, here, here); however, most people seem to use Emacs (which suits me just fine, because that's what I use most of the time anyhow). For Emacs users, the standard Erlang Mode for Emacs (which is included as part of the Erlang distribution) is what most people use. It has a lot of the functionality that you need when working with Erlang code and a lot of the "traditional" things that are normally found in an Emacs major mode for a programming language. It has support for things such as:
- Indentation (according to Erlang syntax rules)
- Comments (knows about Erlang comment structure)
- Movement (key bindings to move to beginning/end of an Erlang function/clause)
- Marking (key bindings to put region around current function/clause)
- Function header commands (to create new clauses and clone arguments from existing function)
- Arrow alignment (key bindings to align arrows of clauses in a region)
- Syntax highlighting (colorization of code)
- Tag support
- Skeleton templates
- Launch Erlang shell
- Compile Erlang code and view errors
- View Man pages for Erlang functions, commands, modules, files and applications inside of Emacs
- Imenu support (for displaying list of Erlang functions in a menu)
erlang-extended-modeaspects of it here. Since Luke also did a lot of the work on SLIME, any Lisper who uses SLIME will notice a lot of similarities between SLIME and Distel. Distel is an extension to
erlang-modein the same sense that SLIME is an extension to
lisp-mode(and it has some of the same types of extensions).
First of all, a few tips about installing Distel. If you Google for Distel, you'll find it in a number of different places. The "canonical" home page is on Luke's site at http://fresh.homeunix.net/~luke/distel/ (and the online documentation is still there); but, the actual source code has been hosted at different times in two separate Sourceforge projects and on the Erlang CEAN site as well. However, the current development repository for Distel is at the distel project on Google Code. To download it, you'll need to check it out from the Subversion repository using the following command:
svn checkout http://distel.googlecode.com/svn/trunk/ distelOnce you've checked it out, you'll need to follow the INSTALL instructions to build things and then update your .emacs file. Here's what I have in my .emacs file to setup Erlang mode and Distel:
;; This is needed for Erlang mode setup (setq erlang-root-dir "/usr/local/lib/erlang") (setq load-path (cons "/usr/local/lib/erlang/lib/tools-2.5.1/emacs" load-path)) (setq exec-path (cons "/usr/local/lib/erlang/bin" exec-path)) (require 'erlang-start)In addition, I add the following customizations:
;; This is needed for Distel setup (let ((distel-dir "/Users/bc/Projects/distel/elisp")) (unless (member distel-dir load-path) ;; Add distel-dir to the end of load-path (setq load-path (append load-path (list distel-dir)))))
(require 'distel) (distel-setup)
;; Some Erlang customizations (add-hook 'erlang-mode-hook (lambda () ;; when starting an Erlang shell in Emacs, default in the node name (setq inferior-erlang-machine-options '("-sname" "emacs")) ;; add Erlang functions to an imenu menu (imenu-add-to-menubar "imenu")))Since Distel is designed to communicate with a running Erlang node (make certain that you have an Erlang cookie set up properly!), the first thing I generally do in an Erlang source buffer is start up Erlang (if it's not already running). Usually, if I'm just playing around with something, I'll start up an Erlang Shell in Emacs with "C-c C-z" (
;; A number of the erlang-extended-mode key bindings are useful in the shell too (defconst distel-shell-keys '(("\C-\M-i" erl-complete) ("\M-?" erl-complete) ("\M-." erl-find-source-under-point) ("\M-," erl-find-source-unwind) ("\M-*" erl-find-source-unwind) ) "Additional keys to bind when in Erlang shell.")
(add-hook 'erlang-shell-mode-hook (lambda () ;; add some Distel bindings to the Erlang shell (dolist (spec distel-shell-keys) (define-key erlang-shell-mode-map (car spec) (cadr spec)))))
erlang-shell-display) and connect to that; otherwise, I'll connect to an instance that I've started up outside of Emacs (either locally or remotely). In my .emacs file, I've got the
inferior-erlang-machine-optionsvariable set to "-sname emacs" so that the default node name for an Erlang shell started in Emacs is "emacs@bc". So, once I've got an Erlang node going, I'll connect Distel to it by pressing "C-c C-d n" (
erl-choose-nodename) and specify the node I want to connect to ("emacs" if I'm connecting to the Erlang shell in Emacs) - that establishes which Erlang node all Distel commands will go to. (Note: For someone familiar with using SLIME with Common Lisp, this is analogous to doing a
Once you've setup things correctly and opened an Erlang source member, if you look at the "Erlang" menu (that was created by
erlang-mode), you'll see that Distel has added some additional commands to that menu. Although Distel provides some functionality not covered by the menu options, the menu options will give you a good idea of a lot of the supplemental functionality over and above what is provided by
Here are some of the things that Distel provides:
- Dynamic TAGS: Distel replaces the
erlang-modebindings for "M-.", -"M-,", and "M-*" with equivalents that are not TAG-file based. You can jump from a call like "io:format(template(Bottle), phrase(Bottle))" directly to the source code for io:format/2 (using "M-.") to inspect the definition, and then unwind back to where you came from (using "M-," or "M-*"). You can also jump from strings like "sing/0" (as found in export lists). Unlike the standard
erlang-modefunctionality, these commands don't require a TAGS file since Distel talks to an Erlang node to track down the source file based on the location of the beam file.
- Completion: Distel provides an Erlang-specific completion facility that allows you to write some portion of a module or function name and then press "M-TAB" to have the remainder completed automatically (e.g. - "io:fo" becomes "io:format(").
- Debugger: An Emacs front-end to the Erlang
debugger. Lets you interpret modules, set breakpoints, attach
to processes, view variables and single-step through code (similar to
edebug) all from within Emacs (no more using the
TCL/TK GUI app - yay!). Setting up the debugger requires a few
steps, but it isn't hard to do. Basically, the steps I follow for starting up debugging are:
- Open the source member (e.g. - "beersong1.erl") in Emacs
- Start an Erlang Shell ("C-c C-z")
- Connect Distel to the Erlang Shell ("C-c C-d n" + node name)
- Compile the source member for debugging in the Erlang Shell ("c("beersong1", [debug_info]).")
- Reload the Erlang module ("C-c C-d L") in the source buffer
- Toggle debug interpreting of the module ("C-c C-d i")
- Set a breakpoint at a line in the module ("C-x SPC")
- From the Erlang Shell, run a function in the module ("beersong1:sing().")
- The debugger's process list comes up in a browse window and I press RET on the process to select it for debugging (there can potentially be multiple processes that are being debugged at the same time)
- The debugger window pops up:
The Distel Erlang debugger looks and functions in a manner very similar to Emacs Lisp edebug. Under the covers, it is interacting with the standard Erlang debugger. The following commands are available in the debugger buffer:
- h: Popup help text of available commands.
- q: Quit the viewer (doesn't kill the process)
- SPC: Step (into expression)
- n: Next (over expression)
- u: Up to the next stack frame
- d: Down to the next stack frame
- c: Continue (until breakpoint)
- b: Toggle a breakpoint on the current line.
- Interactive Sessions: This is a "Scratchpad"-like buffer where you can define Erlang functions and run expressions, like a cross between the Erlang shell and the function-at-a-time definition/testing of Emacs Lisp. So far, I haven't found this to be all that useful. It's similar to the *scratch* buffer used in Emacs Lisp programming and the SLIME scratch buffer. However, some Erlang commands can't be interactively evaluated in that buffer and I've found it to be a bit "buggy". But, I've never used the scratch buffers much when I've done elisp or CL programming either (as I prefer to work in either the source buffer or the REPL/shell), so maybe I'm just not appreciating this functionality due to my personal development habits. Distel does provide an interactive eval function ("C-c C-d :"), so you can interactively test functionality without switching to the Erlang Shell. I personally find the combination of this with the shell usually works best for me.
- Process List: A pman-style process viewer ("C-c C-d l"), for tracing and inspecting the processes running on a node:
- q: Quit the process listing viewer, restoring old window config.
- u: Update the process list.
- k: Send an EXIT signal with reason 'kill' to process at point.
- RET: Show process_info for process at point.
- i: Show a piece of process_info for process at point.
- b: Show a backtrace for the process at point.
- m: Show the message queue for the process at point.
- Profiler: Front-end to fprof ("C-c C-d
p"), so that you can
enter an Erlang expression in the minibuffer and then browse the
results of profiling it. For example, the lower buffer here shows
some of the profiler output after running
"beersong1:sing()"using the interactive eval function ("C-c C-d :") in the top source buffer:
- Online Documentation: Search through documentation
automatically scanned out of all Erlang modules
("fdoc".). The screenshot below shows the difference
between running the standard man-page documentation for
lists:duplicate/2function (the bottom buffer of the screen) and the Distel documentation function output ("C-c C-d d"):
- Refactoring: Distel provides simple refactoring capabilities to allow you to move an expression out of a function into its own function. You can select an expression within a function, run the command (using "C-c C-d f") and the sub-expression is refactored out into a call to a new function.
Available commands in the process buffer are:
describe-mode) in the process viewer buffer.
The man-page documentation might be more complete; however, sometimes the comments that are in the source code are the only source of documentation (or it might be more accurate and up-to-date) and the Distel online documentation function returns those. In addition to the documentation command, there is an "apropos" command that will bring up a list of all functions that match a regular expression.
ps.gz), which describes how to use Distel and what commands are available. For more in-depth information, read the Reference Manual (pdf or ps.gz). In addition to those two documents, Luke's 2002 Erlang User Conference paper Distel: Distributed Emacs Lisp (pdf or ps.gz), describes Distel's motivation and workings in detail. Lastly, the Distel mailing list (also available via gmane) can be a good source of information.