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*))