Distel, the other way around

Luke Gorrie luke@REDACTED
Wed Dec 17 14:36:06 CET 2003


"Vlad Dumitrescu" <vlad_dumitrescu@REDACTED> writes:

> I think I am not alone when I wish there was a nicer interface to Erlang than
> the shell, visually and functionally. Distel is a great tool, but what I'd like
> to see is more like how Mozart/Oz does it: the integration is tighter, and there
> are colors ;-)

What makes the integration tighter (apart from the colours :-)? We'll
soon show them who's boss!

(well maybe not that soon.. few things to do :-)

> This is why I thought: why not use Distel the other way around, to drive Emacs
> from Erlang. If we can call Emacs functions from Erlang, then we can build a
> nice front-end.

The way Distel works it that an Emacs buffer is a process. Erlang can
send a message to an Emacs buffer, and the buffer then receives it
(with `erl-receive') and decides what to do. So all of the mechanisms
are available -- it's just a matter of doing the cool stuff with them.

Here's how to write an RPC server process in Distel / Emacs Lisp:

  (defun rpc-server ()
    "Start an RPC server process with registered name 'rpc-server'.
  The process will be an emacs buffer called '*reg rpc-server*'."
    (interactive)
    (erl-spawn
      (erl-register 'rpc-server)
      (&rpc-loop)))

  (defun &rpc-loop ()
    "RPC server loop: receive an expression in a message and evaluate it.
  Log all the expressions we get in our buffer."
    (erl-receive ()
        ((['eval expression]
          (insert (format "Evalulating %S\n" expression))
          (ignore-errors (eval expression))))
      (&rpc-loop)))

This is roughly equivalent to Erlang:

  rpc_server() ->
      spawn(fun() -> register(rpc_server, self()),
                     rpc_server_loop() end).

  rpc_server_loop() ->
      receive
          {eval, Expr} ->
              io:format("Evaluating ~p~n", [Expr]),
              catch eval(Expr)
      end,
      rpc_server_loop().

(The Elisp code is tested, the Erlang isn't -- and note that `eval' is
a builtin in Elisp.)

If you do `M-x rpc-server' it starts the server process in a buffer
called "*reg rpc-server*".

Unfortunately, you can't send a message from Erlang to Emacs using a
registered name "{foo, node@REDACTED} ! ..."  syntax -- probably just
because Distel connects as a hidden node. So in Erlang you need to
somehow get the PID of the Elisp process. One way is to do an RPC from
Emacs to Erlang that prints the pid, here on Erlang node x@REDACTED:

  (erl-send-rpc 'x@REDACTED
                'io 'format (list "Emacs RPC server pid: ~p~n"
                                  (list (erl-whereis 'rpc-server))))

Which will print (in Emacs, because stdio/group_leader is redirected)
a message like:

  Emacs RPC server pid: <4408.2.0>

Then in the Erlang shell you can write:

  P = pid(4408, 2, 0),
  P ! {eval, [message, "This is a small lisp program that prints a message"]}.

which runs the Elisp program (message "This ...") in Emacs. You see
the message in the minibuffer area.

Cheers,
Luke




More information about the erlang-questions mailing list