Skip to content

Commit

Permalink
More docs and tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
fare committed Oct 28, 2023
1 parent dac8812 commit e9cd89e
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 14 deletions.
19 changes: 19 additions & 0 deletions doc/reference/std/cli/getopt.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,22 @@ e.g. with prototype objects like `gerbil-poo`.

TODO: add examples, discuss abort-on-error behavior,
lack of automatic help, etc.

### ->getopt-spec
```scheme
(->getopt-spec arg) => list-of-getopt-arguments
```
Given an argument `arg`, return a list *lst* of getopt arguments
to which one can `(apply getopt lst)` to specify a getopt object to parse with.

Default behavior:
- If `arg` is a list,
[`flatten`](../misc/list.md#flatten) it.
- If `arg` is a natural integer *n*,
specify a list of *n* positional `argument`s.
- If `arg` is `#f`, specify a single `rest-argument` named `rest`,
i.e. let it be a passthrough to be processed by the function being called.
- Otherwise, raise an error.

This function is useful for calls not just to `getopt` directly,
but also to `command` that itself calls `getopt`, etc.
101 changes: 99 additions & 2 deletions doc/reference/std/cli/multicall.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,114 @@ in gerbil-utils.
## Interface

### current-program
### entry-points
```scheme
(def current-program (make-parameter []))
```
A parameter that contains the name of the current program or subprogram,
as a list in reverse of the successive subcommands used to invoke it.

### current-program-string
```scheme
(def current-program (make-parameter []))
```
Return as a string of space-separated commands and subcommands in order
the name of the current program or subprogram.

### entry-points
```scheme
entry-points => table
```
A table, indexed by symbols, of `entry-point` structs,
describing the available shell entry points.

### entry-point
### getopt-spec
```scheme
(defstruct entry-point (name function help getopt) transparent: #t)
```
A struct type describing an available entry-point:
- `name` is a symbol, whose `symbol->string` is used as command or subcommand
to select the entry-point from the CLI.
- `function` is the Scheme function to call if the entry-point is selected.
- `help` is a short help string describing the purpose of the entry-point,
to be displayed to the user when help is requested.
- `getopt` is a `getopt-spec`
based on which the rest of the command-line will be parsed, and
based on which help about the available options is displayed.

### entry-points-getopt-spec
```scheme
(entry-points-getopt-spec [table])
```
Given a `table` of entry-points which default to the variable `entry-points`,
return a getopt-spec (suitable to be passed to `(apply getopt ...)`) of
`command` specifiers, one for each registered entry-point, in asciibetical order.

### register-entry-point
```scheme
(register-entry-point function
[id: #f] [name: #f] [help: #f] [getopt: #f])
```
Register the function as entry-point,
with given `name` (argument passed to `make-symbol`),
or if not specified, a symbol made of only the
[easy-shell-characters](shell.md#easy-shell-characters?) of `id`.
The entry-point will have the given `help` and `getopt` fields.

### define-entry-point
```scheme
(define-entry-point (id . formals) (options ...) body ...)
```
Syntax that expands to both
1. defining in the current scope function with the given name `id`
and specified Scheme function formals, and the given `body`.
2. register an entry-point for that function,
with given `id` and `options`.

### multicall-default
```scheme
multicall-default
```
A mutable variable that contains the default function to call
if the command doesn’t match any of the specified commands.

### set-default-entry-point!
```scheme
(set-default-entry-point! symbol)
```
Set the default entry-point in `multicall-default` as given `symbol`.

### help
```scheme
(help [command])
```
Global entry-point to print a help message (about the command, if specified)
about the current overall command and subcommands.

### meta
```scheme
(meta)
```
Global entry-point to print the available completions for the command,
for use with CLI syntax autodetection.

### version
```scheme
(version [all?: #f] [layer])
```
Global entry-point to print the current version.
If `all?` (flag `-a`) is passed, print all components from build manifest.
If `layer` (flag `-l`) is passed, print the thus-named component.

### call-entry-point
```scheme
(call-entry-point . args)
```
Call an entry point as specified by `args`,
or else the `multicall-default` entry point.

### define-multicall-main
```scheme
define-multicall-main
```
Define `call-entry-point` as a suitable `main` function
in the current scope.
11 changes: 10 additions & 1 deletion src/std/cli/getopt.ss
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

(import (only-in :std/error deferror-class Error:::init!)
(only-in :std/generic defgeneric)
(only-in :std/iter for/collect in-iota)
(only-in :std/misc/hash hash->list/sort)
(only-in :std/misc/list when/list)
(only-in :std/misc/list when/list flatten)
(only-in :std/misc/string as-string<?)
(only-in :std/sugar try catch)
(only-in :std/format fprintf)
Expand Down Expand Up @@ -442,3 +443,11 @@
(call-with-getopt-parse processor (getopt-parse processor command-line) function))
((list? processor)
(call-with-processed-command-line (apply getopt processor) command-line function)))))

(defgeneric ->getopt-spec
(lambda (spec)
(cond
((list? spec) (flatten spec))
((nat? spec) (for/collect ((i (in-iota spec 1))) (argument (format "arg~d" i))))
((not spec) (rest-arguments "rest"))
(else (error "Bad getopt spec")))))
14 changes: 3 additions & 11 deletions src/std/cli/multicall.ss
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
(only-in :std/getopt getopt getopt-display-help-topic getopt-display-help
call-with-processed-command-line
command flag option argument optional-argument rest-arguments)
(only-in :std/iter for/collect in-iota)
(only-in :std/misc/hash hash->list/sort)
(only-in :std/misc/list flatten)
(only-in :std/misc/number nat?)
Expand All @@ -28,18 +27,10 @@

(defstruct entry-point (name function help getopt) transparent: #t)

(defgeneric getopt-spec
(lambda (spec)
(cond
((list? spec) spec)
((nat? spec) (for/collect ((i (in-iota spec 1))) (argument (number->string i))))
((not spec) [(rest-arguments "rest")])
(else (error "Bad getopt-spec")))))

(def (entry-points-getopt-spec (h entry-points))
(for/collect (([name . e] (hash->list/sort h as-string<?)))
(apply command name help: (entry-point-help e)
(getopt-spec (entry-point-getopt e)))))
(->getopt-spec (entry-point-getopt e)))))

;; TODO: allow registering a getopt: structure and/or other command information,
;; so we can show detailed help and automatically parse arguments?
Expand All @@ -65,12 +56,13 @@
(help: "Print help about available commands"
getopt: [(optional-argument 'command help: "subcommand for which to display help")])
(displayln (display-build-manifest (filter-build-manifest)))
(def gopt (apply getopt (entry-points-getopt-spec)))
(def gopt (getopt (entry-points-getopt-spec)))
(def program (current-program-string (cdr (current-program))))
(if command
(getopt-display-help-topic gopt (make-symbol command) program)
(getopt-display-help gopt program)))

;; TODO: also handle getopt specifications?
(define-entry-point (meta)
(help: "Print meta-information for completion purposes"
getopt: [])
Expand Down

0 comments on commit e9cd89e

Please sign in to comment.