Here are some bits of Lisp code which might help you if you are using a specific implementation, or an interface from Emacs to Lisp.
LispWorks, like other Lisp systems, has a top level
`listener' in which, as well as Lisp forms being
evaluated, certain `commands' can be issued. In common with
Franz' Allegro CL, it distinguishes these commands by looking
for lines that begin with a keyword: :a will cause
the debugger to select the `abort' restart for instance.
Unlike Allegro, there's no documented way of defining such commands. However after poking around (and asking people) it turns out that it is possible to intervene in the system in such a way as to define new commands. This is fairly grotty code which relies on LW internal functionality, and I'm hoping that a more documented interface will appear at some point. It doesn't let you get at the various `contexts' - such as `in the debugger', `in the listener' that LW has, but just provides the commands in all contexts.
The code supports a fairly simple interface.The function that
implements a new command has a lambda list of (cmd
&rest args), where cmd is the command
keyword - so the same function can handle many commands. The
function is responsible for destructuring the remaining
arguments itself & should check argument count and types.
Here is an example function (from the code) which deals with
compiling and loading files.
(defvar *file-command-default-files '())
(defun file-command (cmd &rest args)
(let ((files (if args
(setf *file-command-default-files args)
*file-command-default-files)))
(case cmd
((:ld)
(dolist (f files (values))
(load f)))
((:cf)
(dolist (f files (values))
(compile-file f)))
((:cl)
(dolist (f files (values))
(let ((cp (compile-file-pathname f))
(sp (merge-pathnames f #.(make-pathname :type "lisp"))))
(when (or (not (probe-file cp))
(< (file-write-date cp) (file-write-date sp)))
(compile-file f))
(load cp))))
(otherwise
(warn "Unknown file command ~S" cmd)
(values)))))
Once the function is defined, then the macro
declare-extra-lw-commands is used to tell the system
which commands correspond to this function, and to provide
documentation for them:
(declare-extra-lw-commands (:ld file-command "Load a file") (:cf file-command "Compile a file") (:cl file-command "Compile a file and load it"))
Here, each form in the body of the macro should be a triple of command (a keyword), function-name and documentation string. It is safe to evaluate the same macro multiple times: things get redefined suitably.
Once all this is done, then the new commands will be
available. There is a slight subtelty in that they are in general
only available the next time a top-level loop is started,
although in practice they often become available immediately
(because *extra-lw-commands* gets modified
destructively, and if there are no commands provided by LW
itself then this destructive modification is seen by the
top-loop).
The way the arguments to commands get read is slightly different to ACL - they are read by the normal Lisp reader, so if you want to pass a string to quote it:
CL-USER 8 > :cl "~/work/lw/tdb/tdb.lisp"
; Loading fasl file D:\home\tfb\work\lw\tdb\tdb.fsl
| Copyright | lw-commands.lisp
is copyright 2002 by me, Tim Bradshaw, and may be used for
any purpose whatsoever by anyone. It has no warranty
whatsoever. I would appreciate acknowledgement if you use
it in anger, and I would also very much appreciate any
feedback or bug fixes. |
|---|---|
| Here | is the current version. |
| Please mail me | with any bugs or comments. |