Distel = Emacs erlang-mode++

原文地址:http://bc.tech.coop/blog/070528.html

There are a number of different editor options for people wanting to develop Erlang code (see hereherehere); 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)

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, Luke Gorrie created Distel - an Emacs Lisp + Erlang package that fills this gap (I've mentioned Distel in previous blog posts hereherehere). Although Distel is a lot more than just an extension of Erlang Mode for Emacs, I'll focus on just the erlang-extended-mode aspects 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-mode in 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/ 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 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" (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 SLIME with Common Lisp, this is analogous to doing aslime-connect in SLIME.) 

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 erlang-mode:

Menu

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 standard erlang-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.

 

    • 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:
      1. Open the source member (e.g. - "beersong1.erl") in Emacs
      2. Start an Erlang Shell ("C-c C-z")
      3. Connect Distel to the Erlang Shell ("C-c C-d n" + node name)
      4. Compile the source member for debugging in the Erlang Shell ("c("beersong1", [debug_info]).")
      5. Reload the Erlang module ("C-c C-d L") in the source buffer
      6. Toggle debug interpreting of the module ("C-c C-d i")
      7. Set a breakpoint at a line in the module ("C-x SPC")
      8. From the Erlang Shell, run a function in the module ("beersong1:sing().")
      9. 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)
      10. The debugger window pops up:


      Debugger

      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.



Interactive Session

    • Process List: A pman-style process viewer ("C-c C-d l"), for tracing and inspecting the processes running on a node:



Process List

      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.
      Unfortunately, there is no "h" command to popup the help text of the available commands (as there is with the debugger commands); however, you can always see the available commands by pressing "C-h m" (

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

    • 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"):



Documentation

      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 (pdf or

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.

posted on 2013-06-13 19:15  百万军中  阅读(970)  评论(0编辑  收藏  举报