Skip to content

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 structs 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)

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:

  1. 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.
  1. 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 #

@[flag]
enum FieldHints {
	is_bool
	is_array
	is_ignore
	is_int_type
	has_tail
	short_only
	can_repeat
}

enum Show #

@[flag]
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`
	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 #

@[params]
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 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) footer #

fn (mut fs FlagParser) footer(footer string)

add_footer - add a footnote, that will be shown at the bottom of the help screen.

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) !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.

fn (FlagParser) bool #

fn (mut fs FlagParser) bool(name string, abbr u8, bdefault bool, usage string) 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.

fn (FlagParser) int_multi #

fn (mut fs FlagParser) int_multi(name string, abbr u8, usage string) []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.

fn (FlagParser) int_opt #

fn (mut fs FlagParser) int_opt(name string, abbr u8, usage string) !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.

fn (FlagParser) int #

fn (mut fs FlagParser) int(name string, abbr u8, idefault int, usage string) 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.

fn (FlagParser) float_multi #

fn (mut fs FlagParser) float_multi(name string, abbr u8, usage string) []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.

fn (FlagParser) float_opt #

fn (mut fs FlagParser) float_opt(name string, abbr u8, usage string) !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.

fn (FlagParser) float #

fn (mut fs FlagParser) float(name string, abbr u8, fdefault f64, usage string) 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.

fn (FlagParser) string_multi #

fn (mut fs FlagParser) string_multi(name string, abbr u8, usage string) []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.

fn (FlagParser) string_opt #

fn (mut fs FlagParser) string_opt(name string, abbr u8, usage string) !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.

fn (FlagParser) string #

fn (mut fs FlagParser) string(name string, abbr u8, sdefault string, usage string) 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.

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 #

@[params]
struct ParseConfig {
pub:
	delimiter string = '-' // delimiter used for flags
	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
}