Table of Content:
Introduction
The flag:
module provides utilities for parsing
command-line flags.
This module supports two different conventions of command-line flags. The Go convention is recommended for Elvish scripts (and followed by the Elvish command itself). The alternative getopt convention is also supported, and useful for writing scripts that wrap existing programs following this convention.
Go convention
Each flag looks like -flag=value
.
For boolean flags, -flag
is equivalent
to -flag=true
. For non-boolean flags, -flag
treats the next argument as its value; in other words,
-flag value
is equivalent to -flag=value
.
Flag parsing stops before any non-flag argument, or after the flag
terminator --
.
Examples (-verbose
is a boolean flag and
-port
is a non-boolean flag):
In
-port 10 foo -x
, theport
flag is10
, and the rest (foo -x
) are non flag arguments.In
-verbose 10 foo -x
, theverbose
flag istrue
, and the rest (10 foo -x
) are non-flag arguments.In
-port 10 -- -verbose foo
, theport
flag is10
, and the part after--
(-verbose foo
) are non-flag arguments.
Using --flag
is supported, and equivalent to
-flag
.
Note: Chaining of single-letter flags is not
supported: -rf
is one flag named rf
, not
equivalent to -r -f
.
Getopt convention
A flag may have either or both of the following forms:
A short form: a single character preceded by
-
, like-f
;A long form: a string preceded by
--
, like--flag
.
A flag may take:
No argument, like
-f
or--flag
;A required argument, like
-f value
,-fvalue
,--flag=value
or--flag value
;An optional argument, like
-f
,-fvalue
,--flag
or--flag=value
.
A short flag that takes no argument can be followed immediately by
another short flag. For example, if -r
takes no arguments,
-rf
is equivalent to -r -f
. The other short
flag may be followed by more short flags (if it takes no argument), or
its argument (if it takes one). Assuming that -f
and
-v
take no arguments while -p
does, here are
some examples:
-rfv
is equivalent to-r -f -v
.-rfp80
is equivalent to-r -f -p 80
.
Some aspects of the behavior can be turned on and off as needed:
Optionally, flag parsing stops after seeing the flag terminator
--
.Optionally, flag parsing stops before seeing any non-flag argument. Turning this off corresponds to the behavior of GNU’s
getopt_long
; turning it on corresponds to the behavior of BSD’sgetopt_long
.Optionally, only long flags are supported, and they may start with
-
. Turning this on corresponds to the behavior ofgetopt_long_only
and the Go convention.
Functions
flag:call
flag:call $fn $args
Parses flags from $args
according to the signature of
the $fn
, using the Go
convention, and calls $fn
.
The $fn
must be a user-defined function (i.e. not a
builtin function or external command). Each option corresponds to a
flag; see flag:parse
for how the
default value affects the behavior of flags. After parsing, the non-flag
arguments are used as function arguments.
Example:
~> use flag
~> fn f {|&verbose=$false &port=(num 8000) name| put $verbose $port $name }
~> flag:call $f [-verbose -port 80 a.c]
▶ $true
▶ (num 80)
▶ a.c
See also flag:parse
.
flag:parse
flag:parse $args $specs
Parses flags from $args
according to the
$specs
, using the Go
convention.
The $args
must be a list of strings containing the
command-line arguments to parse.
The $specs
must be a list of flag specs:
[
[flag default-value 'description of the flag']
...
]
Each flag spec consists of the name of the flag (without the leading
-
), its default value, and a description. The default value
influences the how the flag gets converted from string:
If it is boolean, the flag is a boolean flag (see Go convention for implications). Flag values
0
,f
,F
,false
,False
andFALSE
are converted to$false
, and1
,t
,T
,true
,True
andTRUE
to$true
. Other values are invalid.If it is a string, no conversion is done.
If it is a typed number, the flag value is converted using
num
.If it is a list, the flag value is split at
,
(equivalent to{|s| put [(str:split , $s)] }
).If it is none of the above, an exception is thrown.
On success, this command outputs two values: a map containing the
value of flags defined in $specs
(whether they appear in
$args
or not), and a list containing non-flag
arguments.
Example:
~> flag:parse [-v -times 10 foo] [
[v $false 'Verbose']
[times (num 1) 'How many times']
]
▶ [&v=$true ×=(num 10)]
▶ [foo]
~> flag:parse [] [
[v $false 'Verbose']
[times (num 1) 'How many times']
]
▶ [&v=$false ×=(num 1)]
▶ []
See also flag:call
and
flag:parse-getopt
.
flag:parse-getopt
flag:parse-getopt $args $specs ^
&stop-after-double-dash=$true &stop-before-non-flag=$false &long-only=$false
Parses flags from $args
according to the
$specs
, using the getopt
convention (see there for the semantics of the options), and outputs
the result.
The $args
must be a list of strings containing the
command-line arguments to parse.
The $specs
must be a list of flag specs:
[
[&short=f &long=flag &arg-optional=$false &arg-required=$false]
...
]
Each flag spec can contain the following:
The short and long form of the flag, without the leading
-
or--
. The short form, if non-empty, must be one character. At least one of&short
and&long
must be non-empty.Whether the flag takes an optional argument or a required argument. At most one of
&arg-optional
and&arg-required
may be true.
It is not an error for a flag spec to contain more keys.
On success, this command outputs two values: a list describing all
flags parsed from $args
, and a list containing non-flag
arguments. The former list looks like:
[
[&spec=... &arg=value &long=$false]
...
]
Each entry contains the original spec for the flag, its argument, and whether the flag appeared in its long form.
Example (some output reformatted for readability):
~> var specs = [
[&short=v &long=verbose]
[&short=p &long=port &arg-required]
]
~> flag:parse-getopt [-v -p 80 foo] $specs
▶ [[&spec=[&short=v &long=verbose] &long=$false &arg='']
[&spec=[&arg-required=$true &short=p &long=port] &long=$false &arg=80]]
▶ [foo]
~> flag:parse-getopt [--verbose] $specs
▶ [[&spec=[&short=v &long=verbose] &long=$true &arg='']]
▶ []
~> flag:parse-getopt [-v] [[&short=v &extra-info=foo]] # extra key in spec
▶ [[&spec=[&extra-info=foo &short=v] &long=$false &arg='']]
▶ []
See also flag:parse
and edit:complete-getopt
.