--- layout: ../Site.layout.js --- # 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 --eval`s towards `eepitch` Syncronously `swank:eval-in-emacs`es to get the current `eepitch-buffer-name`, then changes the eepitch target to the `target`, and `eepitch`es. ``` • (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)) # 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)) # 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))) # CL-USER> (1+ 2) 3 CL-USER> ``` ecl: ``` CL-USER> (SEND *SBCL* (QUOTE (1+ 2))) # 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](https://gamerplus.org/@screwlisp/115114918131931640)). Is my idea of a sequence of three-party conversations more than superficial?