(:use "COMMON-LISP" "SB-EXT")
(:shadowing-import-from "SB-IMPL" "SCRUB-CONTROL-STACK")
(:shadowing-import-from "SB-INT" "*REPL-PROMPT-FUN*" "*REPL-READ-FORM-FUN*" "*STEP*" "*STEPPING*")
;; user-level customization of UI
"*PROMPT*" "*EXIT-ON-EOF*" "*MAX-HISTORY*"
;; user-level customization of functionality
;; internalsish, but the documented way to make a new repl "object"
;; such that it inherits the current state of the repl but has its
;; own independent state subsequently.
(defvar *noprint* nil
"boolean: T if don't print prompt and output")
(defvar *break-level* 0
"current break level")
(defvar *inspect-break* nil
"boolean: T if break caused by inspect")
(defvar *continuable-break* nil
"boolean: T if break caused by continuable error")
(defun repl (&key
(break-level (1+ *break-level*))
(let ((*noprint* noprint)
(sb-int:/show0 "entering REPL")
(multiple-value-bind (reason reason-param)
;; reset toplevel step-condition handler
(setf *step* nil
(declare (ignore reason-param))
((and (eq reason :inspect)
((and (eq reason :pop)
(defun rep-one ()
"Read-Eval-Print one form"
;; (See comment preceding the definition of SCRUB-CONTROL-STACK.)
(funcall *repl-prompt-fun* *standard-output*)
;; (Should *REPL-PROMPT-FUN* be responsible for doing its own
;; FORCE-OUTPUT? I can't imagine a valid reason for it not to
;; be done here, so leaving it up to *REPL-PROMPT-FUN* seems
;; odd. But maybe there *is* a valid reason in some
;; circumstances? perhaps some deadlock issue when being driven
;; by another process or something...)
(let* ((form (funcall *repl-read-form-fun*
(results (multiple-value-list (sb-impl::interactive-eval form))))
(dolist (result results)
;; FIXME: Calling fresh-line before a result ensures the result starts
;; on a newline, but it usually generates an empty line.
;; One solution would be to have the newline's entered on the
;; input stream inform the output stream that the column should be
;; reset to the beginning of the line.
(prin1 result *standard-output*)))))