[slime-devel] eval-in-emacs and 'window'-debugger

Antonio Menezes Leitao aml at gia.ist.utl.pt
Thu Feb 10 00:35:22 UTC 2005


Helmut Eller <e9626484 at stud3.tuwien.ac.at> writes:

> Antonio Menezes Leitao <aml at gia.ist.utl.pt> writes:
>> Is there a different swank function for that? (in the
>> emacs-lisp-interface from Franz I used a lep::eval-in-emacs that did
>> precisely what I needed).
> No, there's currently no such thing.  We could probably generalize the
> code that reads input from the REPL (see READ-USER-INPUT-FROM-EMACS)
> to support arbitrary calls.  But this will not happen before the Great
> Release.
>> This is very useful to provide refactoring operations (that operate on
>> the Lisp side) that need to interact with the user using emacs lisp
>> operations such as y-or-n-p or read-from-minibuffer.
> I think it is good principle to keep the interaction between Emacs and
> Lisp to a minimum.  I'm not sure, tough, whether such Y-OR-N-P-style
> functions help to reduce the interactions; experience will tell.
>> I know that it might be difficult to find a general scheme to
>> translate from emacs lisp values to common lisp values but all I need
>> is symbols, strings, numbers and such.
> Yes, keywords, strings, numbers, and cons trees map quite nicely
> between the to dialects.  For other objects it's better to exchange
> some index or numeric id.

Six months later, I decided to bite the bullet.  I'm not sure I did it
correctly but it's working.  However, I did a bit of copy&paste that
surely could be improved by someone that knows about slime internals.

I would be glad if someone could correct/improve my patches.  Here are
the changes:

In file slime.el, I added a function that is a simplified version of

(defun evaluate-in-emacs (expr thread tag)
  (push thread slime-read-string-threads)
  (push tag slime-read-string-tags)
  (slime-repl-return-string (eval expr)))

and I also included an extra clause in slime-dispatch-event, as

(defun slime-dispatch-event (event &optional process)
      ((:read-string thread tag)
       (assert thread)
       (slime-repl-read-string thread tag))
      ((:evaluate-in-emacs string thread tag)      ;;<--
       (assert thread)
       (evaluate-in-emacs (car (read-from-string string)) thread tag))
      ((:read-aborted thread tag)
       (assert thread)
       (slime-repl-abort-read thread tag))

In file swank.lisp, I added a function that was mostly copied&pasted
from read-user-input-from-emacs:

(defun evaluate-in-emacs (string)
  (let ((*read-input-catch-tag* (1+ *read-input-catch-tag*)))
    (send-to-emacs `(:evaluate-in-emacs ,string ,(current-thread) ,*read-input-catch-tag*))
    (let ((ok nil))
           (prog1 (catch (intern-catch-tag *read-input-catch-tag*)
                    (loop (read-from-emacs)))
             (setq ok t))
        (unless ok 
          (send-to-emacs `(:read-aborted ,(current-thread)

and I also included an extra clause in dispatch-event, as follows:

(defun dispatch-event (event socket-io)
    ((:read-string thread &rest args)
     (encode-message `(:read-string ,(thread-id thread) , at args) socket-io))
    ((:evaluate-in-emacs string thread &rest args) ;;AML
     (encode-message `(:evaluate-in-emacs ,string ,(thread-id thread) , at args) socket-io))
    ((:read-aborted thread &rest args)
     (encode-message `(:read-aborted ,(thread-id thread) , at args) socket-io))

That's all.

These changes allow me to evaluate, on the Common Lisp side,
expressions that interact with the user via the Emacs editor, such as:

CL-USER> (swank::evaluate-in-emacs "(y-or-n-p \"Continue?\")")
CL-USER> (swank::evaluate-in-emacs "(read-from-minibuffer \"Your name:\")")
"Antonio Leitao"

These (and others) are very useful to implement some refactoring
operations that need to interact with the user and that should be
hidden in the Common Lisp side.

Best regards,

António Leitão.

More information about the slime-devel mailing list