screwlisp proposes kittens

Emacsclient common lisp slime eepitch: the reckoning. Three-way-conversations.

In my rushed article yesterday, I started making an eev eepitches-using-emacsclient class which I didn’t quite finish. Let’s finish now.

Quickly, my reason for using emacsclient was that I wanted the eepitches to be performed from-outside. When I was doing them via swank:eval-in-emacs in certain cases, things happened not-in-the-order-I-wanted. Hence emacsclient. (Eduardo has been thinking about doing something special with named pipes, but this is where I am at right now).

Since we are going via spawning emacsclient processes, you need to issue M-x start-server for this to be enabled.

A common lisp class that emacsclient --evals towards eepitch

Syncronously swank:eval-in-emacses to get the current eepitch-buffer-name, then changes the eepitch target to the target, and eepitches.

(setq inferior-lisp-program "sbcl")(slime)(setq eepitch-buffer-name "*slime-repl sbcl*")(setq inferior-lisp-program "ecl")(slime)

From before.

(defclass eepitch ()
  ((target :initarg :target)
   (previous))
  (:default-initargs :target "*slime-repl ECL*"))

(defmethod send ((obj eepitch) expression)
  (with-slots (previous target) obj
    (uiop:launch-program
     (let ((*print-pretty* nil))
       (format nil "emacsclient -e '~?'"
	       "(progn (setq eepitch-buffer-name ~s) ~@
	       (eepitch-line ~a~s~a) ~@
	       (setq eepitch-buffer-name ~s))"
	       `(,target #" ,expression #" ,previous))))))

(defmethod send :before ((obj eepitch) expression)
  (with-slots (target previous) obj
    (setf previous
	  (swank:eval-in-emacs 'eepitch-buffer-name))))

Trying that.

• (setq eepitch-buffer-name "*slime-repl sbcl*")
(defparameter *ecl*
  (make-instance 'eepitch
		 :target "*slime-repl ECL*"))
 eepitch-buffer-name
(send *ecl* '(1+ 1))
 eepitch-buffer-name

Voila. In *slime-repl ECL*:

; SLIME 2.29.1
CL-USER> (1+ 1)
2

Back in *slime-repl sbcl*:

CL-USER> (defparameter *ecl*
	     (make-instance 'eepitch
			    		 :target "*slime-repl ECL*"))
*ECL*
CL-USER> (send *ecl* '(1+ 1))
#<UIOP/LAUNCH-PROGRAM::PROCESS-INFO {1002C4C663}>
CL-USER> 

And vice versa

• (setq eepitch-buffer-name "*slime-repl ECL*")
;; above definitions again.
(defparameter *sbcl* (make-instance 'eepitch :Target "*slime-repl sbcl*"))
(send *sbcl* '(1+ 1))

Having done the defclass eepitch in the ECL repl:

CL-USER> (defparameter *sbcl* (make-instance 'eepitch :Target "*slime-repl sbcl*"))
*SBCL*
CL-USER> (send *sbcl* '(1+ 1))
#<a UIOP/RUN-PROGRAM::PROCESS-INFO 0x7f40f03f9a00>
CL-USER> 

Whence in *slime-repl sbcl*:

CL-USER> (1+ 1)
2
CL-USER> 

SBCL!ECL : Two+ jump eepitching

This begs the question:

• (setq eepitch-buffer-name "*slime-repl sbcl*")
(send *ecl* '(send *sbcl* '(1+ 2)))
• eepitch-buffer-name

Got it, seems to unwind as expected.

sbcl:

CL-USER> (send *ecl* '(send *sbcl* '(1+ 2)))
#<UIOP/LAUNCH-PROGRAM::PROCESS-INFO {1002C4E6D3}>
CL-USER> (1+ 2)
3
CL-USER> 

ecl:

CL-USER> (SEND *SBCL* (QUOTE (1+ 2)))
#<a UIOP/RUN-PROGRAM::PROCESS-INFO 0x7f40f03f95c0>
CL-USER> 

Conclusions

We wrote a common lisp class that uses an emacsclient async process to eepitch forms to other targets using the emacs server (i.e. M-x server-start).

This stores the previous eepitch-buffer-name using the :before common lisp object system method qualifier, which eepitch-buffer-name is returned to in a progn with the form being pitched. This appears to unwind correctly, while being sent asyncronously using uiop:launch-program.

Hence we have fairly robust eepitching eepitching eepitching eepitching eepitching, though the aesthetically appealling process is to have eepitch’s three buffer configuration and watch the two buffers’ conversation happening in real time. Creating a sequence of two-repl conversations, into which the human can interject freely with their own eepitches, hopefully with the current converse-ees, so as not to disrupt the three panel layout.

This interimage communication medium has the oddly human semblance of a series of three-person dialogs which would be disrupted by any of the participants starting a conversation with a fourth member. Rather, there would be a subsequent meeting with a new set of participants.

The human is different to the two lisp images in that each lisp-image would use for-example yes-or-no-p in their own repl to receive responses from the human, whereas the lisp images communicate with each other by asyncronously sending one-way instructions (the instruction may be get back to me).

Fin.

All right! What do you think? (On the Mastodon thread). Is my idea of a sequence of three-party conversations more than superficial?

screwlisp proposes kittens