trivial-toplevel-prompt
2024-10-12
Portability library to customize REPL prompts.
Trivial Toplevel Prompt is a petty portability library to set the implementation-specific REPL prompt to a new, possibly more useful, value. It allows showing the inspect/debug/stepping statuses alongside the command number, current package, and current process or thread.
Tested on SBCL, CCL, ECL, ABCL, CLISP, Allegro CL (basically all the implementations I can run), and CMUCL (untested, incomplete). Help in supporting other implementations (like LispWorks with its prompt) is much appreciated!
1Getting started
Clone the Git repository: git clone https://github.com/aartaka/trivial-toplevel-prompt ~/common-lisp/
And then load :trivial-toplevel-prompt
in the REPL:
(asdf:load-system :trivial-toplevel-prompt)
;; or, if you use Quicklisp
(ql:quickload :trivial-toplevel-prompt)
You can also install Trivial Toplevel Prompt via Guix, using the
bundled guix.scm
file:
guix package -f guix.scm
2APIs
The main API function is set-toplevel-prompt
. The values that it
accepts are:
- String
- use it as a format control.
- Function
- use it to print the prompt to the REPL stream.
Arguments provided to both the format control and the printing function are (mostly modeled after Allegro CL APIs):
- Stream to print the prompt to. Only provided for the function, implied for the string.
- The current process/thread name (a string) or NIL when not provided/meaningless.
- The shortest possible name/nickname of the current package (
cl:*package*
). - A number indicating the command/expression number.
- A number indicating the current break/debug level.
- A boolean indicating whether stepping is enabled.
- A boolean indicating whether
inspect
is in progress.
Note that some implementations have custom REPLs for stepping and
inspection, so set-toplevel-prompt
will be useless for inspect and
stepping arguments.
Then there's reset-toplevel-prompt
to undo the effect of set-toplevel-prompt
, basically restoring the previous prompt state.
3Examples
Here's a simple format control example: just skip the process name, print package name and command number.
(trivial-toplevel-prompt:set-toplevel-prompt "~*~a~@[(~d)~]: ")
;; CL-USER(7):
And a more involved, Allegro-style ([4si] CL-USER(29):
) prompt:
(trivial-toplevel-prompt:set-toplevel-prompt
(lambda (stream process/thread-name package-name
command-number debug-level stepping-p inspect-p)
(declare (ignorable process/thread-name))
(when (or debug-level stepping-p inspect-p)
(format stream "[~@[~d~]~@[s~*~]~@[i~*~]] "
debug-level stepping-p inspect-p))
(format stream "~a~@[(~d)~]: " package-name command-number)))
;; [4si] CL-USER(29):
And then reset it:
(trivial-toplevel-prompt::reset-toplevel-prompt)
;; CL-USER(7):
(trivial-toplevel-prompt::reset-toplevel-prompt)
;; Back to implementation-specific prompt.