(cl:defpackage :sb-aclrepl
- (:use :cl :sb-ext))
+ (: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*")
+ (:export
+ ;; user-level customization of UI
+ "*PROMPT*" "*EXIT-ON-EOF*" "*MAX-HISTORY*"
+ "*USE-SHORT-PACKAGE-NAME*" "*COMMAND-CHAR*"
+ ;; user-level customization of functionality
+ "ALIAS"
+ ;; 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.
+ "MAKE-REPL-FUN"))
(cl:in-package :sb-aclrepl)
-(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")
-
-(shadowing-import '(sb-impl::scrub-control-stack
- sb-int:*repl-prompt-fun* sb-int:*repl-read-form-fun*)
- :sb-aclrepl)
-
+(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*))
- (noprint *noprint*)
- (inspect nil)
- (continuable nil))
+ (break-level (1+ *break-level*))
+ (noprint *noprint*)
+ (inspect nil)
+ (continuable nil))
(let ((*noprint* noprint)
- (*break-level* break-level)
- (*inspect-break* inspect)
- (*continuable-break* continuable))
+ (*break-level* break-level)
+ (*inspect-break* inspect)
+ (*continuable-break* continuable))
(sb-int:/show0 "entering REPL")
(loop
(multiple-value-bind (reason reason-param)
- (catch 'repl-catcher
- (loop
- (rep-one)))
+ (catch 'repl-catcher
+ (loop
+ (unwind-protect
+ (rep-one)
+ ;; reset toplevel step-condition handler
+ (setf *step* nil
+ *stepping* nil))))
+ (declare (ignore reason-param))
(cond
- ((and (eq reason :inspect)
- (plusp *break-level*))
- (return-from repl))
- ((and (eq reason :pop)
- (plusp *break-level*))
- (return-from repl)))))))
+ ((and (eq reason :inspect)
+ (plusp *break-level*))
+ (return-from repl))
+ ((and (eq reason :pop)
+ (plusp *break-level*))
+ (return-from repl)))))))
(defun rep-one ()
"Read-Eval-Print one form"
;; by another process or something...)
(force-output *standard-output*))
(let* ((form (funcall *repl-read-form-fun*
- *standard-input*
- *standard-output*))
- (results (multiple-value-list (sb-impl::interactive-eval form))))
+ *standard-input*
+ *standard-output*))
+ (results (multiple-value-list (sb-impl::interactive-eval form))))
(unless *noprint*
(dolist (result results)
- ;; Don't fresh-line before a result, since newline was entered by user
- ;; in *repl-read-form-fun*
- (fresh-line *standard-output*)
- (prin1 result *standard-output*)))))
-
-(defun repl-fun (noprint)
- (repl :noprint noprint :break-level 0))
-
-(when (boundp 'sb-impl::*repl-fun*)
- (setq sb-impl::*repl-fun* #'repl-fun))
+ ;; 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.
+ (fresh-line *standard-output*)
+ (prin1 result *standard-output*)))))