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-c
, 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
cl-readline
.
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:
You can 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: ./replic
,
or build it yourself.
- the library is on Quicklisp (since the 2019-01-07 dist) and on Ultralisp:
(ql:quickload :replic)
or clone this repo into ~/quicklisp/local-projects/
,
then build the executable with make build
.
__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.
Run it:
replic -h
./replic
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).
Given the example ~/.replic.lisp
below, you can
try hello <name>
(completion for hello
) and goodbye <name>
,
where <name> can be completed from what was given to hello
.
(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.
Write a function or a variable and export
it.
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* ... If true, print debugging information during the program execution.
Write a preamble and a postamble in *help-preamble*
and *help-postamble*
.
You can read the help of a specific command or variable (with completion):
help help
The general help
shows the first paragraph of the
functions/parameters docstring, the help <cmd>
function is more
complete and shows all of it.
set
can be used with zero, one or two arguments:
set
shows all available variables,
set *variable*
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 (~/.replic.conf
).
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.
replic
is in Quicklisp (2019-01-07):
(ql:quickload :replic)
Follow the documentation below, and see example applications on the wiki.
You can change the prompt. It defaults to “> “. It can contain ansi colors.
(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 (replic:prompt)
.
If you want to have the base commands (help
, reload
, set
,
quit
), import the base package:
(replic.completion:functions-to-commands :replic.base)
This is the core of the library.
Create the commands you’ll find at the readline prompt from the exported functions and variables of a given package:
(replic.completion:functions-to-commands :my-package)
To exclude functions, use the :exclude
list:
(replic.completion:functions-to-commands :my-package :exclude '("main"))
For more control, you can create a command from one given function:
(replic.completion:add-command :function :package)
;; add a variable:
(replic.completion:add-variable :*variable* :package)
It is generally a good idea to have a package for the lisp functions you’ll use at the repl, and another package for the ones that must be commands at the readline interface.
A lisp function from a library usually returns some result and doesn’t
necessarily print it. If you want replic
to automatically print it,
ask it like so:
(replic:autoprint-results-from :my-package :exclude '("exclude" "those-functions"))
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):
(replic.config:apply-config :replic)
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
: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:
(replic: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*
-> foo
). Lispers shall use a lispy config
file anyway.
The available variables are:
*verbose*
(bool): if true, print debugging information during the program execution.*confirm-exit*
(bool): if true (the default), ask for confirmation when a user tries to exit the program with aC-d
(EOF).*prompt*
(str): the readline prompt. Defaults to simply>
. Can contain ansi colours (usecl-ansi-text:green
for example).*confirm-exit*
(t or nil): ift
(the default), ask for confirmation when the user tries to exit the command line with aC-d
(EOF).*write-history*
(t or nil): ift
(the default), write the commands to the app’s history. (this needscl-readline
superior 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.
The GNU Readline library provides settings you might take advantage
of. We can set the settings in the readline init file (~/.inputrc
by
default, obeys the INPUTRC
environment variable).
For example, you can change the completion behavior. This:
TAB: menu-complete
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 completion.lisp
.
Clone this repo in QL’s local projects (~/quicklisp/local-projects
).
Build the executable:
make build
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.
- v0.11 (end of june, 2019)
- added a declarative way to automatically print a function’s result
- fixed: a quoted string on the readline prompt is now understood as one single argument.
Learning:
Getting started: