Commit 84acffd2 authored by Joao Tavora's avatar Joao Tavora
Browse files

Stability fixes in sly-mrepl

* contrib/sly-mrepl.el: Fix top doc.
(sly-mrepl): Don't list license and authord in contrib def.
(sly-mrepl--prompt): `accept-process-output' here.
(:write-values): Not here.
(:evaluation-aborted): Print condition.

* contrib/swank-mrepl.lisp (listener-channel): Remove DEDICATED slot, add
IN and OUT.
(initialize-instance): Make IN and OUT here, possibly blocking
while waiting for Emacs to connect to OUT.
(create-mrepl): Don't open DEDICATED here.
(mrepl-eval): Use HANDLER-CASE to catch errors. Always flush
streams.
(flush-streams): New function.
(send-prompt): Just send prompt.
parent a06b4a01
Showing with 41 additions and 34 deletions
+41 -34
;; -*- lexical-binding: t -*- ;; -*- lexical-binding: t -*- An experimental implementation of
;; An experimental implementation of multiple REPLs multiplexed over a ;; multiple REPLs multiplexed over a single Slime socket. M-x
;; single Slime socket. M-x sly-open-listener creates a new REPL ;; sly-mrepl or M-x sly-mrepl-new create new REPL buffers.
;; buffer.
;; ;;
(require 'sly) (require 'sly)
(require 'inferior-sly) ; inferior-sly-indent-lime (require 'inferior-sly) ; inferior-sly-indent-lime
...@@ -9,8 +8,6 @@ ...@@ -9,8 +8,6 @@
(define-sly-contrib sly-mrepl (define-sly-contrib sly-mrepl
"Multiple REPLs." "Multiple REPLs."
(:authors "Helmut Eller <heller@common-lisp.net>")
(:license "GPL")
(:swank-dependencies swank-mrepl) (:swank-dependencies swank-mrepl)
(:on-load (:on-load
(define-key sly-inspector-mode-map (kbd "M-RET") 'sly-inspector-copy-down-to-repl) (define-key sly-inspector-mode-map (kbd "M-RET") 'sly-inspector-copy-down-to-repl)
...@@ -133,12 +130,18 @@ emptied.See also `sly-mrepl-hook'") ...@@ -133,12 +130,18 @@ emptied.See also `sly-mrepl-hook'")
(set (make-local-variable 'sly-mrepl--prompt) prompt))) (set (make-local-variable 'sly-mrepl--prompt) prompt)))
(defun sly-mrepl--prompt () (defun sly-mrepl--prompt ()
(when (and sly-mrepl--dedicated-stream
(process-live-p sly-mrepl--dedicated-stream))
;; This non-blocking call should be enough to allow asynch calls
;; to `sly-mrepl--insert-output' to still see the correct value
;; for `sly-mrepl--output-marker' just before we set it.
(accept-process-output))
(sly-mrepl--insert (pcase (current-column) (sly-mrepl--insert (pcase (current-column)
(0 "") (0 "")
(t "\n"))) (t "\n")))
(set-marker sly-mrepl--output-mark (sly-mrepl--mark)) (set-marker sly-mrepl--output-mark (sly-mrepl--mark))
(sly-mrepl--insert (format "%s> " (sly-mrepl--insert (format "%s> "
sly-mrepl--prompt)) sly-mrepl--prompt))
(sly-mrepl--recenter)) (sly-mrepl--recenter))
(defun sly-mrepl--recenter () (defun sly-mrepl--recenter ()
...@@ -169,18 +172,12 @@ emptied.See also `sly-mrepl-hook'") ...@@ -169,18 +172,12 @@ emptied.See also `sly-mrepl-hook'")
(sly-mrepl--insert "\n")) (sly-mrepl--insert "\n"))
(when (null values) (when (null values)
(sly-mrepl--insert "; No values")) (sly-mrepl--insert "; No values"))
(when (and sly-mrepl--dedicated-stream
(process-live-p sly-mrepl--dedicated-stream))
;; This non-blocking call should be enough to allow
;; `sly-mrepl--insert-output' to still see the correct value
;; for `sly-mrepl--output-marker', before `sly-mrepl-prompt'
;; sets it.
(accept-process-output))
(sly-mrepl--prompt)))) (sly-mrepl--prompt))))
(sly-define-channel-method listener :evaluation-aborted () (sly-define-channel-method listener :evaluation-aborted (&optional condition)
(with-current-buffer (sly-channel-get self 'buffer) (with-current-buffer (sly-channel-get self 'buffer)
(sly-mrepl--insert "; Evaluation aborted\n"))) (sly-mrepl--insert (format "; Evaluation aborted on %s\n" condition))
(sly-mrepl--prompt)))
(sly-define-channel-method listener :write-string (string) (sly-define-channel-method listener :write-string (string)
(with-current-buffer (sly-channel-get self 'buffer) (with-current-buffer (sly-channel-get self 'buffer)
......
...@@ -42,7 +42,8 @@ ...@@ -42,7 +42,8 @@
(env :initarg :env :accessor env) (env :initarg :env :accessor env)
(mode :initform :eval :accessor channel-mode) (mode :initform :eval :accessor channel-mode)
(tag :initform nil) (tag :initform nil)
(dedicated :initform nil :accessor dedicated))) (out :reader out)
(in :reader in)))
(defmethod initialize-instance :after ((channel listener-channel) (defmethod initialize-instance :after ((channel listener-channel)
&rest initargs) &rest initargs)
...@@ -51,7 +52,12 @@ ...@@ -51,7 +52,12 @@
(setf (slot-value channel 'swank::thread) (setf (slot-value channel 'swank::thread)
(if (use-threads-p) (if (use-threads-p)
(spawn-listener-thread *emacs-connection* channel) (spawn-listener-thread *emacs-connection* channel)
nil))) nil))
(setf (slot-value channel 'out)
(or (and *use-dedicated-output-stream*
(open-dedicated-output-stream channel))
(make-listener-output-stream channel)))
(setf (slot-value channel 'in) (make-listener-input-stream channel)))
(defun package-prompt (package) (defun package-prompt (package)
(reduce (lambda (x y) (if (<= (length x) (length y)) x y)) (reduce (lambda (x y) (if (<= (length x) (length y)) x y))
...@@ -65,9 +71,6 @@ ...@@ -65,9 +71,6 @@
:name (format nil "mrepl listener for remote ~a" remote))) :name (format nil "mrepl listener for remote ~a" remote)))
(thread (channel-thread ch))) (thread (channel-thread ch)))
(when *use-dedicated-output-stream*
(setf (dedicated ch) (open-dedicated-output-stream ch)))
(setf (slot-value ch 'env) (initial-listener-env ch)) (setf (slot-value ch 'env) (initial-listener-env ch))
(when thread (when thread
...@@ -80,11 +83,11 @@ ...@@ -80,11 +83,11 @@
(defvar *history* nil) (defvar *history* nil)
(defun initial-listener-env (channel) (defun initial-listener-env (channel)
(let* ((out (make-listener-output-stream channel)) (let* ((out (out channel))
(in (make-listener-input-stream channel)) (in (in channel))
(io (make-two-way-stream in out))) (io (make-two-way-stream in out)))
`((cl:*package* . ,*package*) `((cl:*package* . ,*package*)
(cl:*standard-output* . ,(or (dedicated channel) out)) (cl:*standard-output* . ,out)
(cl:*standard-input* . ,in) (cl:*standard-input* . ,in)
(cl:*trace-output* . ,out) (cl:*trace-output* . ,out)
(cl:*error-output* . ,out) (cl:*error-output* . ,out)
...@@ -153,10 +156,16 @@ ...@@ -153,10 +156,16 @@
(let ((p *package*) (let ((p *package*)
results) results)
(unwind-protect (unwind-protect
(progn (setq results (with-sly-interrupts (read-eval-print string))) (handler-case
(setq aborted nil)) (progn
(setq results (with-sly-interrupts (read-eval-print string))
aborted nil))
(error (err)
(setq aborted err)))
(flush-streams channel)
(cond (aborted (cond (aborted
(send-to-remote-channel remote `(:evaluation-aborted))) (send-to-remote-channel remote `(:evaluation-aborted
,(prin1-to-string aborted))))
(t (t
(when / (when /
(setq *** ** ** * * (car /) (setq *** ** ** * * (car /)
...@@ -168,13 +177,14 @@ ...@@ -168,13 +177,14 @@
(loop for binding in env (loop for binding in env
do (setf (cdr binding) (symbol-value (car binding)))))))))) do (setf (cdr binding) (symbol-value (car binding))))))))))
(defun flush-streams (channel)
(with-slots (in out) channel
(force-output out)
(clear-input in)))
(defun send-prompt (channel) (defun send-prompt (channel)
(with-slots (env remote) channel (with-slots (env remote) channel
(let ((pkg (or (cdr (assoc '*package* env)) *package*)) (let ((pkg (or (cdr (assoc '*package* env)) *package*)))
(out (cdr (assoc '*standard-output* env)))
(in (cdr (assoc '*standard-input* env))))
(when out (force-output out))
(when in (clear-input in))
(send-to-remote-channel remote `(:prompt ,(package-name pkg) (send-to-remote-channel remote `(:prompt ,(package-name pkg)
,(package-prompt pkg)))))) ,(package-prompt pkg))))))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment