flag: add .usage_example/1, .footer/1, .remaining_parameters/0 and tests
parent
71e8237483
commit
fd644e4e28
|
@ -62,6 +62,10 @@ pub:
|
||||||
idx_dashdash int // the index of a `--`, -1 if there is not any
|
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
|
all_after_dashdash []string // all options after `--` are ignored, and will be passed to the application unmodified
|
||||||
pub mut:
|
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_help_label string = 'display this help and exit'
|
||||||
default_version_label string = 'output version information and exit'
|
default_version_label string = 'output version information and exit'
|
||||||
args []string // the current list of processed args
|
args []string // the current list of processed args
|
||||||
|
@ -72,7 +76,8 @@ pub mut:
|
||||||
application_description string
|
application_description string
|
||||||
min_free_args int
|
min_free_args int
|
||||||
args_description string
|
args_description string
|
||||||
allow_unknown_args bool // whether passing undescribed arguments is allowed
|
allow_unknown_args bool // whether passing undescribed arguments is allowed
|
||||||
|
footers []string // when set, --help will display all the collected footers at the bottom.
|
||||||
}
|
}
|
||||||
|
|
||||||
[unsafe]
|
[unsafe]
|
||||||
|
@ -123,6 +128,21 @@ pub fn new_flag_parser(args []string) &FlagParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
pub fn (mut fs FlagParser) usage_example(example string) {
|
||||||
|
fs.usage_examples << example
|
||||||
|
}
|
||||||
|
|
||||||
|
// add_footer - add a footnote, that will be shown
|
||||||
|
// at the bottom of the help screen.
|
||||||
|
pub fn (mut fs FlagParser) footer(footer string) {
|
||||||
|
fs.footers << footer
|
||||||
|
}
|
||||||
|
|
||||||
// change the application name to be used in 'usage' output
|
// change the application name to be used in 'usage' output
|
||||||
pub fn (mut fs FlagParser) application(name string) {
|
pub fn (mut fs FlagParser) application(name string) {
|
||||||
fs.application_name = name
|
fs.application_name = name
|
||||||
|
@ -133,9 +153,14 @@ pub fn (mut fs FlagParser) version(vers string) {
|
||||||
fs.application_version = vers
|
fs.application_version = vers
|
||||||
}
|
}
|
||||||
|
|
||||||
// change the application version to be used in 'usage' output
|
// description appends to the application description lines, shown
|
||||||
|
// in the help/usage screen
|
||||||
pub fn (mut fs FlagParser) description(desc string) {
|
pub fn (mut fs FlagParser) description(desc string) {
|
||||||
fs.application_description = desc
|
if fs.application_description.len == 0 {
|
||||||
|
fs.application_description = desc
|
||||||
|
} else {
|
||||||
|
fs.application_description += '\n$desc'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// in most cases you do not need the first argv for flag parsing
|
// in most cases you do not need the first argv for flag parsing
|
||||||
|
@ -453,12 +478,21 @@ pub fn (fs FlagParser) usage() string {
|
||||||
use << '$fs.application_name $fs.application_version'
|
use << '$fs.application_name $fs.application_version'
|
||||||
use << '$flag.underline'
|
use << '$flag.underline'
|
||||||
}
|
}
|
||||||
use << 'Usage: $fs.application_name [options] $adesc'
|
if fs.usage_examples.len == 0 {
|
||||||
|
use << 'Usage: $fs.application_name [options] $adesc'
|
||||||
|
} else {
|
||||||
|
for i, example in fs.usage_examples {
|
||||||
|
if i == 0 {
|
||||||
|
use << 'Usage: $fs.application_name $example'
|
||||||
|
} else {
|
||||||
|
use << ' or: $fs.application_name $example'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
use << ''
|
use << ''
|
||||||
if fs.application_description != '' {
|
if fs.application_description != '' {
|
||||||
use << 'Description: $fs.application_description'
|
use << 'Description: $fs.application_description'
|
||||||
use << ''
|
use << ''
|
||||||
use << ''
|
|
||||||
}
|
}
|
||||||
// show a message about the [ARGS]:
|
// show a message about the [ARGS]:
|
||||||
if positive_min_arg || positive_max_arg || no_arguments {
|
if positive_min_arg || positive_max_arg || no_arguments {
|
||||||
|
@ -506,6 +540,9 @@ pub fn (fs FlagParser) usage() string {
|
||||||
use << fdesc
|
use << fdesc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for footer in fs.footers {
|
||||||
|
use << footer
|
||||||
|
}
|
||||||
return use.join('\n').replace('- ,', ' ')
|
return use.join('\n').replace('- ,', ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,3 +609,16 @@ pub fn (mut fs FlagParser) finalize() ?[]string {
|
||||||
remaining << fs.all_after_dashdash
|
remaining << fs.all_after_dashdash
|
||||||
return remaining
|
return remaining
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
pub fn (mut fs FlagParser) remaining_parameters() []string {
|
||||||
|
return fs.finalize() or {
|
||||||
|
eprintln(err.msg)
|
||||||
|
println(fs.usage())
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
xyz 0.0.2
|
||||||
|
-----------------------------------------------
|
||||||
|
Usage: xyz [NUMBER]...
|
||||||
|
or: xyz OPTION
|
||||||
|
|
||||||
|
Description: description line 1
|
||||||
|
description line 2
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help display this help and exit
|
||||||
|
--version output version information and exit
|
||||||
|
footer 1
|
||||||
|
footer 2
|
|
@ -0,0 +1 @@
|
||||||
|
[vlib/flag/testdata/usage_example.v:16] rest_of_args: ['abc', 'def']
|
|
@ -0,0 +1,17 @@
|
||||||
|
import os
|
||||||
|
import flag
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut fp := flag.new_flag_parser(os.args)
|
||||||
|
fp.skip_executable()
|
||||||
|
fp.application('xyz')
|
||||||
|
fp.version('0.0.2')
|
||||||
|
fp.usage_example('[NUMBER]...')
|
||||||
|
fp.usage_example('OPTION')
|
||||||
|
fp.description('description line 1')
|
||||||
|
fp.description('description line 2')
|
||||||
|
fp.footer('footer 1')
|
||||||
|
fp.footer('footer 2')
|
||||||
|
rest_of_args := fp.remaining_parameters()
|
||||||
|
dump(rest_of_args)
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
xyz 0.0.2
|
|
@ -0,0 +1,35 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
const the_source = 'vlib/flag/testdata/usage_example.v'
|
||||||
|
|
||||||
|
const the_executable = os.real_path(os.join_path(os.cache_dir(), 'flag_usage_example_app.exe'))
|
||||||
|
|
||||||
|
fn testsuite_begin() {
|
||||||
|
os.chdir(@VMODROOT)
|
||||||
|
os.rm(the_executable) or {}
|
||||||
|
res := os.execute('${@VEXE} -o $the_executable $the_source')
|
||||||
|
assert res.exit_code == 0
|
||||||
|
assert os.execute(the_executable).exit_code == 0
|
||||||
|
C.atexit(fn () {
|
||||||
|
os.rm(the_executable) or {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalise_lines(lines []string) string {
|
||||||
|
return '\n' + lines.join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_program(opts string, extension string) {
|
||||||
|
result := the_source.replace('.v', extension)
|
||||||
|
res := os.execute('$the_executable $opts')
|
||||||
|
assert res.exit_code == 0
|
||||||
|
assert normalise_lines(res.output.split_into_lines()) == normalise_lines(os.read_lines(result) or {
|
||||||
|
panic(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_normal_usage() {
|
||||||
|
check_program('abc def', '.out')
|
||||||
|
check_program(' --help', '.help.out')
|
||||||
|
check_program(' --version', '.version.out')
|
||||||
|
}
|
Loading…
Reference in New Issue