flag: handle `--` as a parsing stop, and pass everything after it in .finalise() (#10703)

pull/10723/head
JalonSolov 2021-07-09 04:13:32 -04:00 committed by GitHub
parent 47bf64473c
commit f62b6b37f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 21 deletions

View File

@ -40,8 +40,9 @@ fn (mut f Flag) free() {
}
pub fn (f Flag) str() string {
return '' + ' flag:\n' + ' name: $f.name\n' + ' abbr: $f.abbr\n' +
' usag: $f.usage\n' + ' desc: $f.val_desc'
return '' + ' flag:\n' + ' name: $f.name\n' +
' abbr: `$f.abbr.ascii_str()`\n' + ' usag: $f.usage\n' +
' desc: $f.val_desc'
}
pub fn (af []Flag) str() string {
@ -56,8 +57,12 @@ pub fn (af []Flag) str() string {
//
pub 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:
args []string // the arguments to be parsed
args []string // the current list of processed args
max_free_args int
flags []Flag // registered flags
application_name string
@ -96,10 +101,22 @@ pub const (
)
// create a new flag set for parsing command line arguments
// TODO use INT_MAX some how
pub fn new_flag_parser(args []string) &FlagParser {
original_args := args.clone()
idx_dashdash := args.index('--')
mut all_before_dashdash := args.clone()
mut all_after_dashdash := []string{}
if idx_dashdash >= 0 {
all_before_dashdash.trim(idx_dashdash)
if idx_dashdash < original_args.len {
all_after_dashdash = original_args[idx_dashdash + 1..]
}
}
return &FlagParser{
args: args.clone()
original_args: original_args
idx_dashdash: idx_dashdash
all_after_dashdash: all_after_dashdash
args: all_before_dashdash
max_free_args: flag.max_args_number
}
}
@ -168,10 +185,6 @@ fn (mut fs FlagParser) parse_value(longhand string, shorthand byte) []string {
should_skip_one = false
continue
}
if arg == '--' {
// End of input. We're done here.
break
}
if arg[0] != `-` {
continue
}
@ -219,10 +232,6 @@ fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand byte) ?string
{
full := '--$longhand'
for i, arg in fs.args {
if arg == '--' {
// End of input. We're done.
break
}
if arg.len == 0 {
continue
}
@ -504,8 +513,9 @@ pub fn (fs FlagParser) usage() string {
// defined on the command line. If additional flags are found, i.e.
// (things starting with '--' or '-'), it returns an error.
pub fn (fs FlagParser) finalize() ?[]string {
mut remaining := fs.args.clone()
if !fs.allow_unknown_args {
for a in fs.args {
for a in remaining {
if (a.len >= 2 && a[..2] == '--') || (a.len == 2 && a[0] == `-`) {
return IError(&UnkownFlagError{
msg: 'Unknown flag `$a`'
@ -513,20 +523,21 @@ pub fn (fs FlagParser) finalize() ?[]string {
}
}
}
if fs.args.len < fs.min_free_args && fs.min_free_args > 0 {
if remaining.len < fs.min_free_args && fs.min_free_args > 0 {
return IError(&MinimumArgsCountError{
msg: 'Expected at least $fs.min_free_args arguments, but given $fs.args.len'
msg: 'Expected at least $fs.min_free_args arguments, but given $remaining.len'
})
}
if fs.args.len > fs.max_free_args && fs.max_free_args > 0 {
if remaining.len > fs.max_free_args && fs.max_free_args > 0 {
return IError(&MaximumArgsCountError{
msg: 'Expected at most $fs.max_free_args arguments, but given $fs.args.len'
msg: 'Expected at most $fs.max_free_args arguments, but given $remaining.len'
})
}
if fs.args.len > 0 && fs.max_free_args == 0 && fs.min_free_args == 0 {
if remaining.len > 0 && fs.max_free_args == 0 && fs.min_free_args == 0 {
return IError(&NoArgsExpectedError{
msg: 'Expected no arguments, but given $fs.args.len'
msg: 'Expected no arguments, but given $remaining.len'
})
}
return fs.args
remaining << fs.all_after_dashdash
return remaining
}

View File

@ -382,3 +382,26 @@ fn test_optional_flags() {
b := fp.string_opt('another-flag', `b`, '') or { 'some_default_value' }
assert b == 'some_default_value'
}
fn test_dashdash_acts_as_parser_full_stop() ? {
mut fp := flag.new_flag_parser(['-b', '5', '--', '-d', '-x', '-b', '4', '-a', '-c', 'hello',
'some', 'other', 'parameters'])
a := fp.bool_opt('a-bool-flag', `a`, '') or { false }
b := fp.int_opt('an-int-flag', `b`, '') or { -1 }
c := fp.string_opt('a-string-flag', `c`, '') or { 'default' }
assert a == false
assert b == 5
assert c == 'default'
args := fp.finalize() ?
assert args.len > 0
assert args[0] != '--'
assert args == ['-d', '-x', '-b', '4', '-a', '-c', 'hello', 'some', 'other', 'parameters']
}
fn test_dashdash_acts_as_parser_full_stop_dashdash_at_end() ? {
mut fp := flag.new_flag_parser(['-b', '5', '-b', '4', 'other', 'params', '--'])
b := fp.int_multi('an-int-flag', `b`, '')
assert b == [5, 4]
args := fp.finalize() ?
assert args.len > 0
}