diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-11-03 20:56:47 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-11-03 20:56:47 -0700 |
commit | 7ccd643ac222d3da563b386cef5caf7af1b79363 (patch) | |
tree | f370b15e162259da08afe318777f034ae5dff72e | |
parent | 935f58e8941f03590bbd5c8482a31b50cf233802 (diff) | |
download | txr-7ccd643ac222d3da563b386cef5caf7af1b79363.tar.gz txr-7ccd643ac222d3da563b386cef5caf7af1b79363.tar.bz2 txr-7ccd643ac222d3da563b386cef5caf7af1b79363.zip |
Support simple list arguments in getopts.
* share/txr/stdlib/getopts.tl (defstruct sys:opt-parsed): New
slot eff-type, appearing as an optional parameter in the boa
constructor parameter list.
(opt-desc check): Allow a type to be a cons with list
in the car position.
(sys:opt-parsed convert-type): Use the eff-type slot
if it is set instead of the type from the descriptor.
This lets us override the type for a slot, which is
key to the recursive approach to how lists are handled
in this same function.
(opthelp): Show list type options in a visual way
which suggests the use. No details are given.
* txr.1: Documented list option type.
-rw-r--r-- | share/txr/stdlib/getopts.tl | 35 | ||||
-rw-r--r-- | txr.1 | 15 |
2 files changed, 40 insertions, 10 deletions
diff --git a/share/txr/stdlib/getopts.tl b/share/txr/stdlib/getopts.tl index f5909873..c0159e93 100644 --- a/share/txr/stdlib/getopts.tl +++ b/share/txr/stdlib/getopts.tl @@ -37,10 +37,11 @@ me.(check) (set me.arg-p (neq me.type :bool)))) -(defstruct (sys:opt-parsed name arg desc) nil +(defstruct (sys:opt-parsed name arg desc : eff-type) nil name arg ;; string, integer, real, ... desc ;; opt-desc + eff-type (:postinit (me) me.(convert-type))) (defstruct opts nil @@ -64,6 +65,7 @@ (defmeth opt-desc check (me) (unless (or (functionp me.type) (fboundp me.type) + (and (consp me.type) (eq (car me.type) 'list)) (member me.type me.valid-types)) (error "getopts: type must be a function or valid keyword, not ~s" me.type)) @@ -79,11 +81,12 @@ (error "getopts: short option ~a starts with - character" me.short)))) (defmeth sys:opt-parsed convert-type (me) - (let ((name (sys:opt-dash me.name))) - (when (and (neq me.desc.type :bool) + (let ((name (sys:opt-dash me.name)) + (type (or me.eff-type me.desc.type))) + (when (and (neq type :bool) (eq me.arg :explicit-no)) (sys:opt-err "Non-Boolean option ~a explicitly specified as false" name)) - (caseql me.desc.type + (caseql type (:bool (set me.arg (neq me.arg :explicit-no))) (:dec (set me.arg @@ -122,7 +125,17 @@ (or (ignerr (read `"@{me.arg}"`)) (sys:opt-err "option ~a needs string lit syntax, ~a given" name me.arg)))) - (t (set me.arg (call me.desc.type me.arg)))))) + (t (cond + ((and (consp type) (eq (car type) 'list)) + (let* ((rec-type (cadr type)) + (pieces (split-str me.arg #/,/)) + (sub-opts (mapcar (do new (sys:opt-parsed me.name @1 + me.desc + rec-type)) + pieces))) + (set me.arg (mapcar (usl arg) sub-opts)))) + ((or (symbolp me.type) (functionp me.type)) + (set me.arg (call me.desc.type me.arg)))))))) (defmeth opts lambda (me key : dfl) (iflet ((o [me.opt-hash key])) o.arg dfl)) @@ -230,9 +243,12 @@ (undocumented (keep-if (op null @1.helptext) opt-desc-list))) (put-line "\nOptions:\n") (each ((od sorted)) - (let* ((type (if (keywordp od.type) - (upcase-str (tostringp od.type)) - "ARG")) + (let* ((type (cond + ((keywordp od.type) (upcase-str (tostringp od.type))) + ((and (consp od.type) (eq (car od.type) 'list)) + (let ((ts (upcase-str (tostringp (cadr od.type))))) + `@ts[,@ts...]`)) + (t "ARG"))) (long (if od.long `--@{od.long}@(if od.arg-p `=@type`)`)) (short (if od.short @@ -301,7 +317,8 @@ (mapdo (do put-line ` @1`) (sys:wdwrap `@{(flatten texts)}` 77))) (put-line) - (whenlet ((types (remq :bool (uniq (mapcar (usl type) sorted))))) + (whenlet ((types (keep-if [andf keywordp (op neq :bool)] + (uniq (mapcar (usl type) sorted))))) (put-line "Type legend:\n") (each ((ty types)) (iflet ((ln (caseql ty @@ -41538,12 +41538,25 @@ or .code E followed by a decimal integer which may have a leading positive or negative sign, and include leading zeros. - .coIP :str This type indicates that the argument consists of the interior notation of a TXR Lisp character string. It is processed by adding a double quote at the beginning or end, and parsed as a string literal. This parsing must successfully yield a string object, otherwise the argument is ill-formed. +.meIP (list << type ) +If the type is specified as a compound form headed by the +.code list +symbol, it indicates that the command line option's argument is a list +of elements. The argument appears on the command line as a single string +contained within one argument. It may contain commas, and is split into pieces +using the comma character as a separator. The pieces are then individually +treated as of type +.meta type +and converted accordingly. The option's argument is then a list object +whose elements are the converted pieces. For instance +.code "(list :dec)" +will convert a list of comma-separated decimal integer tokens into +a list of integer objects. .RE .PP |