[slime-devel] proposed customization mechanism for repl behavior

Alan Ruttenberg alanr-l at mumble.net
Fri May 6 19:01:48 UTC 2005


For some work I am doing I wanted to customize the behavior of the repl 
so that some forms wouldn't be evaluated,
but instead handled in a different way. Below is a proposed hook for 
doing so. Unless someone can think of why this is a
bad idea, or finds a bug, I'll update the cvs sources. This would be a 
change to swank.lisp.

It also fixes a behavior I found objectionable, namely that when a form 
caused an error, and you aborted,  *, **, *** and friends
were changed.

(in-package :swank)

(defvar *slime-repl-advance-history* nil
   "In the dynamic scope of a single form typed at the repl, set to nil 
to
    prevent the repl from advancing the history - * ** *** etc.")

(defvar *slime-repl-suppress-output* nil
   "In the dynamic scope of a single form typed at the repl, set to nil 
to
    prevent the repl from printing the result of the evalation.")

(defvar *slime-repl-eval-hook-pass* (gensym "PASS")
   "Token to indicate that a repl hook declines to evaluate the form")

(defvar *slime-repl-eval-hooks* nil
   "A list of functions. When the repl is about to eval a form, first 
try running each of
    these hooks. The first hook which returns a value which is not 
*slime-repl-eval-hook-pass*
    is considered a replacement for calling eval. If there are no hooks, 
or all
    pass, then eval is used.")

(defslimefun listener-eval (string)
   (clear-user-input)
   (with-buffer-syntax ()
     (let ((*slime-repl-suppress-output* :unset)
	  (*slime-repl-advance-history* :unset))
       (multiple-value-bind (values last-form) (eval-region string t)
	(unless (or (and (eq values nil) (eq last-form nil))
		    (eq *slime-repl-advance-history* nil))
	  (setq *** **  ** *  * (car values)
		/// //  // /  / values))
	(setq +++ ++  ++ +  + last-form)
	(if (eq *slime-repl-suppress-output* t)
	    ""
	    (cond ((null values) "; No value")
		  (t
		   (format nil "~{~S~^~%~}" values))))))))

(defun eval-region (string &optional package-update-p)
   "Evaluate STRING and return the result.
If PACKAGE-UPDATE-P is non-nil, and evaluation causes a package
change, then send Emacs an update."
   (unwind-protect
        (with-input-from-string (stream string)
          (let (- values)
            (loop
             (let ((form (read stream nil stream)))
               (when (eq form stream)
                 (fresh-line)
                 (force-output)
                 (return (values values -)))
               (setq - form)
	      (if *slime-repl-eval-hooks*
		  (loop for hook in *slime-repl-eval-hooks*
			for res =  (multiple-value-list (funcall hook form))
			until (not (eq (car res) *slime-repl-eval-hook-pass*))
			finally
			(when (eq (car res) *slime-repl-eval-hook-pass*)
			    (setq values (multiple-value-list (eval form)))))
		  (setq values (multiple-value-list (eval form))))
               (force-output)))))
     (when (and package-update-p (not (eq *package* *buffer-package*)))
       (send-to-emacs
        (list :new-package (package-name *package*)
              (package-string-for-prompt *package*))))))

;; example hook - if you type (setq foo *) then nothing is printed, and
;; the history is not advanced.

(defun setq-no-print-repl-hook(form)
   (if (and (listp form) (listp (cdr form))
	   (eq (car form) 'setq)
	   (eq (third form) '*))
       (progn
	(setq *slime-repl-suppress-output* t)
	(setq *slime-repl-advance-history* nil)
	(eval form))
       *slime-repl-eval-hook-pass*))




More information about the slime-devel mailing list