Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the adopt-subcommands Reference Manual, version 0.2.2, generated automatically by Declt version 3.0 "Montgomery Scott" on Sun May 15 03:14:48 2022 GMT+0.
• Introduction | What adopt-subcommands is all about | |
• Systems | The systems documentation | |
• Files | The files documentation | |
• Packages | The packages documentation | |
• Definitions | The symbols documentation | |
• Indexes | Concepts, functions, variables and data types |
#+TITLE: Adopt Subcommands #+AUTHOR: Eric TimmonsThis library is an extension of Steve Losh's [[https://docs.stevelosh.com/adopt/][Adopt]] library (hands down my favorite CLI options parser for CL) to support arbitrarily nested subcommands. Not all features of Adopt are nicely supported yet (like producing man pages for subcommands), but the basic functionality is there. Subcommands are organized into folders and terminals. Both folders and terminals can have options associated with them. Folders can additionally contain other folders and terminals. Terminals *must* have a function associated with them that will be called when a CLI command is dispatched. This function must accept three arguments: a list of arguments (strings), an =EQL= hash table of processed arguments, and a path object denoting all the folders and terminal traversed. Folders *may* have a function associated with them that is called before attempting to further process the remaining arguments. This is useful to bind dynamic variables or munge the options passed down to the later levels. This function, if provided, must take four arguments: a list of arguments (strings), an =EQL= hash table of options, a path object denoting all the folders and traversed so far, and a thunk that must be called to continue processing. This library tries to follow the same aesthetic as Adopt (such as interfaces encouraged to be defined with =defparameter= and errors signaled with some restarts provided) with two primary exceptions: 1. Any function you provide for terminals or folders is called with the results of processing the command line. You do not need to call =adopt:parse-options= or similar yourself. 2. Printing help and exiting is a common enough operation that this library provides native support for it, so you do not need to duplicate the checks for your program's help option everywhere. * How to use In this section, we describe how to use the library, partially illustrated by examples from [[file:simple-demo.lisp][=simple-demo.lisp=]] (see the History section for more details on the provenance of this file). First, you must define your program's hierarchy. Terminals are defined using =make-subcommand-terminal=. It accepts the same arguments as =adopt:make-interface=, with the addition of the mandatory =:function= and optional =:key= keywords. The provided function will be called once we dispatch based on the command line arguments. The key is used if you want to specify the name of the subcommand; it is normally not required as it is derived from =:name=. For example: #+begin_src common-lisp (defparameter *ui/foo* (adopt-subcommands:make-subcommand-terminal :name "subex foo" :usage "foo [-a|-b]" :summary "foo some things" :help "foo some things" :contents (list *o/foo/a* *o/foo/b*) :function 'run/foo)) #+end_src Folders are defined using =make-subcommand-folder=. It accepts the same arguments as =adopt:make-interface=, with the addition of the optional =:function= and =:key= keywords. If provided, the function will be called once we dispatch based on the command line arguments, before continuing to process the remainder of the arguments. It can be used to establish dynamic bindings or otherwise munge the arguments before continuing to process them. The key is used if you want to specify the name of the folder; it is normally not required as it is derived from =:name=. Additionally, the =:contents= of a folder can include other folders or terminals. For example: #+begin_src common-lisp (defparameter *ui* (adopt-subcommands:make-subcommand-folder :name "subex" :usage "[subcommand] [options]" :help "subcommand example program" :summary "an example program that uses subcommands" :contents (list *o/help* *o/version* *ui/foo* *ui/bar*) :function 'run/global)) #+end_src Next, you must actually process the arguments and call the desired functions. This is accomplished using the =dispatch= function. It requires a folder as an argument. It can additionally be provided the list of arguments. Last, if =print-help-and-exit= is non-NIL, it should name our program's help option. If provided, this library processes as much of the command line as it can. Then, if the help option is non-NIL, prints the help and exits the program. For example: #+begin_src common-lisp (defun toplevel () (handler-bind ((adopt-subcommands:folder-is-terminal 'adopt-subcommands:print-help-and-exit)) (adopt-subcommands:dispatch *ui* :print-help-and-exit 'help))) #+end_src * History This work was largely inspired by Steve Losh's [[https://old.reddit.com/r/Common_Lisp/comments/m7gjno/writing_small_cli_programs_in_common_lisp_steve/grdqq1j/][Reddit comment]] on a quick and dirty method to implement subcommands using Adopt. For a while, I had my own way of doing this (that also supported arbitrarily nested subcommands), but it was very nasty because I had somehow missed the existence of the =adopt:treat-as-argument= restart (d'oh). So after seeing that, I cleaned up my code and packaged it up as a library for others to use. For reference, the file =simple-demo.lisp= shows how to implement Steve's Reddit example using this library. * Deficiencies These are the current deficiencies that I would like to fix some day: 1. We reach into Adopt's internals a bit. Need to reach out to Steve and figure out if he's amenable to exporting the accessors we need and/or refactoring the help/man page generation to be more modular (and export the new components). 2. Man page generation is not yet supported. 3. Options need to come after the subcommand that defines them. For example, if =-a= is defined as part of =foo='s interface, the following will not work: #+begin_src shell my-program -a foo #+end_src But this will: #+begin_src shell my-program foo -a #+end_src This could be easily fixed for parameterless options. It could also be easily fixed for options with parameters, so long as the argument list has the parameter in the same token as the option (e.g. =--foo=5= instead of =--foo 5=). But a general purpose solution is harder and it is not obvious it's worth it.
Next: Files, Previous: Introduction, Up: Top [Contents][Index]
The main system appears first, followed by any subsystem dependency.
• The adopt-subcommands system |
Eric Timmons <eric@timmons.dev>
MIT
Extend the Adopt command line processing library to handle nested subcommands.
0.2.2
adopt-subcommands.asd (file)
adopt-subcommands.lisp (file)
Files are sorted by type and then listed depth-first from the systems components trees.
• Lisp files |
• The adopt-subcommands.asd file | ||
• The adopt-subcommands/adopt-subcommands.lisp file |
Next: The adopt-subcommands/adopt-subcommands․lisp file, Previous: Lisp files, Up: Lisp files [Contents][Index]
/home/quickref/quicklisp/dists/quicklisp/software/adopt-subcommands-v0.2.2/adopt-subcommands.asd
adopt-subcommands (system)
Previous: The adopt-subcommands․asd file, Up: Lisp files [Contents][Index]
adopt-subcommands (system)
adopt-subcommands.lisp
Next: Definitions, Previous: Files, Up: Top [Contents][Index]
Packages are listed by definition order.
• The adopt-subcommands package |
adopt-subcommands.lisp (file)
common-lisp
Definitions are sorted by export status, category, package, and then by lexicographic order.
• Exported definitions | ||
• Internal definitions |
Next: Internal definitions, Previous: Definitions, Up: Definitions [Contents][Index]
• Exported functions | ||
• Exported generic functions | ||
• Exported conditions |
Next: Exported generic functions, Previous: Exported definitions, Up: Exported definitions [Contents][Index]
Add a subcommand to a folder.
adopt-subcommands.lisp (file)
Given a subcommand UI (as returned by MAKE-SUBCOMMAND-FOLDER), dispatch
based on the provided ARGUMENTS.
If PRINT-HELP-AND-EXIT is provided, it must be a symbol denoting the option corresponding to your UI’s help flag. If provided and the help option is present in the command line, the help will be printed and the program will exit when a terminal node is reached.
adopt-subcommands.lisp (file)
Create and return a subcommand folder.
If this is placed into another folder, that folder uses ‘key‘ to determine when
to dispatch to this interface. If ‘key‘ is not specified, one is determined
automatically by splitting ‘name‘ on space characters and taking the last
entry.
When this subcommand is dispatched, ‘function‘ is called with a list of
remaining arguments, an ‘eql‘ hash table containing all the parsed options, a
path object representing all folders traversed (the path is currently only
useful for passing to the PRINT-HELP), and a thunk that continues processing
the subcommands when called. If not provided, the thunk is simply called.
The remaining arguments are passed directly to ‘adopt:make-interface‘.
adopt-subcommands.lisp (file)
Create and return a terminal subcommand interface.
The subcommand folder into which this is placed uses ‘key‘ to determine when to
dispatch to this interface. If ‘key‘ is not specified, one is determined
automatically by splitting ‘name‘ on space characters and taking the last
entry.
When this subcommand is dispatched, ‘function‘ is called with a list of remaining arguments, an ‘eql‘ hash table containing all the parsed options, and a path object representing all folders and terminal traversed (the path is currently only useful for passing to the PRINT-HELP). ‘function‘ is required.
The remaining arguments are passed directly to ‘adopt:make-interface‘.
adopt-subcommands.lisp (file)
Next: Exported conditions, Previous: Exported functions, Up: Exported definitions [Contents][Index]
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
A GF version of ADOPT:PRINT-HELP that additionally dispatches for the objects defined by this library.
adopt-subcommands.lisp (file)
A GF version of ADOPT:PRINT-HELP-AND-EXIT that additionally dispatches for
the objects defined by this library.
Additionally, we use UIOP:QUIT since that works on more implementations than ADOPT:EXIT.
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
Previous: Exported generic functions, Up: Exported definitions [Contents][Index]
Signals that no terminal subcommand was found
adopt-subcommands.lisp (file)
subcommand-error (condition)
:folder
folder-is-terminal-folder (generic function)
:path
folder-is-terminal-path (generic function)
Signals that a subcommand could not be found.
adopt-subcommands.lisp (file)
subcommand-error (condition)
:folder
unknown-subcommand-folder (generic function)
:key
unknown-subcommand-key (generic function)
:path
unknown-subcommand-path (generic function)
Previous: Exported definitions, Up: Definitions [Contents][Index]
• Internal functions | ||
• Internal generic functions | ||
• Internal conditions | ||
• Internal classes |
Next: Internal generic functions, Previous: Internal definitions, Up: Internal definitions [Contents][Index]
Copy a hash table
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
Return a list of all keys in HT.
adopt-subcommands.lisp (file)
Generate a key from NAME by splitting on space and returning the last element.
adopt-subcommands.lisp (file)
Return a copy of EXISTING-HT with all key/value pairs from NEW-HT inserted into it.
adopt-subcommands.lisp (file)
Return a new plist that contains all keys and values from PLIST, excepting any key in KEYS.
adopt-subcommands.lisp (file)
Print the options for an interface in a path.
This code is mostly copied from Adopt. See LICENSE for more information.
adopt-subcommands.lisp (file)
Print the help for PATH. Prints the examples and usage information for the
most specific interface on the path. Prints the options for all interfaces on
the path.
This code is mostly copied from Adopt. See LICENSE for more information.
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
Next: Internal conditions, Previous: Internal functions, Up: Internal definitions [Contents][Index]
automatically generated reader method
adopt-subcommands.lisp (file)
automatically generated writer method
adopt-subcommands.lisp (file)
adopt-subcommands.lisp (file)
automatically generated reader method
adopt-subcommands.lisp (file)
automatically generated writer method
adopt-subcommands.lisp (file)
automatically generated reader method
adopt-subcommands.lisp (file)
automatically generated writer method
adopt-subcommands.lisp (file)
automatically generated reader method
adopt-subcommands.lisp (file)
automatically generated writer method
adopt-subcommands.lisp (file)
automatically generated reader method
adopt-subcommands.lisp (file)
automatically generated writer method
adopt-subcommands.lisp (file)
Next: Internal classes, Previous: Internal generic functions, Up: Internal definitions [Contents][Index]
adopt-subcommands.lisp (file)
error (condition)
print-help-and-exit (method)
Previous: Internal conditions, Up: Internal definitions [Contents][Index]
adopt-subcommands.lisp (file)
standard-object (class)
:key
key (generic function)
(setf key) (generic function)
:function
%function (generic function)
(setf %function) (generic function)
:interface
interface (generic function)
(setf interface) (generic function)
adopt-subcommands.lisp (file)
subcommand (class)
(make-hash-table :test (quote equal))
subcommands (generic function)
(setf subcommands) (generic function)
adopt-subcommands.lisp (file)
standard-object (class)
:path
path (generic function)
(setf path) (generic function)
adopt-subcommands.lisp (file)
subcommand (class)
Previous: Definitions, Up: Top [Contents][Index]
• Concept index | ||
• Function index | ||
• Variable index | ||
• Data type index |
Next: Function index, Previous: Indexes, Up: Indexes [Contents][Index]
Jump to: | A F L |
---|
Jump to: | A F L |
---|
Next: Variable index, Previous: Concept index, Up: Indexes [Contents][Index]
Jump to: | %
(
A C D E F G H I K M P S U |
---|
Jump to: | %
(
A C D E F G H I K M P S U |
---|
Next: Data type index, Previous: Function index, Up: Indexes [Contents][Index]
Jump to: | F I K P S |
---|
Jump to: | F I K P S |
---|
Previous: Variable index, Up: Indexes [Contents][Index]
Jump to: | A C F P S U |
---|
Jump to: | A C F P S U |
---|