--- a/Makefile Wed Nov 21 23:22:18 2018 -0500
+++ b/Makefile Thu Nov 22 00:03:53 2018 -0500
@@ -1,6 +1,9 @@
-.PHONY: test test-sbcl test-ccl test-ecl test-abcl
+.PHONY: test test-sbcl test-ccl test-ecl test-abcl pubdocs
heading_printer = $(shell which heading || echo 'true')
+sourcefiles = $(shell ffind --full-path --literal .lisp)
+docfiles = $(shell ls docs/*.markdown)
+apidocs = $(shell ls docs/*reference*.markdown)
# Testing ---------------------------------------------------------------------
test: test-sbcl test-ccl test-ecl test-abcl
@@ -20,3 +23,18 @@
test-abcl:
$(heading_printer) broadway 'ABCL'
abcl --load test/run.lisp
+
+# Documentation ---------------------------------------------------------------
+$(apidocs): $(sourcefiles)
+ sbcl --noinform --load docs/api.lisp --eval '(quit)'
+
+docs/build/index.html: $(docfiles) $(apidocs) docs/title
+ cd docs && ~/.virtualenvs/d/bin/d
+
+docs: docs/build/index.html
+
+pubdocs: docs
+ hg -R ~/src/sjl.bitbucket.org pull -u
+ rsync --delete -a ./docs/build/ ~/src/sjl.bitbucket.org/adopt
+ hg -R ~/src/sjl.bitbucket.org commit -Am 'adopt: Update site.'
+ hg -R ~/src/sjl.bitbucket.org push
--- a/README.markdown Wed Nov 21 23:22:18 2018 -0500
+++ b/README.markdown Thu Nov 22 00:03:53 2018 -0500
@@ -1,15 +1,18 @@
Adopt
=====
-I need **A** **D**amn **OPT**ion parsing library.
-
+I needed **A** **D**amn **OPT**ion parsing library.
-Adopt is a simple (~200 LOC) UNIX-style option parser in Common Lisp.
-It depends on `bobbin` and `split-sequence`.
+Adopt is a simple (~150 LOC) UNIX-style option parser in Common Lisp.
+It depends on [Bobbin][] and [split-sequence][].
-It aims to be simple and powerful enough for the majority of use cases.
+The test suite currently passes in SBCL, CCL, ECL, and ABCL on Debian. Further
+testing is welcome.
* **License:** MIT
* **Documentation:** <https://sjl.bitbucket.io/adopt/>
* **Mercurial:** <https://bitbucket.org/sjl/adopt/>
* **Git:** <https://github.com/sjl/adopt/>
+
+[Bobbin]: https://github.com/sjl/bobbin
+[split-sequence]: https://www.cliki.net/split-sequence
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/01-installation.markdown Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,17 @@
+Installation
+============
+
+Adopt is compatible with Quicklisp, but not *in* Quicklisp (yet?). You can
+clone the repository into your [Quicklisp local-projects directory][local] for
+now.
+
+The `adopt` system contains the core API and depends on [Bobbin][] and
+[split-sequence][].
+
+The `adopt.test` system contains the test suite, which uses depends on some
+other systems. You don't need to load this unless you want to run the unit
+tests.
+
+[local]: https://www.quicklisp.org/beta/faq.html#local-project
+[Bobbin]: https://github.com/sjl/bobbin
+[split-sequence]: https://www.cliki.net/split-sequence
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/02-usage.markdown Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,56 @@
+Usage
+=====
+
+Adopt is a simple library for parsing UNIX-style command line arguments in
+Common Lisp. It was made because none of the other libraries did what I needed.
+
+[TOC]
+
+Package
+-------
+
+All core Adopt functions are in the `adopt` package. You can `:use` that if you
+really want to, but it's probably clearer to use namespaced `adopt:…` symbols.
+
+Example
+-------
+
+ (define-interface *my-program* "[options] FILES"
+ (verbosity
+ "Output extra information."
+ :short #\v
+ :long "verbose"
+ :initial-value 0
+ :reduce (constantly 1))
+ (verbosity
+ "Shut up."
+ :short #\q
+ :long "quiet"
+ :reduce (constantly -1))
+ (ignore
+ "Ignore FILE. May be specified multiple times."
+ :long "ignore"
+ :parameter "FILE"
+ :reduce #'append1)
+ (name
+ "Your name. May be specified many times, last one wins."
+ :short #\n
+ :long "name"
+ :parameter "NAME"
+ :reduce #'latest)
+ (meows
+ "Meow."
+ :short #\m
+ :long "meow"
+ :initial-value 0
+ :reduce #'1+))
+
+ (pprint
+ (multiple-value-list
+ (parse-options *my-program*
+ '("-vqn" "steve"
+ "--meow"
+ "-m" "--meow" "foo"
+ "--name=sjl" "more"
+ "--" "--ignore" "bar"
+ ))))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/03-reference.markdown Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,108 @@
+# API Reference
+
+The following is a list of all user-facing parts of adopt.
+
+If there are backwards-incompatible changes to anything listed here, they will
+be noted in the changelog and the author will feel bad.
+
+Anything not listed here is subject to change at any time with no warning, so
+don't touch it.
+
+[TOC]
+
+## Package `ADOPT`
+
+### `APPEND1` (function)
+
+ (APPEND1 LIST EL)
+
+Append element `el` to the end of `list`.
+
+ This is implemented as `(append list (list el))`. It is not particularly
+ fast.
+
+ It is useful as a `:reduce` function when you want to collect all values given
+ for an option.
+
+
+
+### `ARGV` (function)
+
+ (ARGV)
+
+Return a list of the program name and command line arguments.
+
+ This is not implemented for every Common Lisp implementation. You can always
+ pass your own values to `parse-options` and `print-usage` if it's not
+ implemented for your particular Lisp.
+
+
+
+### `DEFINE-INTERFACE` (macro)
+
+ (DEFINE-INTERFACE NAME USAGE &REST OPTIONS)
+
+### `LATEST` (function)
+
+ (LATEST OLD NEW)
+
+Return `new`.
+
+ It is useful as a `:reduce` function when you want to just keep the last-given
+ value for an option.
+
+
+
+### `PARSE-OPTIONS` (function)
+
+ (PARSE-OPTIONS INTERFACE &OPTIONAL (ARGUMENTS (REST (ARGV))))
+
+Parse `arguments` according to `interface`.
+
+ Two values are returned:
+
+ 1. A fresh list of top-level, unaccounted-for arguments that don't correspond
+ to any options defined in `interface`.
+ 2. An `EQL` hash map of option `name`s to values.
+
+ See the full usage documentation for more information.
+
+
+
+### `PRINT-USAGE` (function)
+
+ (PRINT-USAGE INTERFACE &KEY (STREAM *STANDARD-OUTPUT*) (PROGRAM-NAME (FIRST (ARGV))) (WIDTH 80) (OPTION-WIDTH 20))
+
+Print a pretty usage document for `interface` to `stream`.
+
+ `width` 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.
+
+ `option-width` 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.
+
+ The result will look something like (assuming a usage string of
+ `"[options] FILES"`):
+
+ (print-usage *program-interface* :width 60 :option-width 15)
+ ; =>
+ ; USAGE: /bin/foo [options] FILES
+ ;
+ ; Options:
+ ; -v, --verbose Output extra information.
+ ; -q, --quiet Shut up.
+ ; --ignore FILE Ignore FILE. May be specified multiple
+ ; times.
+ ; -n NAME, --name NAME
+ ; Your name. May be specified many times,
+ ; last one wins.
+ ; -m, --meow Meow.
+ ; 0.........1.... option-width
+ ; 0........1.........2.........3.........4.........5.........6
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/04-changelog.markdown Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,11 @@
+Changelog
+=========
+
+Here's the list of changes in each released version.
+
+[TOC]
+
+Current Development Version
+---------------------------
+
+Adopt is still in active development. No promises yet.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/api.lisp Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,20 @@
+(ql:quickload "cl-d-api")
+
+(defparameter *header*
+ "The following is a list of all user-facing parts of adopt.
+
+If there are backwards-incompatible changes to anything listed here, they will
+be noted in the changelog and the author will feel bad.
+
+Anything not listed here is subject to change at any time with no warning, so
+don't touch it.
+
+")
+
+(d-api:generate-documentation
+ :adopt
+ #p"docs/03-reference.markdown"
+ (list "ADOPT")
+ *header*
+ :title "API Reference")
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/footer.markdown Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,14 @@
+<i>Made with Lisp and love by [Steve Losh][] in Rochester, New York.</i>
+
+[Steve Losh]: http://stevelosh.com/
+
+<script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-15328874-3', 'auto');
+ ga('send', 'pageview');
+
+</script>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/index.markdown Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,17 @@
+I needed **A** **D**amn **OPT**ion parsing library.
+
+Adopt is a simple (~150 LOC) UNIX-style option parser in Common Lisp.
+It depends on [Bobbin][] and [split-sequence][].
+
+It aims to be simple and powerful enough for the majority of use cases.
+
+* **License:** MIT
+* **Documentation:** <https://sjl.bitbucket.io/adopt/>
+* **Mercurial:** <https://bitbucket.org/sjl/adopt/>
+* **Git:** <https://github.com/sjl/adopt/>
+
+The test suite currently passes in SBCL, CCL, ECL, and ABCL on Debian. Further
+testing is welcome.
+
+[Bobbin]: https://github.com/sjl/bobbin
+[split-sequence]: https://www.cliki.net/split-sequence
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/title Thu Nov 22 00:03:53 2018 -0500
@@ -0,0 +1,1 @@
+Adopt
--- a/package.lisp Wed Nov 21 23:22:18 2018 -0500
+++ b/package.lisp Thu Nov 22 00:03:53 2018 -0500
@@ -1,3 +1,12 @@
(defpackage :adopt
(:use :cl)
- (:export :parse-options :print-usage :define-interface))
+ (:export
+ :parse-options
+ :print-usage
+ :define-interface
+
+ :argv
+
+ :latest
+ :append1
+ ))
--- a/src/main.lisp Wed Nov 21 23:22:18 2018 -0500
+++ b/src/main.lisp Thu Nov 22 00:03:53 2018 -0500
@@ -2,13 +2,36 @@
;;;; Utils --------------------------------------------------------------------
(defun append1 (list el)
+ "Append element `el` to the end of `list`.
+
+ This is implemented as `(append list (list el))`. It is not particularly
+ fast.
+
+ It is useful as a `:reduce` function when you want to collect all values given
+ for an option.
+
+ "
(append list (list el)))
(defun latest (old new)
+ "Return `new`.
+
+ It is useful as a `:reduce` function when you want to just keep the last-given
+ value for an option.
+
+ "
(declare (ignore old))
new)
+
(defun argv ()
+ "Return a list of the program name and command line arguments.
+
+ This is not implemented for every Common Lisp implementation. You can always
+ pass your own values to `parse-options` and `print-usage` if it's not
+ implemented for your particular Lisp.
+
+ "
#+sbcl sb-ext:*posix-argv*
#+ccl ccl:*unprocessed-command-line-arguments*
#-(or sbcl ccl) (error "ARGV is not supported on this implementation."))
@@ -126,6 +149,17 @@
(defun parse-options (interface &optional (arguments (rest (argv))))
+ "Parse `arguments` according to `interface`.
+
+ Two values are returned:
+
+ 1. A fresh list of top-level, unaccounted-for arguments that don't correspond
+ to any options defined in `interface`.
+ 2. An `EQL` hash map of option `name`s to values.
+
+ See the full usage documentation for more information.
+
+ "
(let ((toplevel nil)
(results (make-hash-table)))
(dolist (option (options interface))
@@ -212,20 +246,19 @@
(print-usage *program-interface* :width 60 :option-width 15)
; =>
- USAGE: /bin/foo [options] FILES
-
- Options:
- -v, --verbose Output extra information.
- -q, --quiet Shut up.
- --ignore FILE Ignore FILE. May be specified multiple
- times.
- -n NAME, --name NAME
- Your name. May be specified many times,
- last one wins.
- -m, --meow Meow.
-
- 0.........10... option-width
- 0........10........20........30........40........50........60 width
+ ; USAGE: /bin/foo [options] FILES
+ ;
+ ; Options:
+ ; -v, --verbose Output extra information.
+ ; -q, --quiet Shut up.
+ ; --ignore FILE Ignore FILE. May be specified multiple
+ ; times.
+ ; -n NAME, --name NAME
+ ; Your name. May be specified many times,
+ ; last one wins.
+ ; -m, --meow Meow.
+ ; 0.........1.... option-width
+ ; 0........1.........2.........3.........4.........5.........6
"
(assert (> width (+ 2 option-width 2)) (width option-width)
@@ -238,45 +271,3 @@
(doc-width (- width doc-column)))
(dolist (option (options interface))
(print-option-usage stream option option-column doc-column doc-width))))
-
-
-;;;; Scratch ------------------------------------------------------------------
-(define-interface *my-program* "[options] FILES"
- (verbosity
- "Output extra information."
- :short #\v
- :long "verbose"
- :initial-value 0
- :reduce (constantly 1))
- (verbosity
- "Shut up."
- :short #\q
- :long "quiet"
- :reduce (constantly -1))
- (ignore
- "Ignore FILE. May be specified multiple times."
- :long "ignore"
- :parameter "FILE"
- :reduce #'append1)
- (name
- "Your name. May be specified many times, last one wins."
- :short #\n
- :long "name"
- :parameter "NAME"
- :reduce #'latest)
- (meows
- "Meow."
- :short #\m
- :long "meow"
- :initial-value 0
- :reduce #'1+))
-
-(pprint
- (multiple-value-list
- (parse-options *my-program*
- '("-vqn" "steve"
- "--meow"
- "-m" "--meow" "foo"
- "--name=sjl" "more"
- "--" "--ignore" "bar"
- ))))