Building a readline application is cool, but readline gives you the basics and you must still build a REPL around it: loop and read commands, catch a
C-d, ask confirmation to quit, print the general help, the help of a command, setup the completion of commands, the completion of their arguments, load an init file, colorize output,...
replic does this for you.
You can use
replic as a ready-to-use executable or as a library.
Using the executable, you can define functions and variables in
~/.replic.lisp, give them completion candidates, and use them straight away on the replic command line.
With the library you can automatically build a REPL and turn functions you already have into commands in the readline prompt, with the process described below.
There are a few examples below, in
src/examples.lisp and expect more to come.
This is an attempt at generalizing what I did several times with
What this is not:
- this is not a Lisp REPL. See cl-repl for that (itself not a replacement for Slime ;) )
- this is not a shell. See shcl.
Example applications built on replic:
Either download the executable (a 14MB zipped download, a 60Mo GNU/Linux x64 self-contained binary, instant start-up !), make it executable (
chmod +x replic) and run it:
either clone this repo into
and build the executable with
Note_: you need the cl-readline library from Quicklisp of end of may, 2018 (for the read and write history feature). See
make install for a quick clone.
Available options: -h, --help Print this help and exit. -q, --quiet Do not load the init file. -l, --load ARG Load the given file.
and see the available commands:
replic > help replic > help help
Now add commands in your lisp init file (see next section) or build an application with it (see the Developer section).
User: the executable and the init file
Given the example
~/.replic.lisp below, you can try
hello <name> (completion for
goodbye <name>, where <name> can be completed from what was given to
(in-package :replic.user) (defparameter *names* '() "List of names (string) given to `hello`. Will be autocompleted by `goodbye`.") (defun hello (name) "Takes only one argument. Adds the given name to the global `*names*` variable, used to complete arguments of `goodbye`. " (format t "hello ~a~&" name) (push name *names*)) (defun goodbye (name) "Says goodbye to name, where `name` should be completed from what was given to `hello`." (format t "goodbye ~a~&" name)) (replic.completion:add-completion "goodbye" (lambda () *names*)) (export '(hello goodbye))
Note that only the
export'ed functions and parameters will be taken into account.
See more examples in the
src/examples.lisp file of this repository.
Define custom completion for arguments
Write a function or a variable and
You can associate a function name with a list of completion candidates (a list of strings) or a function:
(replic.completion:add-completion "goodbye" (lambda () *names*))
When you have many functions that should complete from the same list, you can set a default completion function:
(setf replic.completion:*default-command-completion* #'my-function)
You get a built-in
help command that shows the documentation of functions and variables:
replic > help Available commands ================== help ... Print the help of all available commands. reload ... NIL set ... Change a variable, see its value, or see all variables. quit --- Quit the application. Available variables =================== *verbose* ... Example setting.
Write a preamble and a postamble in
You can read the help of a specific command or variable (with completion):
help shows the first paragraph of the functions/parameters docstring, the
help <cmd> function is more complete and shows all of it.
Setting and seeing variables
set can be used with zero, one or two arguments:
shows all available variables,
this prints the value of this variable (use auto-completion),
set *variable* new-value
and this sets a new value. "yes", "true" and "t" denote true.
We kept the "earmuffs" to denote variables.
Replic reads an
init-like configuration file. It searches a
.replic.conf file under
~/.config/ and at the user's home directory (
These are the default parameters with their default values:
[default] confirm-exit = true verbose = false prompt = >? history = true write-history = true
"true", "True" and "t" are truthy and "false", "False" and "nil" are falsy.
It must begin with a section name (
default) (we don't handle different profiles yet).
They are overriden by command line arguments.
Developer: using replic as a library with an existing system
Change the prompt
You can change the prompt. It defaults to "> ". It can contain ansi colours.
(setf replic:*prompt* (cl-ansi-text:green "replic > "))
You can add a prefix to it, for example one that changes with the state of the application (current directory,...):
(setf replic:*prompt-prefix* (format t "(~a) " "sthg"))
and concatenate the two with
Load base commands (help, reload, set)
If you want to have the base commands (
quit), import the base package:
Create commands from a package's exported functions
Create the commands from all the exported functions and variables:
To exclude functions, use the
(replic:functions-to-commands :my-package :exclude '("main"))
Create a command from one function:
(replic.completion:add-command :function :package) ;; add a variable: (replic.completion:add-variable :*variable* :package)
Load a config file
replic searches by default for a
.replic.conf (see above). The function
replic.config:apply-config takes as first parameter a package name (as a symbol):
and as an optional second parameter, you can give another file name:
(replic.config:apply-config :torrents ".torrents.conf")
The exported variables from the package can then be overriden in the config file. For example, the
:replic package exports
(:export :main :confirm :repl :functions-to-commands :help :set :reload ;; settings :*help-preamble* :*help-postamble* :*prompt* :*prompt-prefix* :*confirm-exit* :*write-history* :*verbose*))
so we can configure:
[default] write-history = true verbose = true prompt = my silly prompt
and so on.
Note: for now, we look only at the "default" section.
Start the repl
Start the repl:
That's it. You didn't have to write the REPL.
Variables that are exported from a package on the lisp side will be automacitally available for the config file and read when the application starts up. The rule is that in the config file, we don't use earmuffs (
foo). Lispers shall use a lispy config file anyway.
The available variables are:
*verbose*(bool): if true, print stuff during the program execution.
*confirm-exit*(bool): if true (the default), ask for confirmation when a user tries to exit the program with a
*prompt*(str): the readline prompt. Defaults to simply
>?. Can contain ansi colours (use
*confirm-exit*(t or nil): if
t(the default), ask for confirmation when the user tries to exit the command line with a
*write-history*(t or nil): if
t(the default), write the commands to the app's history. (this needs
cl-readlinesuperior to may, 2018)
*help-preamble*: text to display at the beginning of the help.
*help-postamble*: text to display last.
- print colored output from markdown or code with pygments:
(format-markdown txt :lang "md"). It outputs text for a console display with ansi colours. Needs pygments, or does nothing.
For example, you can change the completion behavior. This:
inserts the first completion candidate, even if there are many, instead of showing the list of choices under the prompt.
If you prefer vi mode:
set editing-mode vi
etc. See readline's documentation.
This is a generalization on
cl-readline. See also the simple cl-readline example. Once you've built two even basic readline apps you'll want to factorize the common parts.
We want to store a list of commands (functions, "verbs") and a list of variables (the ones to use with "set"). We want to read them from any Lisp file, hence we need to remember the package they come from. This mechanism is provided through an interface in
Clone this repo in QL's local projects (
Build the executable:
Develop and test interactively into the console
By starting a swank server in the (real) Lisp repl we can compile code in our editor and try instantly in the terminal, without re-building the executable. See this cl-charms crash course for now. Some details need fixing.