;;;; any given time, for this functionality is on the ACL website:
;;;; <http://www.franz.com/support/documentation/6.2/doc/top-level.htm>.
-(cl:defpackage :sb-aclrepl
- (:use :cl :sb-ext)
- (:export #:*prompt* #:*exit-on-eof* #:*max-history*
- #:*use-short-package-name* #:*command-char*
- #:alias))
-
(cl:in-package :sb-aclrepl)
+(defstruct user-cmd
+ (input nil) ; input, maybe a string or form
+ (func nil) ; cmd func entered, overloaded
+ ; (:eof :null-cmd :cmd-error :history-error)
+ (args nil) ; args for cmd func
+ (hnum nil)) ; history number
+
+
+;;; cmd table entry
+(defstruct cmd-table-entry
+ (name nil) ; name of command
+ (func nil) ; function handler
+ (desc nil) ; short description
+ (parsing nil) ; (:string :case-sensitive nil)
+ (group nil) ; command group (:cmd or :alias)
+ (abbr-len 0)) ; abbreviation length
+
(eval-when (:compile-toplevel :load-toplevel :execute)
- (defparameter *default-prompt* "~&~A(~d): "
+ (defparameter *default-prompt* "~:[~2*~;[~:*~D~:[~;i~]~:[~;c~]] ~]~A(~D): "
"The default prompt."))
(defparameter *prompt* #.*default-prompt*
"The current prompt string or formatter function.")
"The top-level directory stack")
(defparameter *command-char* #\:
"Prefix character for a top-level command")
-(defvar *max-history* 24
+(defvar *max-history* 100
"Maximum number of history commands to remember")
(defvar *exit-on-eof* t
"If T, then exit when the EOF character is entered.")
(declaim (type list *history*))
-(defstruct user-cmd
- (input nil) ; input, maybe a string or form
- (func nil) ; cmd func entered, overloaded
- ; (:eof :null-cmd :cmd-error :history-error)
- (args nil) ; args for cmd func
- (hnum nil)) ; history number
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (export '(*prompt* *exit-on-eof* *max-history*
+ *use-short-package-name* *command-char*
+ alias)))
-(defvar *eof-marker* (cons :eof nil))
+(defvar *eof-marker* :eof)
(defvar *eof-cmd* (make-user-cmd :func :eof))
(defvar *null-cmd* (make-user-cmd :func :null-cmd))
(*use-short-package-name* t)
(*dir-stack* nil)
(*command-char* #\:)
- (*max-history* 24)
+ (*max-history* 100)
(*exit-on-eof* t)
(*history* nil)
- (*cmd-number* 1))
+ (*cmd-number* 1)
+ )
(defun prompt-package-name ()
(if *use-short-package-name*
nil
(list args-string)))
(t
- (let ((string-stream (make-string-input-stream args-string)))
- (loop as arg = (read string-stream nil *eof-marker*)
- until (eq arg *eof-marker*)
+ (let ((string-stream (make-string-input-stream args-string))
+ (eof (cons nil *eof-marker*))) ;new cons for eq uniqueness
+ (loop as arg = (read string-stream nil eof)
+ until (eq arg eof)
collect arg))))))
(let ((next-char (peek-char-non-whitespace input-stream)))
(cond
(string-trim-whitespace (subseq line first-space-pos))
"")))
(declare (string line))
- (if (numberp (read-from-string cmd-string))
- (let ((cmd (get-history (read-from-string cmd-string))))
- (if (eq cmd *null-cmd*)
- (make-user-cmd :func :history-error
- :input (read-from-string cmd-string))
- (make-user-cmd :func (user-cmd-func cmd)
+ (cond
+ ((numberp (read-from-string cmd-string))
+ (let ((cmd (get-history (read-from-string cmd-string))))
+ (if (eq cmd *null-cmd*)
+ (make-user-cmd :func :history-error
+ :input (read-from-string cmd-string))
+ (make-user-cmd :func (user-cmd-func cmd)
:input (user-cmd-input cmd)
:args (user-cmd-args cmd)
- :hnum *cmd-number*)))
- (let ((cmd-entry (find-cmd cmd-string)))
- (if cmd-entry
- (make-user-cmd :func (cmd-table-entry-func cmd-entry)
- :input line
- :args (parse-args
- (cmd-table-entry-parsing cmd-entry)
+ :hnum *cmd-number*))))
+ ((or (zerop (length cmd-string))
+ (whitespace-char-p (char cmd-string 0)))
+ *null-cmd*)
+ (t
+ (let ((cmd-entry (find-cmd cmd-string)))
+ (if cmd-entry
+ (make-user-cmd :func (cmd-table-entry-func cmd-entry)
+ :input line
+ :args (parse-args
+ (cmd-table-entry-parsing cmd-entry)
cmd-args-string)
- :hnum *cmd-number*)
- (make-user-cmd :func :cmd-error
- :input cmd-string)
- )))))
+ :hnum *cmd-number*)
+ (make-user-cmd :func :cmd-error
+ :input cmd-string)))))))
((eql next-char #\newline)
(read-char input-stream)
*null-cmd*)
- (t
- (let ((form (read input-stream nil *eof-marker*)))
- (if (eq form *eof-marker*)
- *eof-cmd*
- (make-user-cmd :input form :func nil :hnum *cmd-number*))))))))
+ ((eql next-char :eof)
+ *eof-cmd*)
+ (t
+ (let* ((eof (cons nil *eof-marker*))
+ (form (read input-stream nil eof)))
+ (if (eq form eof)
+ *eof-cmd*
+ (make-user-cmd :input form :func nil :hnum *cmd-number*))))))))
-;;; cmd table entry
-(defstruct cmd-table-entry
- (name nil) ; name of command
- (func nil) ; function handler
- (desc nil) ; short description
- (parsing nil) ; (:string :case-sensitive nil)
- (group nil)) ; command group (:cmd or :alias)
-
-(defun make-cte (name-param func desc parsing group)
+(defun make-cte (name-param func desc parsing group abbr-len)
(let ((name (etypecase name-param
(string
name-param)
(symbol
(string-downcase (write-to-string name-param))))))
(make-cmd-table-entry :name name :func func :desc desc
- :parsing parsing :group group)))
+ :parsing parsing :group group
+ :abbr-len (if abbr-len
+ abbr-len
+ (length name)))))
(defun %add-entry (cmd &optional abbr-len)
(let* ((name (cmd-table-entry-name cmd))
(defun add-cmd-table-entry (cmd-string abbr-len func-name desc parsing)
(%add-entry
- (make-cte cmd-string (symbol-function func-name) desc parsing :cmd)
+ (make-cte cmd-string (symbol-function func-name) desc parsing :cmd abbr-len)
abbr-len))
(defun find-cmd (cmdstr)
(defun add-to-history (cmd)
(unless (and *history* (user-cmd= cmd (car *history*)))
(when (>= (length *history*) *max-history*)
- (setq *history* (nbutlast *history* (+ (length *history*) *max-history* 1))))
+ (setq *history* (nbutlast *history*
+ (1+ (- (length *history*) *max-history*)))))
(push cmd *history*)
(incf *cmd-number*)))
(let ((cmds '()))
(maphash (lambda (k v)
(when (and
- (eql (length k) (length (cmd-table-entry-name v)))
+ (= (length k) (length (cmd-table-entry-name v)))
(eq (cmd-table-entry-group v) group))
- (push (list k (cmd-table-entry-desc v)) cmds)))
+ (push (list k
+ (if (= (cmd-table-entry-abbr-len v)
+ (length k))
+ ""
+ (subseq k 0 (cmd-table-entry-abbr-len v)))
+ (cmd-table-entry-desc v)) cmds)))
*cmd-table-hash*)
(sort cmds #'string-lessp :key #'car)))
-(defun cd-cmd (output-stream &optional string-dir)
+(defun cd-cmd (&optional string-dir)
(cond
((or (zerop (length string-dir))
(string= string-dir "~"))
(let ((new (truename string-dir)))
(when (pathnamep new)
(setf cl:*default-pathname-defaults* new)))))
- (format output-stream "~A~%" (namestring cl:*default-pathname-defaults*))
+ (format *output* "~A~%" (namestring cl:*default-pathname-defaults*))
(values))
-(defun pwd-cmd (output-stream)
- (format output-stream "Lisp's current working directory is ~s.~%"
+(defun pwd-cmd ()
+ (format *output* "Lisp's current working directory is ~s.~%"
(namestring cl:*default-pathname-defaults*))
(values))
-(defun trace-cmd (output-stream &rest args)
+(defun trace-cmd (&rest args)
(if args
- (format output-stream "~A~%" (eval (sb-debug::expand-trace args)))
- (format output-stream "~A~%" (sb-debug::%list-traced-funs)))
+ (format *output* "~A~%" (eval (sb-debug::expand-trace args)))
+ (format *output* "~A~%" (sb-debug::%list-traced-funs)))
(values))
-(defun untrace-cmd (output-stream &rest args)
+(defun untrace-cmd (&rest args)
(if args
- (format output-stream "~A~%"
+ (format *output* "~A~%"
(eval
(sb-int:collect ((res))
(let ((current args))
`(sb-debug::untrace-1 ,(pop current))
`(sb-debug::untrace-1 ',name))))))
`(progn ,@(res) t))))
- (format output-stream "~A~%" (eval (sb-debug::untrace-all))))
+ (format *output* "~A~%" (eval (sb-debug::untrace-all))))
(values))
-(defun exit-cmd (output-stream &optional (status 0))
- (declare (ignore output-stream))
- (quit :unix-status status)
+#+sb-thread
+(defun thread-pids ()
+ "Return a list of the pids for all threads"
+ (let ((offset (* 4 sb-vm::thread-pid-slot)))
+ (sb-thread::mapcar-threads
+ #'(lambda (sap) (sb-sys:sap-ref-32 sap offset)))))
+
+#+sb-thread
+(defun other-thread-pids ()
+ "Returns a list of pids for all threads except the current process"
+ (delete (sb-thread:current-thread-id) (thread-pids) :test #'eql))
+
+(defun exit-cmd (&optional (status 0))
+ #+sb-thread
+ (let ((other-pids (other-thread-pids)))
+ (when other-pids
+ (format *output* "There exists the following processes~%")
+ (format *output* "~{~5d~%~}" other-pids)
+ (format *output* "Do you want to exit lisp anyway [n]? ")
+ (force-output *output*)
+ (let ((input (string-trim-whitespace (read-line *input*))))
+ (if (and (plusp (length input))
+ (or (char= #\y (char input 0))
+ (char= #\Y (char input 0))))
+ ;; loop in case more threads get created while trying to exit
+ (do ((pids other-pids (other-thread-pids)))
+ ((eq nil pids))
+ (map nil #'sb-thread:destroy-thread pids)
+ (sleep 0.2))
+ (return-from exit-cmd)))))
+ (sb-ext:quit :unix-status status)
(values))
-(defun package-cmd (output-stream &optional pkg)
+(defun package-cmd (&optional pkg)
(cond
((null pkg)
- (format output-stream "The ~A package is current.~%"
+ (format *output* "The ~A package is current.~%"
(package-name cl:*package*)))
((null (find-package (write-to-string pkg)))
- (format output-stream "Unknown package: ~A.~%" pkg))
+ (format *output* "Unknown package: ~A.~%" pkg))
(t
(setf cl:*package* (find-package (write-to-string pkg)))))
(values))
(defun string-to-list-skip-spaces (str)
"Return a list of strings, delimited by spaces, skipping spaces."
+ (declare (type (or null string) str))
(when str
(loop for i = 0 then (1+ j)
as j = (position #\space str :start i)
collect (subseq str i j) while j)))
(let ((last-files-loaded nil))
- (defun ld-cmd (output-stream &optional string-files)
+ (defun ld-cmd (&optional string-files)
(if string-files
(setq last-files-loaded string-files)
(setq string-files last-files-loaded))
(dolist (arg (string-to-list-skip-spaces string-files))
- (format output-stream "loading ~a~%" arg)
- (load arg)))
+ (let ((file
+ (if (string= arg "~/" :end1 1 :end2 1)
+ (merge-pathnames (parse-namestring
+ (string-left-trim "~/" arg))
+ (user-homedir-pathname))
+ arg)))
+ (format *output* "loading ~S~%" file)
+ (load file))))
(values))
-(defun cf-cmd (output-stream string-files)
- (declare (ignore output-stream))
+(defun cf-cmd (string-files)
(when string-files
(dolist (arg (string-to-list-skip-spaces string-files))
(compile-file arg)))
\f
;;;; implementation of commands
-(defun apropos-cmd (output-stream string)
- (declare (ignore output-stream))
+(defun apropos-cmd (string)
(apropos (string-upcase string))
(values))
(let ((last-files-loaded nil))
- (defun cload-cmd (output-stream &optional string-files)
+ (defun cload-cmd (&optional string-files)
(if string-files
(setq last-files-loaded string-files)
(setq string-files last-files-loaded))
(dolist (arg (string-to-list-skip-spaces string-files))
- (format output-stream "loading ~a~%" arg)
+ (format *output* "loading ~a~%" arg)
(load (compile-file-as-needed arg)))
(values)))
-(defun inspect-cmd (output-stream arg)
- (inspector arg nil output-stream)
+(defun inspect-cmd (arg)
+ (inspector arg nil *output*)
(values))
-(defun istep-cmd (output-stream &optional arg-string)
- (istep arg-string output-stream)
+(defun istep-cmd (&optional arg-string)
+ (istep (string-to-list-skip-spaces arg-string) *output*)
(values))
-(defun describe-cmd (output-stream &rest args)
- (declare (ignore output-stream))
+(defun describe-cmd (&rest args)
(dolist (arg args)
(eval `(describe ,arg)))
(values))
-(defun macroexpand-cmd (output-stream arg)
- (pprint (macroexpand arg) output-stream)
+(defun macroexpand-cmd (arg)
+ (pprint (macroexpand arg) *output*)
(values))
-(defun history-cmd (output-stream)
+(defun history-cmd ()
(let ((n (length *history*)))
(declare (fixnum n))
(dotimes (i n)
(declare (fixnum i))
(let ((hist (nth (- n i 1) *history*)))
- (format output-stream "~3A ~A~%" (user-cmd-hnum hist)
- (user-cmd-input hist)))))
+ (format *output* "~3A " (user-cmd-hnum hist))
+ (if (stringp (user-cmd-input hist))
+ (format *output* "~A~%" (user-cmd-input hist))
+ (format *output* "~W~%" (user-cmd-input hist))))))
(values))
-(defun help-cmd (output-stream &optional cmd)
+(defun help-cmd (&optional cmd)
(cond
(cmd
(let ((cmd-entry (find-cmd cmd)))
(if cmd-entry
- (format output-stream "Documentation for ~A: ~A~%"
+ (format *output* "Documentation for ~A: ~A~%"
(cmd-table-entry-name cmd-entry)
(cmd-table-entry-desc cmd-entry)))))
(t
- (format output-stream "~13A ~a~%" "Command" "Description")
- (format output-stream "------------- -------------~%")
- (format output-stream "~13A ~A~%" "n"
- "(for any number n) recall nth command from history list")
+ (format *output* "~11A ~4A ~A~%" "COMMAND" "ABBR" "DESCRIPTION")
+ (format *output* "~11A ~4A ~A~%" "<n>" ""
+ "re-execute <n>th history command")
(dolist (doc-entry (get-cmd-doc-list :cmd))
- (format output-stream "~13A ~A~%" (car doc-entry) (cadr doc-entry)))))
+ (format *output* "~11A ~4A ~A~%" (first doc-entry)
+ (second doc-entry) (third doc-entry)))))
(values))
-(defun alias-cmd (output-stream)
+(defun alias-cmd ()
(let ((doc-entries (get-cmd-doc-list :alias)))
(typecase doc-entries
(cons
- (format output-stream "~13A ~a~%" "Alias" "Description")
- (format output-stream "------------- -------------~%")
+ (format *output* "~11A ~A ~4A~%" "ALIAS" "ABBR" "DESCRIPTION")
(dolist (doc-entry doc-entries)
- (format output-stream "~13A ~A~%" (car doc-entry) (cadr doc-entry))))
+ (format *output* "~11A ~4A ~A~%" (first doc-entry) (second doc-entry) (third doc-entry))))
(t
- (format output-stream "No aliases are defined~%"))))
+ (format *output* "No aliases are defined~%"))))
(values))
-(defun shell-cmd (output-stream string-arg)
+(defun shell-cmd (string-arg)
(sb-ext:run-program "/bin/sh" (list "-c" string-arg)
- :input nil :output output-stream)
+ :input nil :output *output*)
(values))
-(defun pushd-cmd (output-stream string-arg)
+(defun pushd-cmd (string-arg)
(push string-arg *dir-stack*)
- (cd-cmd output-stream string-arg)
+ (cd-cmd *output* string-arg)
(values))
-(defun popd-cmd (output-stream)
+(defun popd-cmd ()
(if *dir-stack*
(let ((dir (pop *dir-stack*)))
(cd-cmd dir))
- (format output-stream "No directory on stack to pop.~%"))
+ (format *output* "No directory on stack to pop.~%"))
+ (values))
+
+(defun pop-cmd (&optional (n 1))
+ #+ignore
+ (let ((new-level (- (length *break-stack*) n 1)))
+ (when (minusp new-level)
+ (setq new-level 0))
+ (dotimes (i (- (length *break-stack*) new-level 1))
+ (pop *break-stack*)))
+ ;; Find inspector
+ #+ignore
+ (do* ((i (1- (length *break-stack*)) (1- i))
+ (found nil))
+ ((or found (minusp i)))
+ (let ((inspect (break-data-inspect (nth i *break-stack*))))
+ (when inspect
+ (set-current-inspect inspect)
+ (setq found t))))
+ (when *inspect-reason*
+ (throw 'inspect-quit nil))
+ (values))
+
+(defun continue-cmd (&optional (n 0))
+ (let ((restarts (compute-restarts)))
+ (if restarts
+ (if (< -1 n (length restarts))
+ (invoke-restart-interactively (nth n restarts))
+ (format *output* "~&There is no such restart"))
+ (format *output* "~&There are no restarts"))))
+
+(defun error-cmd ()
+ (print-restarts))
+
+(defun current-cmd ()
+ )
+
+(defun frame-cmd ()
+ )
+
+(defun zoom-cmd ()
+ )
+
+(defun local-cmd (&optional var)
+ (declare (ignore var))
+ )
+
+(defun processes-cmd ()
+ #+sb-thread
+ (let ((pids (thread-pids))
+ (current-pid (sb-thread:current-thread-id)))
+ (dolist (pid pids)
+ (format *output* "~&~D" pid)
+ (when (= pid current-pid)
+ (format *output* " [current listener]"))))
+ #-sb-thread
+ (format *output* "~&Threads are not supported in this version of sbcl")
+ (values))
+
+(defun kill-cmd (&rest selected-pids)
+ #+sb-thread
+ (let ((pids (thread-pids)))
+ (dolist (selected-pid selected-pids)
+ (if (find selected-pid pids :test #'eql)
+ (progn
+ (sb-thread:destroy-thread selected-pid)
+ (format *output* "~&Thread ~A destroyed" selected-pid))
+ (format *output* "~&No thread ~A exists" selected-pid))))
+ #-sb-thread
+ (declare (ignore selected-pids))
+ #-sb-thread
+ (format *output* "~&Threads are not supported in this version of sbcl")
+ (values))
+
+(defun signal-cmd (signal &rest selected-pids)
+ #+sb-thread
+ (let ((pids (thread-pids)))
+ (dolist (selected-pid selected-pids)
+ (if (find selected-pid pids :test #'eql)
+ (progn
+ (sb-unix:unix-kill selected-pid signal)
+ (format *output* "~&Signal ~A sent to thread ~A"
+ signal selected-pid))
+ (format *output* "~&No thread ~A exists" selected-pid))))
+ #-sb-thread
+ (declare (ignore signal selected-pids))
+ #-sb-thread
+ (format *output* "~&Threads are not supported in this version of sbcl")
+ (values))
+
+(defun focus-cmd (&optional process)
+ #-sb-thread
+ (declare (ignore process))
+ #+sb-thread
+ (when process
+ (format *output* "~&Focusing on next thread waiting waiting for the debugger~%"))
+ #+sb-thread
+ (progn
+ (sb-thread:release-foreground)
+ (sleep 1))
+ #-sb-thread
+ (format *output* "~&Threads are not supported in this version of sbcl")
+ (values))
+
+(defun reset-cmd ()
+ #+ignore
+ (setf *break-stack* (last *break-stack*))
(values))
-(defun dirs-cmd (output-stream)
+(defun dirs-cmd ()
(dolist (dir *dir-stack*)
- (format output-stream "~a~%" dir))
+ (format *output* "~a~%" dir))
(values))
+
\f
;;;; dispatch table for commands
("cf" 2 cf-cmd "compile file" :parsing :string)
("cload" 2 cload-cmd "compile if needed and load file"
:parsing :string)
+ ("current" 3 current-cmd "print the expression for the current stack frame")
+ ("continue" 4 continue-cmd "continue from a continuable error")
("describe" 2 describe-cmd "describe an object")
("macroexpand" 2 macroexpand-cmd "macroexpand an expression")
("package" 2 package-cmd "change current package")
+ ("error" 3 error-cmd "print the last error message")
("exit" 2 exit-cmd "exit sbcl")
+ ("frame" 2 frame-cmd "print info about the current frame")
("help" 2 help-cmd "print this help")
("history" 3 history-cmd "print the recent history")
("inspect" 2 inspect-cmd "inspect an object")
("istep" 1 istep-cmd "navigate within inspection of a lisp object" :parsing :string)
+ #+sb-thread ("kill" 2 kill-cmd "kill (destroy) processes")
+ #+sb-thread ("signal" 2 signal-cmd "send a signal to processes")
+ #+sb-thread ("focus" 2 focus-cmd "focus the top level on a process")
+ ("local" 3 local-cmd "print the value of a local variable")
("pwd" 3 pwd-cmd "print current directory")
("pushd" 2 pushd-cmd "push directory on stack" :parsing :string)
- ("popd" 2 popd-cmd "pop directory from stack")
+ ("pop" 3 pop-cmd "pop up `n' (default 1) break levels")
+ ("popd" 4 popd-cmd "pop directory from stack")
+ #+sb-thread ("processes" 3 processes-cmd "list all processes")
+ ("reset" 3 reset-cmd "reset to top break level")
("trace" 2 trace-cmd "trace a function")
("untrace" 4 untrace-cmd "untrace a function")
("dirs" 2 dirs-cmd "show directory stack")
- ("shell" 2 shell-cmd "execute a shell cmd" :parsing :string))))
+ ("shell" 2 shell-cmd "execute a shell cmd" :parsing :string)
+ ("zoom" 2 zoom-cmd "print the runtime stack")
+ )))
(dolist (cmd cmd-table)
(destructuring-bind (cmd-string abbr-len func-name desc &key parsing) cmd
(add-cmd-table-entry cmd-string abbr-len func-name desc parsing))))
\f
;;;; machinery for aliases
-(defsetf alias (name) (user-func)
+(defsetf alias (name &key abbr-len description) (user-func)
`(progn
(%add-entry
- (make-cte (quote ,name) ,user-func "" nil :alias))
+ (make-cte (quote ,name) ,user-func ,description nil :alias ,abbr-len))
(quote ,name)))
(defmacro alias (name-param args &rest body)
(setq abbr-index param)))))
`(progn
(%add-entry
- (make-cte (quote ,name) (lambda ,args ,@body) ,desc ,parsing :alias)
+ (make-cte (quote ,name) (lambda ,args ,@body) ,desc ,parsing :alias (when ,abbr-index
+ (1+ ,abbr-index)))
,abbr-index)
,name)))
(string-trim '(#\space #\tab #\return)
str))
-(defun whitespace-char-not-newline-p (x)
+(defun whitespace-char-p (x)
(and (characterp x)
(or (char= x #\space)
(char= x #\tab)
+ (char= x #\newline)
(char= x #\return))))
+(defun whitespace-char-not-newline-p (x)
+ (and (whitespace-char-p x)
+ (not (char= x #\newline))))
+
\f
;;;; linking into SBCL hooks
+
(defun repl-prompt-fun (stream)
- (if (functionp *prompt*)
- (write-string (funcall *prompt* (prompt-package-name) *cmd-number*)
- stream)
- (format stream *prompt* (prompt-package-name) *cmd-number*)))
+ (let ((break-level
+ (if (zerop *break-level*) nil *break-level*)))
+ #+sb-thread
+ (let ((lock sb-thread::*session-lock*))
+ (sb-thread::get-foreground)
+ (let ((stopped-threads (sb-thread::waitqueue-data lock)))
+ (when stopped-threads
+ (format stream "~{~&Thread ~A suspended~}~%" stopped-threads))))
+ (if (functionp *prompt*)
+ (write-string (funcall *prompt*
+ *inspect-reason*
+ *continuable-reason*
+ (prompt-package-name) *cmd-number*)
+ stream)
+ (handler-case
+ (format nil *prompt* break-level
+ *inspect-reason*
+ *continuable-reason*
+ (prompt-package-name) *cmd-number*)
+ (error ()
+ (format stream "~&Prompt error> "))
+ (:no-error (prompt)
+ (format stream "~&~A" prompt))))))
-(defun process-cmd (user-cmd output-stream)
+(defun process-cmd (user-cmd)
;; Processes a user command. Returns t if the user-cmd was a top-level
;; command
(cond ((eq user-cmd *eof-cmd*)
(when *exit-on-eof*
- (quit))
- (format output-stream "EOF~%")
+ (sb-ext:quit))
+ (format *output* "EOF~%")
t)
((eq user-cmd *null-cmd*)
t)
((eq (user-cmd-func user-cmd) :cmd-error)
- (format output-stream "Unknown top-level command: ~s.~%"
+ (format *output* "Unknown top-level command: ~s.~%"
(user-cmd-input user-cmd))
- (format output-stream "Type `:help' for the list of commands.~%")
+ (format *output* "Type `:help' for the list of commands.~%")
t)
((eq (user-cmd-func user-cmd) :history-error)
- (format output-stream "Input numbered ~d is not on the history list~%"
+ (format *output* "Input numbered ~d is not on the history list~%"
(user-cmd-input user-cmd))
t)
((functionp (user-cmd-func user-cmd))
(add-to-history user-cmd)
- (apply (user-cmd-func user-cmd) output-stream (user-cmd-args user-cmd))
+ (apply (user-cmd-func user-cmd) (user-cmd-args user-cmd))
(fresh-line)
t)
(t
(add-to-history user-cmd)
nil))) ; nope, not in my job description
-(defun repl-read-form-fun (input-stream output-stream)
+(defun repl-read-form-fun (input output)
;; Pick off all the leading ACL magic commands, then return a normal
;; Lisp form.
- (loop for user-cmd = (read-cmd input-stream) do
- (if (process-cmd user-cmd output-stream)
+ (let ((*input* input)
+ (*output* output))
+ (loop for user-cmd = (read-cmd *input*) do
+ (if (process-cmd user-cmd)
(progn
- (repl-prompt-fun output-stream)
- (force-output output-stream))
- (return (user-cmd-input user-cmd)))))
+ (funcall sb-int:*repl-prompt-fun* *output*)
+ (force-output *output*))
+ (return (user-cmd-input user-cmd))))))
(setf sb-int:*repl-prompt-fun* #'repl-prompt-fun