flag #
Description
A V module to parse, map and document different command line option flag styles (as typically found in in os.args
).
flag.to_struct[T](os.args)!
can map flags into user defined V struct
s via compile time reflection.
The module supports several flag "styles" like:
- POSIX short style (
-v
) - POSIX short style repeats (
-vvvvv
) - GNU long style (
--long
/--long=value
- Go
flag
module style (-flag
,-flag-name
and GNU long) - V style (
-v
,-version
) - V long style (
--v
,--version
) as supported byflag.FlagParser
Its main features are:
- simplicity of usage.
- parses flags like
-f
or--flag
or--stuff=things
or--things stuff
. - handles bool, int, float and string args.
- can flexibly generate usage information, listing all the declared flags.
See also the cli
module, for a more complex command line option parser, that supports declaring multiple subcommands each having a separate set of options.
Example
Put the following V code in a file flags_example.v
and run it with:
v run flags_example.v -h
import flag
import os
@[xdoc: 'My application that does X']
@[footer: 'A footer']
@[version: '1.2.3']
@[name: 'app']
struct Config {
show_version bool @[short: v; xdoc: 'Show version and exit']
debug_level int @[long: debug; short: d; xdoc: 'Debug level']
level f32 @[only: l; xdoc: 'This doc text is overwritten']
example string
square bool
show_help bool @[long: help; short: h]
multi int @[only: m; repeats]
wroom []int @[short: w]
ignore_me string @[ignore]
}
fn main() {
// Map POSIX and GNU style flags found in `os.args` to fields on struct `T`
config, no_matches := flag.to_struct[Config](os.args, skip: 1)!
if no_matches.len > 0 {
println('The following flags could not be mapped to any fields on the struct: ${no_matches}')
}
if config.show_help {
// Generate and layout (a configuable) documentation for the flags
documentation := flag.to_doc[Config](
version: '1.0' // NOTE: this overrides the `@[version: '1.2.3']` struct attribute
fields: {
'level': 'This is a doc string of the field `level` on struct `Config`'
'example': 'This is another doc string'
'multi': 'This flag can be repeated'
'-e, --extra': 'Extra flag that does not exist on the struct, but we want documented (in same format as the others)'
'-q, --quiet-and-quite-long-flag <string>': 'This is a flag with a long name'
'square': '.____.\n| |\n| |\n|____|'
}
)!
println(documentation)
exit(0)
}
dump(config)
}
Usage
The 2 most useful functions in the module is to_struct[T]()
and to_doc[T]()
.
to_struct[T](...)
to_struct[T](input []string, config ParseConfig) !(T, []string)
maps flags found in input
to matching fields on T
. The matching is determined via hints that the user can specify with special field attributes. The matching is done in the following way:
- Match the flag name with the field name directly (
my_field
matches e.g.--my-field
).
- Underscores (
_
) in long field names are converted to-
. - Fields with the attribute
@[ignore]
is ignored. - Fields with the attribute
@[only: n]
will only match if the short flag-n
is provided. - Fields with the attribute
@[long: my_name]
will match the flag--my-name
.
- Match a field's short identifier, if specified.
- Short identifiers are specified using
@[short: n]
- To map a field solely to a short flag use
@[only: n]
- Short flags that repeats is mapped to fields via the attribute
@[repeats]
A new instance of T
is returned with fields assigned with values from any matching input flags, along with an array of flags that could not be matched.
usingT
using[T](defaults T, input []string, config ParseConfig) !(T, []string)
does the same as to_struct[T]()
but allows for passing in an existing instance of T
, making it possible to preserve existing field values that does not match any flags in input
.
to_doc[T](...)
pub fn to_doc[T](dc DocConfig) !string
returns an auto-generated string
with flag documentation. The documentation can be tweaked in several ways to suit any special user needs via the DocConfig
configuration struct or directly via attributes on the struct itself and it's fields.
See also examples/flag/flag_layout_editor.v
for a WYSIWYG editor.
Sub commands
Due to the nature of how to_struct[T]
works it is not suited for applications that use sub commands at first glance. git
and v
are examples of command line applications that uses sub commands e.g.: v help xyz
, where help
is the sub command.
To support this "flag" style in your application and still use to_struct[T]()
you can simply parse out your sub command prior to mapping any flags.
Try the following example.
Put the following V code in a file subcmd.v
and run it with:
v run subcmd.v -h && v run subcmd.v sub -h && v run subcmd.v sub --do-stuff ##
import flag
import os
struct Config {
show_help bool @[long: help; short: h; xdoc: 'Show version and exit']
}
struct ConfigSub {
show_help bool @[long: help; short: h; xdoc: 'Show version and exit']
do_stuff bool @[xdoc: 'Do stuff']
}
fn main() {
// Handle sub command `sub` if provided
if os.args.len > 1 && !os.args[1].starts_with('-') {
if os.args[1] == 'sub' {
config_for_sub, _ := flag.to_struct[ConfigSub](os.args, skip: 2)! // NOTE the `skip: 2`
if config_for_sub.do_stuff {
println('Working...')
exit(0)
}
if config_for_sub.show_help {
println(flag.to_doc[ConfigSub](
description: 'My sub command'
)!)
exit(0)
}
}
}
config, _ := flag.to_struct[Config](os.args, skip: 1)!
if config.show_help {
println(flag.to_doc[Config](
description: 'My application'
)!)
exit(0)
}
}
Other examples
If you want to parse flags in a more function-based manner you can use the FlagParser
instead.
module main
import os
import flag
fn main() {
mut fp := flag.new_flag_parser(os.args)
fp.application('flag_example_tool')
fp.version('v0.0.1')
fp.limit_free_args(0, 0)! // comment this, if you expect arbitrary texts after the options
fp.description('This tool is only designed to show how the flag lib is working')
fp.skip_executable()
an_int := fp.int('an_int', 0, 0o123, 'some int to define 0o123 is its default value')
a_bool := fp.bool('a_bool', 0, false, 'some boolean flag. --a_bool will set it to true.')
a_float := fp.float('a_float', 0, 1.0, 'some floating point value, by default 1.0 .')
a_string := fp.string('a_string', `a`, 'no text', 'finally, some text with ' +
' `-a` as an abbreviation, so you can pass --a_string abc or just -a abc')
additional_args := fp.finalize() or {
eprintln(err)
println(fp.usage())
return
}
println('an_int: ${an_int} | a_bool: ${a_bool} | a_float: ${a_float} | a_string: "${a_string}" ')
println(additional_args.join_lines())
}
Constants #
const space = ' '
used for formatting usage message
const underline = '-----------------------------------------------'
const max_args_number = 4048
fn new_flag_parser #
fn new_flag_parser(args []string) &FlagParser
new_flag_parser - create a new flag parser for the given args
fn to_doc #
fn to_doc[T](dc DocConfig) !string
to_doc returns a "usage" style documentation string
generated from attributes on T
or via the dc
argument.
fn to_struct #
fn to_struct[T](input []string, config ParseConfig) !(T, []string)
to_struct returns T
with field values sat to any matching flags in input
. to_struct also returns any flags from input
, in order of appearance, that could not be matched with any field on T
.
fn using #
fn using[T](defaults T, input []string, config ParseConfig) !(T, []string)
using returns defaults
with field values overwritten with any matching flags in input
. Any field that could not be matched with a flag will have the same value as the field(s) passed as defaults
. using also returns any flags from input
, in order of appearance, that could not be matched with any field on T
.
fn ([]Flag) str #
fn (af []Flag) str() string
str returns a string representation of the given array of Flags
enum FieldHints #
enum FieldHints {
is_bool
is_array
is_ignore
is_int_type
has_tail
short_only
can_repeat
}
enum ParseMode #
enum ParseMode {
strict // return errors for unknown or malformed flags per default
relaxed // relax flag match errors and add them to `no_match` list instead
}
enum Show #
enum Show {
name
version
flags
flag_type
flag_hint
description
flags_header
footer
}
enum Style #
enum Style {
short // Posix short only, allows multiple shorts -def is `-d -e -f` and "sticky" arguments e.g.: `-ofoo` = `-o foo`
long // GNU style long option *only*. E.g.: `--name` or `--name=value`
short_long // extends `posix` style shorts with GNU style long options: `--flag` or `--name=value`
v // V style flags as found in flags for the `v` compiler. Single flag denote `-` followed by string identifier e.g.: `-verbose`, `-name value`, `-v`, `-n value` or `-d ident=value`
v_flag_parser // V `flag.FlagParser` style flags as supported by `flag.FlagParser`. Long flag denote `--` followed by string identifier e.g.: `--verbose`, `--name value`, `-v` or `-n value`.
go_flag // GO `flag` module style. Single flag denote `-` followed by string identifier e.g.: `-verbose`, `-name value`, `-v` or `-n value` and both long `--name value` and GNU long `--name=value`
cmd_exe // `cmd.exe` style flags. Single flag denote `/` followed by lower- or upper-case character
}
struct DocConfig #
struct DocConfig {
pub:
delimiter string = '-' // delimiter used for flags
style Style = .short_long // expected flag style
pub mut:
name string // application name
version string // application version
description string // application description
footer string // application description footer written after auto-generated flags list/ field descriptions
layout DocLayout // documentation layout
options DocOptions // documentation options
fields map[string]string // doc strings for each field (overwrites @[doc: xxx] attributes)
}
struct DocLayout #
struct DocLayout {
pub mut:
description_padding int = 28
description_width int = 50
flag_indent int = 2
}
fn (DocLayout) max_width #
fn (dl DocLayout) max_width() int
max_width returns the total width of the DocLayout
.
struct DocOptions #
struct DocOptions {
pub mut:
flag_header string = '\nOptions:'
compact bool
show Show = ~Show.zero()
}
struct Flag #
struct Flag {
pub:
name string // name as it appears on command line
abbr u8 // shortcut
usage string // help message
val_desc string // something like '' that appears in usage,
// and also the default value, when the flag is not given
}
data object storing information about a defined flag
fn (Flag) str #
fn (f Flag) str() string
str returns a string representation of the given Flag
struct FlagConfig #
struct FlagConfig {
pub:
val_desc string // descriptive string for an argument
}
struct FlagMapper #
struct FlagMapper {
pub:
config ParseConfig @[required]
input []string @[required]
mut:
si StructInfo
handled_pos []int // tracks handled positions in the `input` args array. NOTE: can contain duplicates
field_map_flag map[string]FlagData
array_field_map_flag map[string][]FlagData
no_match []int // indicies of unmatched flags in the `input` array
}
fn (FlagMapper) no_matches #
fn (fm FlagMapper) no_matches() []string
no_matches returns any flags from the input
array, in order of appearance, that could not be matched against any fields. no_matches should be called after to_struct[T]()
.
fn (FlagMapper) parse #
fn (mut fm FlagMapper) parse[T]() !
parse parses T
to an internal data representation.
fn (FlagMapper) to_doc #
fn (fm FlagMapper) to_doc(dc DocConfig) !string
to_doc returns a "usage" style documentation string
generated from the internal data structures generated via the parse()
function.
fn (FlagMapper) fields_docs #
fn (fm FlagMapper) fields_docs(dc DocConfig) ![]string
fields_docs returns every line of the combined field documentation.
fn (FlagMapper) to_struct #
fn (fm FlagMapper) to_struct[T](defaults ?T) !T
to_struct returns defaults
or a new instance of T
that has the parsed flags from input
mapped to the fields of struct T
.
struct FlagParser #
struct FlagParser {
pub:
original_args []string // the original arguments to be parsed
idx_dashdash int // the index of a `--`, -1 if there is not any
all_after_dashdash []string // all options after `--` are ignored, and will be passed to the application unmodified
pub mut:
usage_examples []string // when set, --help will print:
// Usage: $appname $usage_examples[0]`
// or: $appname $usage_examples[1]`
// etc
default_help_label string = 'display this help and exit'
default_version_label string = 'output version information and exit'
args []string // the current list of processed args
max_free_args int
flags []Flag // registered flags
application_name string
application_version string
application_description string
min_free_args int
args_description string
allow_unknown_args bool // whether passing undescribed arguments is allowed
footers []string // when set, --help will display all the collected footers at the bottom.
}
FlagParser is the heart of the flag
module. That structure is created with mut parser := flag.new_flag_parser(os.args)
, The returned instance can be further customised by calling various methods, for specifying the accepted options and their values. The user should finally call rest := parser.finalize()!
to get the rest of the non optional arguments (if there are any left).
fn (FlagParser) usage_example #
fn (mut fs FlagParser) usage_example(example string)
usage_example - add an usage example All examples will be listed in the help screen. If you do not give any examples, then a default usage will be shown, based on whether the application takes options and expects additional parameters.
fn (FlagParser) application #
fn (mut fs FlagParser) application(name string)
change the application name to be used in 'usage' output
fn (FlagParser) version #
fn (mut fs FlagParser) version(vers string)
change the application version to be used in 'usage' output
fn (FlagParser) description #
fn (mut fs FlagParser) description(desc string)
description appends to the application description lines, shown in the help/usage screen
fn (FlagParser) skip_executable #
fn (mut fs FlagParser) skip_executable()
in most cases you do not need the first argv for flag parsing
fn (FlagParser) allow_unknown_args #
fn (mut fs FlagParser) allow_unknown_args()
allow_unknown_args - if your program has sub commands, that have their own arguments, you can call .allow_unknown_args(), so that the subcommand arguments (which generally are not known to your parent program), will not cause the validation in .finalize() to fail.
fn (FlagParser) bool_opt #
fn (mut fs FlagParser) bool_opt(name string, abbr u8, usage string, c FlagConfig) !bool
bool_opt returns an option with the bool value of the given command line flag, named name
. It returns an error, when the flag is not given by the user. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) bool #
fn (mut fs FlagParser) bool(name string, abbr u8, bdefault bool, usage string, c FlagConfig) bool
bool defines and parses a string flag/option named name
. If that flag is given by the user, then it returns its parsed bool value. When it is not, it returns the default value in bdefault
. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) int_multi #
fn (mut fs FlagParser) int_multi(name string, abbr u8, usage string, c FlagConfig) []int
int_multi returns all values associated with the provided flag in name
. When that flag has no values, it returns an empty array. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) int_opt #
fn (mut fs FlagParser) int_opt(name string, abbr u8, usage string, c FlagConfig) !int
int_opt returns an option with the integer value, associated with the flag in name
. When the flag is not given by the user, it returns an error. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) int #
fn (mut fs FlagParser) int(name string, abbr u8, idefault int, usage string, c FlagConfig) int
int defines and parses an integer flag, named name
. When the flag is given by the user, it returns its parsed integer value. When it is not, it returns the integer value in idefault
. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) float_multi #
fn (mut fs FlagParser) float_multi(name string, abbr u8, usage string, c FlagConfig) []f64
float_multi returns all floating point values, associated with the flag named name
. When no values for that flag are found, it returns an empty array. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) float_opt #
fn (mut fs FlagParser) float_opt(name string, abbr u8, usage string, c FlagConfig) !f64
float_opt returns an option with the floating point value, associated with the flag in name
. When the flag is not given by the user, it returns an error. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) float #
fn (mut fs FlagParser) float(name string, abbr u8, fdefault f64, usage string, c FlagConfig) f64
float defines and parses a floating point flag, named name
. When the flag is given by the user, it returns its parsed floating point value. When it is not, it returns the value in fdefault
. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) string_multi #
fn (mut fs FlagParser) string_multi(name string, abbr u8, usage string, c FlagConfig) []string
string_multi returns all string values, associated with the flag named name
. When no values for that flag are found, it returns an empty array. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) string_opt #
fn (mut fs FlagParser) string_opt(name string, abbr u8, usage string, c FlagConfig) !string
string_opt returns an option with the string value, associated with the flag in name
. When the flag is not given by the user, it returns an error. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) string #
fn (mut fs FlagParser) string(name string, abbr u8, sdefault string, usage string, c FlagConfig) string
string defines and parses a string flag/option, named name
. If that flag is given as an option, then its parsed value is returned as a string. When it is not, it returns the default string value in sdefault
. This version supports abbreviations. This version supports a custom value description.
fn (FlagParser) limit_free_args_to_at_least #
fn (mut fs FlagParser) limit_free_args_to_at_least(n int) !
limit_free_args_to_at_least restricts the list of free arguments (non options) to be at least n
in length. If the user gives less free arguments to the program, the parser will return an error.
fn (FlagParser) limit_free_args_to_exactly #
fn (mut fs FlagParser) limit_free_args_to_exactly(n int) !
limit_free_args_to_exactly restricts the list of free arguments (non options) to be at exactly n
in length. If the user gives more or less free arguments to the program, the parser will return an error.
fn (FlagParser) limit_free_args #
fn (mut fs FlagParser) limit_free_args(min int, max int) !
limit_free_args restricts the list of free arguments (non options) to be between min
and max
in length. If the user gives more or less free arguments to the program, the parser will return an error.
fn (FlagParser) arguments_description #
fn (mut fs FlagParser) arguments_description(description string)
arguments_description sets the description field of the parser. This field is usually shown when the --help
option is given to the program.
fn (FlagParser) usage #
fn (fs &FlagParser) usage() string
usage returns a nicely formatted usage screen, containing all the possible options, as well as the description for the program. That screen is usually shown when the --help
option is given to the program.
fn (FlagParser) finalize #
fn (mut fs FlagParser) finalize() ![]string
finalize - return all remaining arguments (non options). Call .finalize() after all arguments are defined. The remaining arguments are returned in the same order they are defined on the command line. If additional flags are found, i.e. (things starting with '--' or '-'), it returns an error.
fn (FlagParser) remaining_parameters #
fn (mut fs FlagParser) remaining_parameters() []string
remaining_parameters will return all remaining parameters. Call .remaining_parameters() AFTER you have defined all options that your program needs. remaining_parameters will also print any parsing errors and stop the program. Use .finalize() instead, if you want more control over the error handling.
struct ParseConfig #
struct ParseConfig {
pub:
delimiter string = '-' // delimiter used for flags
mode ParseMode = .strict // return errors for unknown or malformed flags per default
style Style = .short_long // expected flag style
stop ?string // single, usually '--', string that stops parsing flags/options
skip u16 // skip this amount in the input argument array, usually `1` for skipping executable or subcmd entry
}
- README
- Constants
- fn new_flag_parser
- fn to_doc
- fn to_struct
- fn using
- type []Flag
- enum FieldHints
- enum ParseMode
- enum Show
- enum Style
- struct DocConfig
- struct DocLayout
- struct DocOptions
- struct Flag
- struct FlagConfig
- struct FlagMapper
- struct FlagParser
- fn usage_example
- fn footer
- fn application
- fn version
- fn description
- fn skip_executable
- fn allow_unknown_args
- fn bool_opt
- fn bool
- fn int_multi
- fn int_opt
- fn int
- fn float_multi
- fn float_opt
- fn float
- fn string_multi
- fn string_opt
- fn string
- fn limit_free_args_to_at_least
- fn limit_free_args_to_exactly
- fn limit_free_args
- fn arguments_description
- fn usage
- fn finalize
- fn remaining_parameters
- struct ParseConfig