flag: fix displaying of both abbreviated and long options

Add tests for the usage screen
pull/3280/head
Delyan Angelov 2019-12-30 17:38:32 +02:00 committed by Alexander Medvednikov
parent d07953b0f0
commit d2f2ac523f
4 changed files with 85 additions and 81 deletions

View File

@ -109,18 +109,19 @@ fn main(){
scripting.used_tools_must_exist(['git','cc']) scripting.used_tools_must_exist(['git','cc'])
mut context := Context{} mut context := Context{}
mut fp := flag.new_flag_parser(os.args) mut fp := flag.new_flag_parser(os.args)
fp.application(os.filename(os.executable())) fp.application(filepath.filename(os.executable()))
fp.version( tool_version ) fp.version( tool_version )
fp.description( tool_description ) fp.description( tool_description )
fp.arguments_description('VCOMMIT') fp.arguments_description('VCOMMIT')
fp.skip_executable() fp.skip_executable()
show_help:=fp.bool('help', false, 'Show this help screen\n') show_help:=fp.bool_('help', `h`, false, 'Show this help screen.')
context.cmd_to_run = fp.string('command', '', 'Command to run in the old V repo.\n') context.verbose = fp.bool_('verbose', `v`, false, 'Be more verbose.\n')
context.cleanup = fp.bool('clean', true, 'Clean before running (slower).\n')
context.verbose = fp.bool('verbose', false, 'Be more verbose.\n')
context.workdir = os.realpath( fp.string('work-dir', os.tmpdir(), 'A writable folder, where the comparison will be done.\n') ) context.cleanup = fp.bool('clean', true, 'Clean before running (slower).')
context.cmd_to_run = fp.string_('command', `c`, '', 'Command to run in the old V repo.')
context.workdir = os.realpath( fp.string_('work-dir', `w`, os.tmpdir(), 'A writable folder, where the comparison will be done.\n') )
context.repo_url_v = fp.string('v-repo', remote_repo_url_v, 'The url of the V repository. You can clone it locally too.\n') context.repo_url_v = fp.string('v-repo', remote_repo_url_v, 'The url of the V repository. You can clone it locally too.\n')
@ -129,7 +130,7 @@ fn main(){
flag.SPACE+'beforehand, and then just give the local folder \n'+ flag.SPACE+'beforehand, and then just give the local folder \n'+
flag.SPACE+'path here. That will eliminate the network ops \n'+ flag.SPACE+'path here. That will eliminate the network ops \n'+
flag.SPACE+'done by this tool, which is useful, if you want \n'+ flag.SPACE+'done by this tool, which is useful, if you want \n'+
flag.SPACE+'to script it/run it in a restrictive vps/docker.\n') flag.SPACE+'to script it/run it in a restrictive vps/docker.')
if( show_help ){ if( show_help ){
println( fp.usage() ) println( fp.usage() )

View File

@ -8,7 +8,6 @@ module main
// / code, instead of in embedded C ... // / code, instead of in embedded C ...
// ///////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////
import ( import (
term
filepath filepath
benchmark benchmark
) )

View File

@ -83,18 +83,18 @@ pub fn new_flag_parser(args []string) &FlagParser {
} }
// change the application name to be used in 'usage' output // change the application name to be used in 'usage' output
pub fn (fs mut FlagParser) application(n string) { pub fn (fs mut FlagParser) application(name string) {
fs.application_name = n fs.application_name = name
} }
// change the application version to be used in 'usage' output // change the application version to be used in 'usage' output
pub fn (fs mut FlagParser) version(n string) { pub fn (fs mut FlagParser) version(vers string) {
fs.application_version = n fs.application_version = vers
} }
// change the application version to be used in 'usage' output // change the application version to be used in 'usage' output
pub fn (fs mut FlagParser) description(n string) { pub fn (fs mut FlagParser) description(desc string) {
fs.application_description = n fs.application_description = 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
@ -103,12 +103,12 @@ pub fn (fs mut FlagParser) skip_executable() {
} }
// private helper to register a flag // private helper to register a flag
fn (fs mut FlagParser) add_flag(n string, a byte, u, vd string) { fn (fs mut FlagParser) add_flag(name string, abbr byte, usage string, desc string) {
fs.flags << Flag{ fs.flags << Flag{
name: n, name: name,
abbr: a, abbr: abbr,
usage: u, usage: usage,
val_desc: vd val_desc: desc
} }
} }
@ -204,10 +204,10 @@ fn (fs mut FlagParser) parse_bool_value(longhand string, shorthand byte) ?string
// bool_opt returns an optional that returns the value associated with the flag. // bool_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (fs mut FlagParser) bool_opt(n string, a byte, u string) ?bool { pub fn (fs mut FlagParser) bool_opt(name string, abbr byte, usage string) ?bool {
fs.add_flag(n, a, u, '<bool>') fs.add_flag(name, abbr, usage, '<bool>')
parsed := fs.parse_bool_value(n, a) or { parsed := fs.parse_bool_value(name, abbr) or {
return error("parameter '$n' not provided") return error("parameter '$name' not provided")
} }
return parsed == 'true' return parsed == 'true'
} }
@ -217,11 +217,11 @@ pub fn (fs mut FlagParser) bool_opt(n string, a byte, u string) ?bool {
// the value is returned (true/false) // the value is returned (true/false)
// else // else
// the default value is returned // the default value is returned
// version with abbreviation // version with abbr
//TODO error handling for invalid string to bool conversion //TODO error handling for invalid string to bool conversion
pub fn (fs mut FlagParser) bool_(n string, a byte, v bool, u string) bool { pub fn (fs mut FlagParser) bool_(name string, abbr byte, bdefault bool, usage string) bool {
value := fs.bool_opt(n, a, u) or { value := fs.bool_opt(name, abbr, usage) or {
return v return bdefault
} }
return value return value
} }
@ -232,15 +232,15 @@ pub fn (fs mut FlagParser) bool_(n string, a byte, v bool, u string) bool {
// else // else
// the default value is returned // the default value is returned
//TODO error handling for invalid string to bool conversion //TODO error handling for invalid string to bool conversion
pub fn (fs mut FlagParser) bool(n string, v bool, u string) bool { pub fn (fs mut FlagParser) bool(name string, v bool, usage string) bool {
return fs.bool_(n, `\0`, v, u) return fs.bool_(name, 0, v, usage)
} }
// int_multi returns all instances of values associated with the flags provided // int_multi returns all instances of values associated with the flags provided
// In the case that none were found, it returns an empty array. // In the case that none were found, it returns an empty array.
pub fn (fs mut FlagParser) int_multi(n string, a byte, u string) []int { pub fn (fs mut FlagParser) int_multi(name string, abbr byte, usage string) []int {
fs.add_flag(n, a, u, '<multiple ints>') fs.add_flag(name, abbr, usage, '<multiple ints>')
parsed := fs.parse_value(n, a) parsed := fs.parse_value(name, abbr)
mut value := []int mut value := []int
for val in parsed { for val in parsed {
value << val.int() value << val.int()
@ -250,11 +250,11 @@ pub fn (fs mut FlagParser) int_multi(n string, a byte, u string) []int {
// int_opt returns an optional that returns the value associated with the flag. // int_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (fs mut FlagParser) int_opt(n string, a byte, u string) ?int { pub fn (fs mut FlagParser) int_opt(name string, abbr byte, usage string) ?int {
fs.add_flag(n, a, u, '<int>') fs.add_flag(name, abbr, usage, '<int>')
parsed := fs.parse_value(n, a) parsed := fs.parse_value(name, abbr)
if parsed.len == 0 { if parsed.len == 0 {
return error("parameter '$n' not provided") return error("parameter '$name' not provided")
} }
return parsed[0].int() return parsed[0].int()
} }
@ -264,11 +264,11 @@ pub fn (fs mut FlagParser) int_opt(n string, a byte, u string) ?int {
// the value is returned (int) // the value is returned (int)
// else // else
// the default value is returned // the default value is returned
// version with abbreviation // version with abbr
//TODO error handling for invalid string to int conversion //TODO error handling for invalid string to int conversion
pub fn (fs mut FlagParser) int_(n string, a byte, i int, u string) int { pub fn (fs mut FlagParser) int_(name string, abbr byte, idefault int, usage string) int {
value := fs.int_opt(n, a, u) or { value := fs.int_opt(name, abbr, usage) or {
return i return idefault
} }
return value return value
} }
@ -279,15 +279,15 @@ pub fn (fs mut FlagParser) int_(n string, a byte, i int, u string) int {
// else // else
// the default value is returned // the default value is returned
//TODO error handling for invalid string to int conversion //TODO error handling for invalid string to int conversion
pub fn (fs mut FlagParser) int(n string, i int, u string) int { pub fn (fs mut FlagParser) int(name string, i int, usage string) int {
return fs.int_(n, `\0`, i, u) return fs.int_(name, 0, i, usage)
} }
// float_multi returns all instances of values associated with the flags provided // float_multi returns all instances of values associated with the flags provided
// In the case that none were found, it returns an empty array. // In the case that none were found, it returns an empty array.
pub fn (fs mut FlagParser) float_multi(n string, a byte, u string) []f32 { pub fn (fs mut FlagParser) float_multi(name string, abbr byte, usage string) []f32 {
fs.add_flag(n, a, u, '<multiple floats>') fs.add_flag(name, abbr, usage, '<multiple floats>')
parsed := fs.parse_value(n, a) parsed := fs.parse_value(name, abbr)
mut value := []f32 mut value := []f32
for val in parsed { for val in parsed {
value << val.f32() value << val.f32()
@ -297,11 +297,11 @@ pub fn (fs mut FlagParser) float_multi(n string, a byte, u string) []f32 {
// float_opt returns an optional that returns the value associated with the flag. // float_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (fs mut FlagParser) float_opt(n string, a byte, u string) ?f32 { pub fn (fs mut FlagParser) float_opt(name string, abbr byte, usage string) ?f32 {
fs.add_flag(n, a, u, '<float>') fs.add_flag(name, abbr, usage, '<float>')
parsed := fs.parse_value(n, a) parsed := fs.parse_value(name, abbr)
if parsed.len == 0 { if parsed.len == 0 {
return error("parameter '$n' not provided") return error("parameter '$name' not provided")
} }
return parsed[0].f32() return parsed[0].f32()
} }
@ -311,11 +311,11 @@ pub fn (fs mut FlagParser) float_opt(n string, a byte, u string) ?f32 {
// the value is returned (float) // the value is returned (float)
// else // else
// the default value is returned // the default value is returned
// version with abbreviation // version with abbr
//TODO error handling for invalid string to float conversion //TODO error handling for invalid string to float conversion
pub fn (fs mut FlagParser) float_(n string, a byte, f f32, u string) f32 { pub fn (fs mut FlagParser) float_(name string, abbr byte, fdefault f32, usage string) f32 {
value := fs.float_opt(n, a, u) or { value := fs.float_opt(name, abbr, usage) or {
return f return fdefault
} }
return value return value
} }
@ -326,24 +326,24 @@ pub fn (fs mut FlagParser) float_(n string, a byte, f f32, u string) f32 {
// else // else
// the default value is returned // the default value is returned
//TODO error handling for invalid string to float conversion //TODO error handling for invalid string to float conversion
pub fn (fs mut FlagParser) float(n string, f f32, u string) f32 { pub fn (fs mut FlagParser) float(name string, f f32, usage string) f32 {
return fs.float_(n, `\0`, f, u) return fs.float_(name, 0, f, usage)
} }
// string_multi returns all instances of values associated with the flags provided // string_multi returns all instances of values associated with the flags provided
// In the case that none were found, it returns an empty array. // In the case that none were found, it returns an empty array.
pub fn (fs mut FlagParser) string_multi(n string, a byte, u string) []string { pub fn (fs mut FlagParser) string_multi(name string, abbr byte, usage string) []string {
fs.add_flag(n, a, u, '<multiple floats>') fs.add_flag(name, abbr, usage, '<multiple floats>')
return fs.parse_value(n, a) return fs.parse_value(name, abbr)
} }
// string_opt returns an optional that returns the value associated with the flag. // string_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (fs mut FlagParser) string_opt(n string, a byte, u string) ?string { pub fn (fs mut FlagParser) string_opt(name string, abbr byte, usage string) ?string {
fs.add_flag(n, a, u, '<string>') fs.add_flag(name, abbr, usage, '<string>')
parsed := fs.parse_value(n, a) parsed := fs.parse_value(name, abbr)
if parsed.len == 0 { if parsed.len == 0 {
return error("parameter '$n' not provided") return error("parameter '$name' not provided")
} }
return parsed[0] return parsed[0]
} }
@ -353,10 +353,10 @@ pub fn (fs mut FlagParser) string_opt(n string, a byte, u string) ?string {
// the value is returned (string) // the value is returned (string)
// else // else
// the default value is returned // the default value is returned
// version with abbreviation // version with abbr
pub fn (fs mut FlagParser) string_(n string, a byte, v, u string) string { pub fn (fs mut FlagParser) string_(name string, abbr byte, sdefault string, usage string) string {
value := fs.string_opt(n, a, u) or { value := fs.string_opt(name, abbr, usage) or {
return v return sdefault
} }
return value return value
} }
@ -366,8 +366,8 @@ pub fn (fs mut FlagParser) string_(n string, a byte, v, u string) string {
// the value is returned (string) // the value is returned (string)
// else // else
// the default value is returned // the default value is returned
pub fn (fs mut FlagParser) string(n, v, u string) string { pub fn (fs mut FlagParser) string(name string, sdefault string, usage string) string {
return fs.string_(n, `\0`, v, u) return fs.string_(name, 0, sdefault, usage)
} }
pub fn (fs mut FlagParser) limit_free_args_to_at_least(n int) { pub fn (fs mut FlagParser) limit_free_args_to_at_least(n int) {
@ -448,23 +448,24 @@ pub fn (fs FlagParser) usage() string {
if fs.flags.len > 0 { if fs.flags.len > 0 {
use += 'Options:\n' use += 'Options:\n'
for f in fs.flags { for f in fs.flags {
longstr := if f.val_desc.contains('bool') { mut onames:=[]string
', --$f.name' if f.abbr != 0 {
} else { onames << '-${f.abbr.str()}'
', --$f.name $f.val_desc'
} }
flag_desc := if f.name.len == 0 { if f.name != '' {
', $f.val_desc' if !f.val_desc.contains('<bool>') {
} else { onames << '--${f.name} $f.val_desc'
longstr }else{
onames << '--${f.name}'
}
} }
space := if flag_desc.len > SPACE.len-2 { option_names := ' ' + onames.join(', ')
'\n$SPACE' space := if option_names.len > SPACE.len-2 {
'\n${SPACE}'
} else { } else {
SPACE[flag_desc.len..] SPACE[option_names.len..]
} }
abbr_desc := if f.abbr == `\0` { '' } else { ' -${tos(f.abbr, 1)}' } use += '${option_names}${space}${f.usage}\n'
use += '${abbr_desc}${flag_desc}${space}${f.usage}\n'
} }
} }

View File

@ -245,6 +245,9 @@ fn test_allow_abreviations() {
u := fp.usage() u := fp.usage()
assert u.contains(' -v') && u.contains(' -o') && u.contains(' -i') && u.contains(' -f') assert u.contains(' -v') && u.contains(' -o') && u.contains(' -i') && u.contains(' -f')
assert u.contains(' -o, --output <string>')
assert u.contains(' -i, --count <int>')
assert u.contains(' -f, --value <float>')
} }
fn test_allow_kebab_options() { fn test_allow_kebab_options() {