--- a/adopt/index.html Thu Mar 07 12:47:45 2019 -0500
+++ b/adopt/index.html Wed Apr 17 10:30:37 2019 -0400
@@ -12,18 +12,25 @@
<div class="wrap">
<header><h1><a href="">Adopt</a></h1></header>
<div class="markdown">
-<p>I needed <strong>A</strong> <strong>D</strong>amn <strong>OPT</strong>ion parsing library.</p>
-<p>Adopt is a simple (~150 LOC) UNIX-style option parser in Common Lisp.
-It depends on <a href="https://github.com/sjl/bobbin">Bobbin</a> and <a href="https://www.cliki.net/split-sequence">split-sequence</a>.</p>
-<p>It aims to be simple and powerful enough for the majority of use cases.</p>
+<p>I needed <strong>a</strong> <strong>d</strong>amn <strong>opt</strong>ion parsing library.</p>
+<p>Adopt is a simple UNIX-style option parser in Common Lisp, heavily influenced by
+Python's optparse and argparse.</p>
<ul>
<li><strong>License:</strong> MIT</li>
<li><strong>Documentation:</strong> <a href="https://sjl.bitbucket.io/adopt/">https://sjl.bitbucket.io/adopt/</a></li>
<li><strong>Mercurial:</strong> <a href="https://bitbucket.org/sjl/adopt/">https://bitbucket.org/sjl/adopt/</a></li>
<li><strong>Git:</strong> <a href="https://github.com/sjl/adopt/">https://github.com/sjl/adopt/</a></li>
</ul>
+<p>Adopt aims to be a simple, robust option parser. It can automatically print
+help information and even generate <code>man</code> pages for you.</p>
<p>The test suite currently passes in SBCL, CCL, ECL, and ABCL on Ubuntu. Further
-testing is welcome.</p><h2>Table of Contents</h2><ol class="toc"><li><a href="installation/">Installation</a></li><li><a href="usage/">Usage</a></li><li><a href="reference/"> API Reference</a></li><li><a href="changelog/">Changelog</a></li></ol>
+testing is welcome.</p>
+<p>Adopt is compatible with Quicklisp, but not <em>in</em> Quicklisp (yet). You can clone
+the repository into your <a href="https://www.quicklisp.org/beta/faq.html#local-project">Quicklisp local-projects directory</a> for now.</p>
+<p>The <code>adopt</code> system contains the core API and depends on <a href="https://github.com/sjl/bobbin">Bobbin</a> and
+<a href="https://www.cliki.net/split-sequence">split-sequence</a>.</p>
+<p>The <code>adopt/test</code> system contains the test suite, which depends on some other
+systems. You don't need to load this unless you want to run the unit tests.</p><h2>Table of Contents</h2><ol class="toc"><li><a href="usage/">Usage</a></li><li><a href="reference/"> API Reference</a></li><li><a href="changelog/">Changelog</a></li></ol>
</div>
<footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a>.</i></p>
<p><a href="http://rochestermade.com" title="Rochester Made"><img src="http://rochestermade.com/media/images/rochester-made-dark-on-light.png" alt="Rochester Made" title="Rochester Made" /></a></p>
--- a/adopt/reference/index.html Thu Mar 07 12:47:45 2019 -0500
+++ b/adopt/reference/index.html Wed Apr 17 10:30:37 2019 -0400
@@ -20,26 +20,32 @@
<div class="toc">
<ul>
<li><a href="#package-adopt">Package ADOPT</a><ul>
-<li><a href="#append1-function">APPEND1 (function)</a></li>
<li><a href="#argv-function">ARGV (function)</a></li>
-<li><a href="#define-interface-macro">DEFINE-INTERFACE (macro)</a></li>
-<li><a href="#latest-function">LATEST (function)</a></li>
+<li><a href="#collect-function">COLLECT (function)</a></li>
+<li><a href="#define-string-macro">DEFINE-STRING (macro)</a></li>
+<li><a href="#discard-option-function">DISCARD-OPTION (function)</a></li>
+<li><a href="#exit-function">EXIT (function)</a></li>
+<li><a href="#first-function">FIRST (function)</a></li>
+<li><a href="#flip-function">FLIP (function)</a></li>
+<li><a href="#last-function">LAST (function)</a></li>
+<li><a href="#make-group-function">MAKE-GROUP (function)</a></li>
+<li><a href="#make-interface-function">MAKE-INTERFACE (function)</a></li>
+<li><a href="#make-option-function">MAKE-OPTION (function)</a></li>
<li><a href="#parse-options-function">PARSE-OPTIONS (function)</a></li>
-<li><a href="#print-usage-function">PRINT-USAGE (function)</a></li>
+<li><a href="#print-error-and-exit-function">PRINT-ERROR-AND-EXIT (function)</a></li>
+<li><a href="#print-help-function">PRINT-HELP (function)</a></li>
+<li><a href="#print-help-and-exit-function">PRINT-HELP-AND-EXIT (function)</a></li>
+<li><a href="#print-manual-function">PRINT-MANUAL (function)</a></li>
+<li><a href="#supply-new-value-function">SUPPLY-NEW-VALUE (function)</a></li>
+<li><a href="#treat-as-argument-function">TREAT-AS-ARGUMENT (function)</a></li>
+<li><a href="#unrecognized-option-class">UNRECOGNIZED-OPTION (class)</a><ul>
+<li><a href="#slot-problematic-option">Slot PROBLEMATIC-OPTION</a></li>
+</ul>
+</li>
</ul>
</li>
</ul></div>
<h2 id="package-adopt">Package <code>ADOPT</code></h2>
-<h3 id="append1-function"><code>APPEND1</code> (function)</h3>
-<div class="codehilite"><pre><span/>(APPEND1 LIST EL)
-</pre></div>
-
-
-<p>Append element <code>el</code> to the end of <code>list</code>.</p>
-<p>This is implemented as <code>(append list (list el))</code>. It is not particularly
- fast.</p>
-<p>It is useful as a <code>:reduce</code> function when you want to collect all values given
- for an option.</p>
<h3 id="argv-function"><code>ARGV</code> (function)</h3>
<div class="codehilite"><pre><span/>(ARGV)
</pre></div>
@@ -47,23 +53,92 @@
<p>Return a list of the program name and command line arguments.</p>
<p>This is not implemented for every Common Lisp implementation. You can always
- pass your own values to <code>parse-options</code> and <code>print-usage</code> if it's not
+ pass your own values to <code>parse-options</code> and <code>print-help</code> if it's not
implemented for your particular Lisp.</p>
-<h3 id="define-interface-macro"><code>DEFINE-INTERFACE</code> (macro)</h3>
-<div class="codehilite"><pre><span/>(DEFINE-INTERFACE NAME USAGE &amp;REST OPTIONS)
+<h3 id="collect-function"><code>COLLECT</code> (function)</h3>
+<div class="codehilite"><pre><span/>(COLLECT LIST EL)
+</pre></div>
+
+
+<p>Append element <code>el</code> to the end of <code>list</code>.</p>
+<p>It is useful as a <code>:reduce</code> function when you want to collect all values given
+ for an option.</p>
+<p>This is implemented as <code>(append list (list el))</code>. It is not particularly
+ fast. If you can live with reversed output consider <code>(flip #'cons)</code> instead.</p>
+<h3 id="define-string-macro"><code>DEFINE-STRING</code> (macro)</h3>
+<div class="codehilite"><pre><span/>(DEFINE-STRING VAR STRING &REST ARGS)
+</pre></div>
+
+
+<p>Convenience macro for <code>(defparameter ,var (format nil ,string ,@args))</code>.</p>
+<h3 id="discard-option-function"><code>DISCARD-OPTION</code> (function)</h3>
+<div class="codehilite"><pre><span/>(DISCARD-OPTION CONDITION)
+</pre></div>
+
+
+<p>Invoke the <code>discard-option</code> restart properly.</p>
+<p>Example:</p>
+<div class="codehilite"><pre><span/>(handler-bind ((unrecognized-option 'discard-option))
+ (multiple-value-bind (arguments options) (parse-options *ui*)
+ (run arguments options)))
</pre></div>
-<h3 id="latest-function"><code>LATEST</code> (function)</h3>
-<div class="codehilite"><pre><span/>(LATEST OLD NEW)
+<h3 id="exit-function"><code>EXIT</code> (function)</h3>
+<div class="codehilite"><pre><span/>(EXIT &OPTIONAL (CODE 0))
+</pre></div>
+
+
+<h3 id="first-function"><code>FIRST</code> (function)</h3>
+<div class="codehilite"><pre><span/>(FIRST OLD NEW)
+</pre></div>
+
+
+<p>Return <code>new</code> if <code>old</code> is <code>nil</code>, otherwise return <code>old</code>.</p>
+<p>It is useful as a <code>:reduce</code> function when you want to just keep the
+ first-given value for an option.</p>
+<h3 id="flip-function"><code>FLIP</code> (function)</h3>
+<div class="codehilite"><pre><span/>(FLIP FUNCTION)
+</pre></div>
+
+
+<p>Return a function of two arguments X and Y that calls <code>function</code> with Y and X.</p>
+<p>Useful for wrapping existing functions that expect their arguments in the
+ opposite order.</p>
+<p>Examples:</p>
+<div class="codehilite"><pre><span/>(funcall #'cons 1 2) ; => (1 . 2)
+(funcall (flip #'cons) 1 2) ; => (2 . 1)
+(reduce (flip #'cons) '(1 2 3) :initial-value nil)
+; => (3 2 1)
+</pre></div>
+
+
+<h3 id="last-function"><code>LAST</code> (function)</h3>
+<div class="codehilite"><pre><span/>(LAST OLD NEW)
</pre></div>
<p>Return <code>new</code>.</p>
<p>It is useful as a <code>:reduce</code> function when you want to just keep the last-given
value for an option.</p>
+<h3 id="make-group-function"><code>MAKE-GROUP</code> (function)</h3>
+<div class="codehilite"><pre><span/>(MAKE-GROUP NAME &KEY TITLE HELP MANUAL OPTIONS)
+</pre></div>
+
+
+<h3 id="make-interface-function"><code>MAKE-INTERFACE</code> (function)</h3>
+<div class="codehilite"><pre><span/>(MAKE-INTERFACE &KEY NAME SUMMARY USAGE HELP MANUAL EXAMPLES CONTENTS)
+</pre></div>
+
+
+<h3 id="make-option-function"><code>MAKE-OPTION</code> (function)</h3>
+<div class="codehilite"><pre><span/>(MAKE-OPTION NAME &KEY LONG SHORT HELP MANUAL PARAMETER REDUCE (RESULT-KEY NAME)
+ (INITIAL-VALUE NIL INITIAL-VALUE?) (KEY #'IDENTITY) (FINALLY #'IDENTITY))
+</pre></div>
+
+
<h3 id="parse-options-function"><code>PARSE-OPTIONS</code> (function)</h3>
-<div class="codehilite"><pre><span/>(PARSE-OPTIONS INTERFACE &amp;OPTIONAL (ARGUMENTS (REST (ARGV))))
+<div class="codehilite"><pre><span/>(PARSE-OPTIONS INTERFACE &OPTIONAL (ARGUMENTS (REST (ARGV))))
</pre></div>
@@ -72,29 +147,49 @@
<ol>
<li>A fresh list of top-level, unaccounted-for arguments that don't correspond
to any options defined in <code>interface</code>.</li>
-<li>An <code>EQL</code> hash map of option <code>name</code>s to values.</li>
+<li>An <code>EQL</code> hash table of option keys to values.</li>
</ol>
-<p>See the full usage documentation for more information.</p>
-<h3 id="print-usage-function"><code>PRINT-USAGE</code> (function)</h3>
-<div class="codehilite"><pre><span/>(PRINT-USAGE INTERFACE &amp;KEY (STREAM *STANDARD-OUTPUT*) (PROGRAM-NAME (FIRST (ARGV))) (WIDTH 80) (OPTION-WIDTH 20))
+<p>See the full documentation for more information.</p>
+<h3 id="print-error-and-exit-function"><code>PRINT-ERROR-AND-EXIT</code> (function)</h3>
+<div class="codehilite"><pre><span/>(PRINT-ERROR-AND-EXIT ERROR &KEY (STREAM *ERROR-OUTPUT*) (EXIT-CODE 1) (PREFIX error: ))
</pre></div>
-<p>Print a pretty usage document for <code>interface</code> to <code>stream</code>.</p>
+<p>Print <code>prefix</code> and <code>error</code> to <code>stream</code> and exit.</p>
+<p>Example:</p>
+<div class="codehilite"><pre><span/>(handler-case
+ (multiple-value-bind (arguments options) (parse-options *ui*)
+ (run arguments options))
+ (unrecognized-option (c)
+ (print-error-and-exit c)))
+</pre></div>
+
+
+<h3 id="print-help-function"><code>PRINT-HELP</code> (function)</h3>
+<div class="codehilite"><pre><span/>(PRINT-HELP INTERFACE &KEY (STREAM *STANDARD-OUTPUT*) (PROGRAM-NAME (CAR (ARGV))) (WIDTH 80)
+ (OPTION-WIDTH 20) (INCLUDE-EXAMPLES T))
+</pre></div>
+
+
+<p>Print a pretty help document for <code>interface</code> to <code>stream</code>.</p>
<p><code>width</code> should be the total width (in characters) for line-wrapping purposes.
Care will be taken to ensure lines are no longer than this, though some edge
cases (extremely long short/long option names and parameters) may slip
through.</p>
<p><code>option-width</code> should be the width of the column of short/long options (in
- characters). If the short/long option documentation is shorter than this, the
- option's documentation string will start on the same line. Otherwise the
- option's documentation string will start on the next line.</p>
-<p>The result will look something like (assuming a usage string of
- <code>"[options] FILES"</code>):</p>
-<div class="codehilite"><pre><span/>(print-usage *program-interface* :width 60 :option-width 15)
-; =&gt;
+ characters). If the short/long option help is shorter than this, the option's
+ help string will start on the same line. Otherwise the option's help string
+ will start on the next line.</p>
+<p>The result will look something like:</p>
+<div class="codehilite"><pre><span/>(print-help *program-interface* :width 60 :option-width 15)
+; =>
+; foo - do some things and meow
+;
; USAGE: /bin/foo [options] FILES
;
+; Foo is a program to frobulate some files, meowing as it
+; happens.
+;
; Options:
; -v, --verbose Output extra information.
; -q, --quiet Shut up.
@@ -107,6 +202,62 @@
; 0.........1.... option-width
; 0........1.........2.........3.........4.........5.........6
</pre></div>
+
+
+<h3 id="print-help-and-exit-function"><code>PRINT-HELP-AND-EXIT</code> (function)</h3>
+<div class="codehilite"><pre><span/>(PRINT-HELP-AND-EXIT INTERFACE &KEY (STREAM *STANDARD-OUTPUT*) (PROGRAM-NAME (CAR (ARGV)))
+ (WIDTH 80) (OPTION-WIDTH 20) (INCLUDE-EXAMPLES T) (EXIT-CODE 0))
+</pre></div>
+
+
+<p>Print a pretty help document for <code>interface</code> to <code>stream</code> and exit.</p>
+<p>Handy for easily providing --help:</p>
+<div class="codehilite"><pre><span/>(multiple-value-bind (arguments options) (parse-options *ui*)
+ (when (gethash 'help options)
+ (print-help-and-exit *ui*))
+ (run arguments options))
+</pre></div>
+
+
+<h3 id="print-manual-function"><code>PRINT-MANUAL</code> (function)</h3>
+<div class="codehilite"><pre><span/>(PRINT-MANUAL INTERFACE &KEY (STREAM *STANDARD-OUTPUT*) (MANUAL-SECTION 1))
+</pre></div>
+
+
+<h3 id="supply-new-value-function"><code>SUPPLY-NEW-VALUE</code> (function)</h3>
+<div class="codehilite"><pre><span/>(SUPPLY-NEW-VALUE CONDITION VALUE)
+</pre></div>
+
+
+<p>Invoke the <code>supply-new-value</code> restart properly.</p>
+<p>Example:</p>
+<div class="codehilite"><pre><span/>(handler-bind
+ ((unrecognized-option (alexandria:rcurry 'supply-new-value "--foo"))
+ (multiple-value-bind (arguments options) (parse-options *ui*)
+ (run arguments options)))
+</pre></div>
+
+
+<h3 id="treat-as-argument-function"><code>TREAT-AS-ARGUMENT</code> (function)</h3>
+<div class="codehilite"><pre><span/>(TREAT-AS-ARGUMENT CONDITION)
+</pre></div>
+
+
+<p>Invoke the <code>treat-as-argument</code> restart properly.</p>
+<p>Example:</p>
+<div class="codehilite"><pre><span/>(handler-bind ((unrecognized-option 'treat-as-argument))
+ (multiple-value-bind (arguments options) (parse-options *ui*)
+ (run arguments options)))
+</pre></div>
+
+
+<h3 id="unrecognized-option-class"><code>UNRECOGNIZED-OPTION</code> (class)</h3>
+<h4 id="slot-problematic-option">Slot <code>PROBLEMATIC-OPTION</code></h4>
+<ul>
+<li>Allocation: <code>:INSTANCE</code></li>
+<li>Initarg: <code>:PROBLEMATIC-OPTION</code></li>
+<li>Accessor: <code>PROBLEMATIC-OPTION</code></li>
+</ul>
</div>
<footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a>.</i></p>
<p><a href="http://rochestermade.com" title="Rochester Made"><img src="http://rochestermade.com/media/images/rochester-made-dark-on-light.png" alt="Rochester Made" title="Rochester Made"/></a></p>
--- a/adopt/usage/index.html Thu Mar 07 12:47:45 2019 -0500
+++ b/adopt/usage/index.html Wed Apr 17 10:30:37 2019 -0400
@@ -17,40 +17,310 @@
<div class="toc">
<ul>
<li><a href="#package">Package</a></li>
-<li><a href="#interfaces">Interfaces</a></li>
-<li><a href="#parsing">Parsing</a></li>
+<li><a href="#interfaces">Interfaces</a><ul>
+<li><a href="#creating-an-interface">Creating an Interface</a></li>
+<li><a href="#line-wrapping">Line Wrapping</a></li>
+<li><a href="#examples">Examples</a></li>
+</ul>
+</li>
+<li><a href="#exiting">Exiting</a></li>
<li><a href="#options">Options</a></li>
-<li><a href="#short-and-long-options">Short and Long Options</a></li>
-<li><a href="#initial-value">Initial Value</a></li>
-<li><a href="#reduce">Reduce</a></li>
-<li><a href="#usage-printing">Usage Printing</a></li>
+<li><a href="#parsing">Parsing</a></li>
+<li><a href="#top-level-structure">Top-Level Structure</a></li>
+<li><a href="#computing-values-with-reduce">Computing Values with Reduce</a></li>
</ul></div>
<h2 id="package">Package</h2>
-<p>All core Adopt functions and macros are in the <code>adopt</code> package. You can <code>:use</code>
-that if you really want to, but it's probably clearer to use namespaced
-<code>adopt:…</code> symbols.</p>
+<p>All core Adopt functions are in the <code>adopt</code> package. Several of the symbols in
+adopt shadow those in the <code>common-lisp</code> package, so you should probably use
+namespaced <code>adopt:…</code> symbols instead of <code>USE</code>ing the package.</p>
<h2 id="interfaces">Interfaces</h2>
-<p>define-interface and usage. nothing else.</p>
-<h2 id="parsing">Parsing</h2>
-<p><code>parse-options</code> with a bare-bones interface.</p>
+<p>To get started with Adopt, you should create an interface with the
+<code>adopt:make-interface</code> function. This returns an object representing the
+command line interface presented to your users.</p>
+<h3 id="creating-an-interface">Creating an Interface</h3>
+<p>Let's say you're developing a program to search the contents of files (because
+the world certainly needs <em>another</em> <code>grep</code> replacement). You might start with
+something like:</p>
+<div class="codehilite"><pre><span/>(defparameter *ui*
+ (adopt:make-interface
+ :name "search"
+ :summary "search files for a regular expression"
+ :usage "[OPTIONS] PATTERN [FILE]..."
+ :help "Search the contents of each FILE for the regular expression PATTERN. If no files are specified, searches standard input instead."))
+</pre></div>
+
+
+<p>You can now print some help text for your CLI with <code>adopt:print-help</code>:</p>
+<div class="codehilite"><pre><span/>(adopt:print-help *ui*)
+; =>
+search - search files for a regular expression
+
+USAGE: … [OPTIONS] PATTERN [FILE]...
+
+Search the contents of each FILE for the regular expression PATTERN. If no
+files are specified, searches standard input instead.
+</pre></div>
+
+
+<h3 id="line-wrapping">Line Wrapping</h3>
+<p>Adopt will handle line-wrapping your help text, so you don't need to (and
+shouldn't) add extra line breaks when creating your interface. If you want to
+line break the text in your source code to fit nicely in your editor, remember
+that <code>adopt:make-interface</code> is just a function — you can use <code>format</code> (possibly
+with its <code>~Newline</code> directive) to preprocess the help text argument:</p>
+<div class="codehilite"><pre><span/>(defparameter *ui*
+ (adopt:make-interface
+ :name "search"
+ :summary "search files for a regular expression"
+ :usage "[OPTIONS] PATTERN [FILE]..."
+ :help (format nil "Search the contents of each FILE for ~
+ the regular expression PATTERN. If ~
+ no files are specified, searches ~
+ standard input instead.")))
+</pre></div>
+
+
+<p>Adopt's line-wrapping library [Bobbin][] will only ever <em>add</em> line breaks, never
+remove them, which means you can include breaks in the output if you want to
+have multiple paragraphs in your help text:</p>
+<div class="codehilite"><pre><span/>(defparameter *ui*
+ (adopt:make-interface
+ :name "search"
+ :summary "search files for a regular expression"
+ :usage "[OPTIONS] PATTERN [FILE]..."
+ :help (format nil
+ "Search the contents of each FILE for the regular expression PATTERN.~@
+ ~@
+ If no files are specified (or if - is given as a file name) standard input will be searched instead.")))
+</pre></div>
+
+
+<p>If you want to control the width of the help text lines when they are printed,
+<code>adopt:print-help</code> takes a <code>:width</code> argument:</p>
+<div class="codehilite"><pre><span/>(adopt:print-help *ui* :width 50)
+; =>
+search - search files for a regular expression
+
+USAGE: … [OPTIONS] PATTERN [FILE]...
+
+Search the contents of each FILE for the regular
+expression PATTERN.
+
+If no files are specified (or if - is given as a
+file name) standard input will be searched
+instead.
+</pre></div>
+
+
+<p><code>adopt:print-help</code> takes a number of other options — see the API Reference for
+more information.</p>
+<h3 id="examples">Examples</h3>
+<p>Describing the CLI in detail is helpful, but users can often learn a lot more by
+seeing a few examples of its usage. <code>adopt:make-interface</code> can take an
+<code>:examples</code> argument, which should be an alist of <code>(description . example)</code>
+conses:</p>
+<div class="codehilite"><pre><span/>(defparameter *ui*
+ (adopt:make-interface
+ :name "search"
+ :summary "search files for a regular expression"
+ :usage "[OPTIONS] PATTERN [FILE]..."
+ :help …
+ :examples
+ '(("Search foo.txt for the string 'hello':"
+ . "search hello foo.txt")
+ ("Search standard input for lines starting with x:"
+ . "search '^x' -")
+ ("Watch the file log.txt for lines containing the username steve.losh:"
+ . "tail foo/bar/baz/log.txt | search --literal steve.losh -"))))
+
+(adopt:print-help *ui* :width 50)
+; =>
+search - search files for a regular expression
+
+USAGE: … [OPTIONS] PATTERN [FILE]...
+
+Search the contents of each FILE for the regular
+expression PATTERN.
+
+If no files are specified (or if - is given as a
+file name) standard input will be searched
+instead.
+
+Examples:
+
+ Search foo.txt for the string 'hello':
+
+ search hello foo.txt
+
+ Search standard input for lines starting with x:
+
+ search '^x' -
+
+ Watch the file log.txt for lines containing the
+ username steve.losh:
+
+ tail foo/bar/baz/log.txt | search --literal steve.losh -
+</pre></div>
+
+
+<p>Notice how Adopt line wraps the prose explaining each example, but leaves the
+example itself untouched for easier copying and pasting. In general Adopt tries
+to do the right thing for your users (even when that means making a little more
+work for <em>you</em> in certain places).</p>
+<h2 id="exiting">Exiting</h2>
+<p>Adopt provides some helpful utility functions to exit out of your program with
+a UNIX exit code. These do what you think they do:</p>
+<div class="codehilite"><pre><span/>(adopt:exit)
+
+(adopt:exit 1)
+
+(adopt:print-help-and-exit *ui*)
+
+(adopt:print-help-and-exit *ui*
+ :stream *error-output*
+ :exit-code 1)
+
+(handler-case (assert (= 1 0))
+ (error (err)
+ (adopt:print-error-and-exit err)))
+</pre></div>
+
+
+<p>These functions are not implemented for every Lisp implementation. PRs are
+welcome, or you can just write the implementation-specific calls in your program
+yourself.</p>
<h2 id="options">Options</h2>
-<p>talk about the option arguments.</p>
-<h2 id="short-and-long-options">Short and Long Options</h2>
-<p>short versus long arguments. 1+ is required.</p>
-<h2 id="initial-value">Initial Value</h2>
-<p>at this point it's just a default</p>
-<h2 id="reduce">Reduce</h2>
-<p>talk about reducers. mention argparse's:</p>
-<p><code>store_const</code> is <code>(constantly x)</code></p>
-<p><code>store</code> is <code>#'latest</code></p>
-<p><code>store_true</code> is <code>(constantly t)</code></p>
-<p><code>store_false</code> is <code>(constantly nil)</code></p>
-<p><code>append</code> is <code>append1</code></p>
-<p><code>append_const</code> is <code>(rcurry #'append1 x)</code></p>
-<p><code>count</code> is <code>1+</code> with an <code>initial-value</code> of <code>0</code>.</p>
-<p>need to figure out <code>help</code> and <code>version</code>.</p>
-<h2 id="usage-printing">Usage Printing</h2>
-<p>It's <code>(print-usage interface)</code>.</p>
+<p>Now that you know how to create an interface, you can create some options to use
+inside it with <code>adopt:make-option</code>:</p>
+<div class="codehilite"><pre><span/>(defparameter *option-version*
+ (adopt:make-option 'version
+ :long "version"
+ :help "display version information and exit"
+ :reduce (constantly t)))
+
+(defparameter *option-help*
+ (adopt:make-option 'help
+ :long "help"
+ :short #\h
+ :help "display help information and exit"
+ :reduce (constantly t)))
+
+(defparameter *option-literal*
+ (adopt:make-option 'literal
+ :long "literal"
+ :short #\l
+ :help "treat PATTERN as a literal string instead of a regular expression"
+ :reduce (constantly t)))
+
+(defparameter *ui*
+ (adopt:make-interface
+ :name "search"
+ :summary "search files for a regular expression"
+ :usage "[OPTIONS] PATTERN [FILE]..."
+ :help "Search the contents of …"
+ :contents (list
+ *option-version*
+ *option-help*
+ *option-literal*)))
+</pre></div>
+
+
+<p>Adopt will automatically add the options to the help text:</p>
+<div class="codehilite"><pre><span/>(adopt:print-help *ui*)
+; =>
+search - search files for a regular expression
+
+USAGE: /usr/local/bin/sbcl [OPTIONS] PATTERN [FILE]...
+
+Search the contents of …
+
+Options:
+ --version display version information and exit
+ -h, --help display help information and exit
+ -l, --literal treat PATTERN as a literal string instead of a regular
+ expression
+</pre></div>
+
+
+<p>The first argument to <code>adopt:make-option</code> is the name of the option, which we'll
+see put to use shortly. At least one of <code>:short</code> and <code>:long</code> is required, and
+<code>:help</code> text must be specified. We'll talk more about <code>:reduce</code> in a bit, but
+it too is required.</p>
+<p>I prefer to define each option as its own global variable to keep the call to
+<code>adopt:make-interface</code> from getting too large and unwieldy, but feel free to do
+something like this if you prefer to avoid cluttering your package:</p>
+<div class="codehilite"><pre><span/>(defparameter *ui*
+ (adopt:make-interface
+ …
+ :contents
+ (list (adopt:make-option 'foo …)
+ (adopt:make-option 'bar …)
+ …)))
+</pre></div>
+
+
+<h2 id="parsing">Parsing</h2>
+<p>At this point we've got an interface with some options, so we can use it to
+parse a list of strings we've received as command line arguments:</p>
+<div class="codehilite"><pre><span/>(adopt:parse-options *ui* '("foo.*" "--literal" "a.txt" "b.txt"))
+; =>
+("foo.*" "a.txt" "b.txt")
+#<HASH-TABLE :TEST EQL :COUNT 3 {10103142A3}>
+</pre></div>
+
+
+<p><code>adopt:parse-options</code> returns two values: a list of non-option arguments, and
+a hash table of the option values.</p>
+<p>The keys of the hash table are (by default) the option names given as the first
+argument to <code>adopt:make-option</code>. We'll see how the option values are determined
+soon.</p>
+<p>From now on I'll use a special pretty printer for hash tables to make it easier
+to see what's inside them:</p>
+<div class="codehilite"><pre><span/>(adopt:parse-options *ui* '("foo.*" "--literal" "a.txt" "b.txt"))
+; =>
+("foo.*" "a.txt" "b.txt")
+{LITERAL: T, VERSION: NIL, HELP: NIL}
+</pre></div>
+
+
+<h2 id="top-level-structure">Top-Level Structure</h2>
+<p>We'll look at how the option values are computed shortly, but first let's see
+the overall structure of the programs you create with Adopt:</p>
+<div class="codehilite"><pre><span/>(defun toplevel ()
+ (handler-case
+ (multiple-value-bind (arguments options)
+ (adopt:parse-options *ui*)
+ (when (gethash 'help options)
+ (adopt:print-help-and-exit *ui*))
+ (when (gethash 'version options)
+ (format t "1.0.0~%")
+ (adopt:exit))
+ (destructuring-bind (pattern . files) arguments
+ (run pattern
+ files
+ :literal (gethash 'literal options))))
+ (error (c)
+ (adopt:print-error-and-exit c))))
+
+(sb-ext:save-lisp-and-die "search" :toplevel #'toplevel)
+</pre></div>
+
+
+<p>The <code>toplevel</code> function first uses a <code>handler-case</code> to trap all <code>error</code>s. If
+any error occurs it will print the error message and exit, to avoid confusing
+users by dropping them into a Lisp debugger REPL (which they probably won't
+understand). When you're developing your program yourself you'll want to omit
+this part and let yourself land in the debugger as usual.</p>
+<p>Next we use <code>adopt:parse-options</code> to parse the command line arguments and
+options. We do some initial checks to see if the user wants <code>--help</code> or
+<code>--version</code> information. If not, we destructure the arguments into the items we
+expect and call a <code>run</code> function with all the information it needs to do its
+job.</p>
+<p>If the <code>destructuring-bind</code> fails an error will be signaled, and the
+<code>handler-case</code> will print it and exit. If you want to be a nice person you
+could check that the <code>arguments</code> have the correct shape first, and return
+a friendlier error message to your users if they don't.</p>
+<h2 id="computing-values-with-reduce">Computing Values with Reduce</h2>
</div>
<footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a>.</i></p>
<p><a href="http://rochestermade.com" title="Rochester Made"><img src="http://rochestermade.com/media/images/rochester-made-dark-on-light.png" alt="Rochester Made" title="Rochester Made"/></a></p>