Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/aartaka/trivial-toplevel-commands

Common Lisp library to portably (un)define REPL toplevel commands.
https://github.com/aartaka/trivial-toplevel-commands

command compiler implementation lisp portability shell

Last synced: about 1 month ago
JSON representation

Common Lisp library to portably (un)define REPL toplevel commands.

Awesome Lists containing this project

README

        

#+TITLE:Trivial Toplevel Commands

Most CL implementations provide convenient toplevel commands, like
#+begin_src lisp
;; ECL command to load a Lisp file
:ld file.lisp
#+end_src

These commands tend to start with a colon and end with a newline,
possibly including space-separated arguments. Such commands are too
similar to not want a portable way to define them. Trivial Toplevel
Commands is such a portability layer. It allows to define and remove
toplevel commands on SBCL, CCL, ECL, ABCL, CLISP, and Allegro CL.

Couple of caveats:
- There are no toplevel commands on SBCL :: there are only debugger
commands. Trivial Toplevel Commands only defines debugger command to
not interfere with default SBCL REPL. If you want to access defined
commands, enter the debugger by signaling some condition (~(break)~,
at least) or contribute a more involved REPL to SBCL directly.
- You can also ~(require "sb-aclrepl")~ to enable an Allegro-like
REPL. Trivial Toplevel Commands supports it.
- CCL commands only accept evaluated arguments :: macro-like commands
are thus not possible. If you want to have maximum portability, only
use ~define-toplevel-command/eval~ or constant arguments. Contribute
a new REPL to CCL if you want to change that.
- ECL ~/read~ and ~/string~ commands remove a layer of quotes from strings :: I.e. ""hello"
hello" will be read as "hello hello". Plan accordingly. ~/eval~
commands are unaffected.
- Help with making it work on CLASP, CMUCL, and LispWorks :: I don't
have access to these implementations. Like, at all. Thanks.

* Getting Started
Clone the Git repository:
#+begin_src sh
git clone --recursive https://github.com/aartaka/trivial-toplevel-commands ~/common-lisp/
#+end_src

And then load ~:trivial-toplevel-commands~ in the REPL:
#+begin_src lisp
(asdf:load-system :trivial-toplevel-commands)
;; or, if you use Quicklisp
(ql:quickload :trivial-toplevel-commands)
#+end_src

You can also install Trivial Toplevel Commands via Guix, using the
bundled =guix.scm= file:
#+begin_src sh
guix package -f guix.scm
#+end_src

* Examples

A simple shell-invoking command mimicking [[https://github.com/ruricolist/cmd/][ruricolist/cmd]]. Obviously
quite primitive:
#+begin_src lisp
(tpl-cmds:define-command/eval (:cmd :!) (command)
"Shell invocation shortcut."
(uiop:launch-program command))

;; Used like:
:! "touch ~/cmd-test.txt"

;; With an apparent result
(uiop:file-exists-p #p"~/cmd-test.txt")
;; => #P"~/cmd-test.txt"
#+end_src

A much more involved command processing raw string argument, say, for your MP3 player setup:
#+begin_src lisp
(tpl-cmds:define-command/string (:list-mp3s :lm) (path)
"Recursively list all MP3 files in PATH, be it directory or file."
(labels ((ls (file)
(cond
((uiop:directory-pathname-p file)
(format t "~&Directory ~a..." file)
(mapc #'ls (uiop:subdirectories file))
(mapc #'ls (uiop:directory-files file)))
((equalp "mp3" (pathname-type file))
(format t "~&File ~a..." file)))))
(ls (uiop:merge-pathnames* (uiop:parse-native-namestring path) (uiop:getcwd)))))

;; Used like:
:list-mp3s /path/to/your/mp3/files
;; or
:lm /path/to/your/mp3/files

;; Directory ...
;; Directory ...
;; File ...
;; Directory ...
;; Directory ...
;; File ...
;; File ...
;; File ...
;; File ...
#+end_src

You can also undefine previously defined commands with ~remove-command~:
#+begin_src lisp
;; By alias:
(tpl-cmds:remove-command :lm)
;; Or by full name:
(tpl-cmds:remove-command :list-mp3s)
#+end_src

Most of the information for command is accessible too, via helper
functions:
- Command char for implementation (setf-able) :: ~command-char~.
- Command alias by name :: ~command-alias~.
- And vice versa :: ~command-name~.
- The handler function for the command :: ~command-handler~.
- Documentation for the command can be fetched with ~(documentation (command-handler :command) 'function)~.

You can also see the practical uses for commands [[https://github.com/aartaka/lisp-config/blob/master/commands.lisp][in my config]].

* Similar Libraries
- [[https://web.archive.org/web/20160826073800/http://heim.ifi.uio.no/~pok/download/commands.lisp][Peder Klingenberg's commands.lisp]] :: CMUCL-specific, could possibly
work on SBCL.
- [[https://web.archive.org/web/20170511215618/http://users.actrix.co.nz/mycroft/toplevel.tar.gz][Paul Foley's Toplevel]] :: CMUCL-specific.