原文地址:
There are a number of different editor options for people wanting to develop Erlang code (see , , ); however, most people seem to use Emacs (which suits me just fine, because that's what I use anyhow). For Emacs users, the standard (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)
However, coming from a Lisp background, I'm used to being able to interact directly with the underlying Lisp implementation, and I missed not having that available when working with Erlang code. Fortunately, created - an Emacs Lisp + Erlang package that fills this gap (I've mentioned Distel in previous blog posts , , ). Although Distel is a lot more than just an extension of , I'll focus on just the erlang-extended-mode
aspects of it here. Since Luke also did a lot of the work on , any Lisper who uses SLIME will notice a lot of similarities between SLIME and Distel. Distel is an extension to erlang-mode
in the same sense that SLIME is an extension to lisp-mode
(and it has some of the same types of extensions).
svn checkout http://distel.googlecode.com/svn/trunk/ distel
Once 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) ;; 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)
In addition, I add the following customizations:
;; 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"))) ;; 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)))))
Since Distel is designed to communicate with a running Erlang node (make certain that you have an 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" (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 theinferior-erlang-machine-options
variable 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 with Common Lisp, this is analogous to doing aslime-connect
in SLIME.)
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 erlang-mode
:Here are some of the things that Distel provides: -
- Dynamic TAGS: Distel replaces the standard
erlang-mode
bindings 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 standarderlang-mode
functionality, 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.
- Dynamic TAGS: Distel replaces the standard
-
- 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 ) all from within Emacs (no more using the 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:
- 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.
- 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 ) all from within Emacs (no more using the 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:
-
- 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:
-
- Available commands in the process buffer are:
- 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.
- Available commands in the process buffer are:
describe-mode
-
- ) in the process viewer buffer.
-
- 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:
- 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
-
- 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 the
lists:duplicate/2
function (the bottom buffer of the screen) and the Distel documentation function output ("C-c C-d d"):
- 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 the
-
- 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.
- 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.
If you program in Erlang and use Emacs, then I think it's really worthwhile to have a look at Distel. The best first document to read on Distel is the User Manual ( or
), which describes how to use Distel and what commands are available. For more in-depth information, read the Reference Manual ( or ). In addition to those two documents, Luke's 2002 Erlang User Conference paper Distel: Distributed Emacs Lisp ( or ), describes Distel's motivation and workings in detail. Lastly, the (also available ) can be a good source of information.