Greetings,
I'm familiar with using M-x run-lisp in emacs to start a CL listener, but
is it possible to get a running CL image and emacs talking to one another?
I'd like to be able to do this with both Harlequin LispWorks on Unix and
Allegro CL on WinNT.
In each case, I'd like to take advantage of the GUI development environment
while still working primarily in emacs. [Yes, the editors in each grok
emacs key strokes, etc. -- but I like having everything in one frame.]
Kaelin Colclasure <······@himalia.talarian.com> writes:
< Greetings,
<
< I'm familiar with using M-x run-lisp in emacs to start a CL listener, but
< is it possible to get a running CL image and emacs talking to one another?
< I'd like to be able to do this with both Harlequin LispWorks on Unix and
< Allegro CL on WinNT.
<
< In each case, I'd like to take advantage of the GUI development environment
< while still working primarily in emacs. [Yes, the editors in each grok
< emacs key strokes, etc. -- but I like having everything in one frame.]
I don't know much about Lispworks for unix or ACL for windowsNT, but I
think the following might be useful anyway.
I used inet sockets to communicate between the lisp and emacs; the
docs for acl/linux says these types of sockets work on acl/NT. I know
that emacs 19.34 has open-network-stream and I imagine newer versions
would have this also. I don't know much about lispworks; my guess is
you may have to change some package names.
Here's the common lisp code. Took most of this from
sys:examples;server.cl from acl.
;;; Common Lisp
(in-package :user)
(defvar *socket-port* 8127)
(defvar *socket-process-name* "eServicer")
(defun emacs-evaluator (stream)
;; This isn't too safe
(loop for sexp = (read stream)
do (write-string
(princ-to-string
(ignore-errors
(eval sexp)))
stream)
(terpri stream)
(force-output stream)
until (and (stringp sexp)
(string-equal sexp "exit"))))
(defun start-emacs-server (&optional (function #'emacs-evaluator))
"Start a networked common lisp emacs eval server"
(let ((initial-socket
(socket:make-socket
:connect :passive
:format :text :type :stream
:local-port *socket-port*
:reuse-address t :address-family :internet)))
(mp:process-run-function *socket-process-name*
#'(lambda (socket)
(unwind-protect
(mp:process-run-function *socket-process-name*
#'(lambda (connection)
(unwind-protect
(funcall function connection)
(errorset (close connection) nil)))
(socket:accept-connection socket))
(errorset (close socket) nil)))
initial-socket)))
;;; The emacs lisp code starts here.
(defvar *socket-port* 8127)
(defvar *socket-process-name* "eServicer")
(defvar *socket-response-buffer* "*eServicer Response*")
(defun start-eserver ()
(cond ((get-process *socket-process-name*)
(error "The `%s' process is already running!" *socket-process-name*))
(t
(when (get-buffer *socket-response-buffer*)
(let ((old-buffer (current-buffer)))
(unwind-protect
(unless (eq (set-buffer (get-buffer *socket-response-buffer*))
old-buffer)
(erase-buffer))
(set-buffer old-buffer))))
(let ((socket
(open-network-stream
*socket-process-name*
*socket-response-buffer* "localhost" *socket-port*)))
(set-process-sentinel socket
(lambda (proc stat)
(message "%s terminated: %s" (process-name proc)
;; use subseq to remove newline from status message
(subseq stat 0 -1))))
socket))))
(defun eval-form-in-cl (form &optional no-display-p)
(let ((proc (get-process *socket-process-name*)))
(cond ((null proc)
(error "No %s process running" *socket-process-name*))
(t (process-send-string proc (prin1-to-string form))
(unless no-display-p
(display-buffer (process-buffer proc)))))))
(defun eval-in-cl (form)
"Eval FORM using common lisp"
(interactive "xCommon Lisp sexp: ")
(eval-form-in-cl form))
;;; EOF
;;; Example elisp forms
;; (start-eserver)
;; (eval-in-cl '(lisp-implementation-type))
;; (eval-in-cl '(lisp-implementation-version))
;; (eval-in-cl "exit")
I just started the lisp process with `start-emacs-server' and ran the
above forms in emacs. It shouldn't be much more work to start sending
things from the lisp to emacs, but with proper error handling and
recovery forms would probably be more involved.
I'm not sure how you could get around using a predetermined
socket port. Pretty interesting to hook up the editor and a lisp like
this, maybe you could fill the group in with what you end up doing?
Hope this helps some...