diff --git a/vlib/flag/flag_to.v b/vlib/flag/flag_to.v index 9b5d8e5be9..fa5d18b3c1 100644 --- a/vlib/flag/flag_to.v +++ b/vlib/flag/flag_to.v @@ -524,8 +524,9 @@ pub fn (mut fm FlagMapper) parse[T]() ! { } } - // Extract any tail according to config + // Extract any tail(s) according to config if pos >= pos_last_flag + 1 { + trace_dbg_println('${@FN}: (tail) looking for tail match for position "${pos}"...') pos_is_handled = pos in fm.handled_pos if pos_is_handled { trace_dbg_println('${@FN}: (tail) skipping position "${pos}". Already handled') @@ -542,27 +543,27 @@ pub fn (mut fm FlagMapper) parse[T]() ! { continue } if field.hints.has(.has_tail) { - if last_handled_pos := fm.handled_pos[fm.handled_pos.len - 1] { - trace_println('${@FN}: (tail) flag `${arg}` last_handled_pos: ${last_handled_pos} pos: ${pos}') - if pos == last_handled_pos + 1 { - if field.hints.has(.is_array) { - fm.array_field_map_flag[field.name] << FlagData{ - raw: arg - field_name: field.name - arg: ?string(arg) // .arg is used when assigning at comptime to []XYZ - pos: pos - } - } else { - fm.field_map_flag[field.name] = FlagData{ - raw: arg - field_name: field.name - arg: ?string(arg) - pos: pos - } + trace_dbg_println('${@FN}: (tail) field "${field.name}" has a tail attribute. fm.handled_pos.len: ${fm.handled_pos.len}') + last_handled_pos := fm.handled_pos[fm.handled_pos.len - 1] or { 0 } + trace_println('${@FN}: (tail) flag `${arg}` last_handled_pos: ${last_handled_pos} pos: ${pos}') + if pos == last_handled_pos + 1 || pos == pos_last_flag + 1 { + if field.hints.has(.is_array) { + fm.array_field_map_flag[field.name] << FlagData{ + raw: arg + field_name: field.name + arg: ?string(arg) // .arg is used when assigning at comptime to []XYZ + pos: pos + } + } else { + fm.field_map_flag[field.name] = FlagData{ + raw: arg + field_name: field.name + arg: ?string(arg) + pos: pos } - fm.handled_pos << pos - continue } + fm.handled_pos << pos + continue } } } @@ -900,6 +901,10 @@ pub fn (fm FlagMapper) to_struct[T](defaults ?T) !T { } result.$(field.name) = true } $else $if field.typ is string { + trace_dbg_println('${@FN}: assigning (string) ${struct_name}.${field.name} = ${f.arg or { + 'ERROR' + } + .str()}') result.$(field.name) = f.arg or { return error('failed appending ${f.raw} to ${field.name}') } diff --git a/vlib/flag/flag_to_tail_test.v b/vlib/flag/flag_to_tail_test.v new file mode 100644 index 0000000000..41e96cda74 --- /dev/null +++ b/vlib/flag/flag_to_tail_test.v @@ -0,0 +1,62 @@ +import flag + +const posix_and_gnu_args_no_tail = ['-f'] + +const posix_and_gnu_args_tail = ['-f', 'tail'] +const posix_and_gnu_args_tails = ['-f', 'tail0', 'tail1', 'tail2'] + +const skip_posix_and_gnu_args_tail = ['skipme', '-f', 'tail'] +const skip_posix_and_gnu_args_tails = ['skipme', '-f', 'tail0', 'tail1', 'tail2'] + +struct ConfigTail { + mix bool + path string @[tail] +} + +struct ConfigTails { + mix bool + paths []string @[tail] +} + +fn test_flag_tail() { + // Test `@[tail]` edge-cases + config1, no_matches1 := flag.to_struct[ConfigTail](posix_and_gnu_args_tail)! + assert config1.mix == false + assert config1.path == 'tail' + assert no_matches1 == ['-f'] + + config2, no_matches2 := flag.to_struct[ConfigTails](posix_and_gnu_args_tails)! + assert config2.mix == false + assert config2.paths == ['tail0', 'tail1', 'tail2'] + assert no_matches2 == ['-f'] + + config3, no_matches3 := flag.to_struct[ConfigTail](skip_posix_and_gnu_args_tail, skip: 1)! + assert config3.mix == false + assert config3.path == 'tail' + assert no_matches3 == ['-f'] + + config4, no_matches4 := flag.to_struct[ConfigTails](skip_posix_and_gnu_args_tails, skip: 1)! + assert config4.mix == false + assert config4.paths == ['tail0', 'tail1', 'tail2'] + assert no_matches4 == ['-f'] + + config5, no_matches5 := flag.to_struct[ConfigTail](posix_and_gnu_args_tail, skip: 1)! + assert config5.mix == false + assert config5.path == 'tail' + assert no_matches5 == [] + + config6, no_matches6 := flag.to_struct[ConfigTails](posix_and_gnu_args_tails, skip: 1)! + assert config6.mix == false + assert config6.paths == ['tail0', 'tail1', 'tail2'] + assert no_matches6 == [] + + config7, no_matches7 := flag.to_struct[ConfigTail](posix_and_gnu_args_no_tail)! + assert config7.mix == false + assert config7.path == '' + assert no_matches7 == ['-f'] + + config8, no_matches8 := flag.to_struct[ConfigTail](posix_and_gnu_args_no_tail, skip: 1)! + assert config8.mix == false + assert config8.path == '' + assert no_matches8 == [] +}