Skip to content

Commit

Permalink
cli: simplify flag parsing (#21392)
Browse files Browse the repository at this point in the history
  • Loading branch information
ttytm authored May 1, 2024
1 parent 3ec1994 commit 7170f9d
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 30 deletions.
12 changes: 6 additions & 6 deletions vlib/cli/command.v
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,16 @@ fn (mut cmd Command) add_default_commands() {
}

fn (mut cmd Command) parse_flags() {
for {
if cmd.args.len < 1 || !cmd.args[0].starts_with('-') {
break
for cmd.args.len > 0 {
if !cmd.args[0].starts_with('-') {
return
}
mut found := false
for i in 0 .. cmd.flags.len {
mut flag := &cmd.flags[i]
if flag.matches(cmd.args, cmd.posix_mode) {
for mut flag in cmd.flags {
if flag.matches(cmd.args[0], cmd.posix_mode) {
found = true
flag.found = true
// Eat flag and its values, continue with reduced args.
cmd.args = flag.parse(cmd.args, cmd.posix_mode) or {
eprintln_exit('Failed to parse flag `${cmd.args[0]}`: ${err}')
}
Expand Down
20 changes: 15 additions & 5 deletions vlib/cli/command_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -94,44 +94,54 @@ fn test_if_flag_gets_set_with_long_arg() {
cmd.parse(['command', '--flag', 'value'])
}

fn flag_should_have_value_of_42(cmd cli.Command) ! {
fn assert_flags(cmd cli.Command) ! {
flag := cmd.flags.get_string('flag')!
assert flag == 'value'
value := cmd.flags.get_int('value')!
assert value == 42
flag2 := cmd.flags.get_string('flag-2')!
assert flag2 == 'value-2'
}

fn test_if_multiple_flags_get_set() {
mut cmd := cli.Command{
name: 'command'
execute: flag_should_have_value_of_42
execute: assert_flags
}
cmd.add_flag(cli.Flag{
flag: .string
name: 'flag'
})
cmd.add_flag(cli.Flag{
flag: .string
name: 'flag-2'
})
cmd.add_flag(cli.Flag{
flag: .int
name: 'value'
})
cmd.parse(['command', '-flag', 'value', '-value', '42'])
cmd.parse(['command', '-flag=value', '-value', '42', '-flag-2', 'value-2'])
}

fn test_if_required_flags_get_set() {
mut cmd := cli.Command{
name: 'command'
execute: flag_should_have_value_of_42
execute: assert_flags
}
cmd.add_flag(cli.Flag{
flag: .string
name: 'flag'
})
cmd.add_flag(cli.Flag{
flag: .string
name: 'flag-2'
})
cmd.add_flag(cli.Flag{
flag: .int
name: 'value'
required: true
})
cmd.parse(['command', '-flag', 'value', '-value', '42'])
cmd.parse(['command', '-flag', 'value', '-value', '42', '-flag-2', 'value-2'])
}

fn flag_is_set_in_subcommand(cmd cli.Command) ! {
Expand Down
36 changes: 17 additions & 19 deletions vlib/cli/flag.v
Original file line number Diff line number Diff line change
Expand Up @@ -213,31 +213,29 @@ pub fn (flags []Flag) get_strings(name string) ![]string {
// parse parses flag values from arguments and return
// an array of arguments with all consumed elements removed.
pub fn (mut flag Flag) parse(args []string, posix_mode bool) ![]string {
if flag.matches(args, posix_mode) {
if flag.flag == .bool {
new_args := flag.parse_bool(args)!
return new_args
} else {
if flag.value.len > 0 && flag.flag != .int_array && flag.flag != .float_array
&& flag.flag != .string_array {
return error('The argument `${flag.name}` accept only one value!')
}

new_args := flag.parse_raw(args)!
return new_args
return match true {
!flag.matches(args[0], posix_mode) {
args
}
flag.flag == .bool {
flag.parse_bool(args)!
}
flag.value.len > 0 && flag.flag !in [.int_array, .float_array, .string_array] {
error('The argument `${flag.name}` accept only one value!')
}
else {
flag.parse_raw(args)!
}
} else {
return args
}
}

// matches returns `true` if first arg in `args` matches this flag.
fn (mut flag Flag) matches(args []string, posix_mode bool) bool {
fn (mut flag Flag) matches(arg string, posix_mode bool) bool {
prefix := if posix_mode { '--' } else { '-' }
return (flag.name != '' && args[0] == '${prefix}${flag.name}')
|| (flag.name != '' && args[0].starts_with('${prefix}${flag.name}='))
|| (flag.abbrev != '' && args[0] == '-${flag.abbrev}')
|| (flag.abbrev != '' && args[0].starts_with('-${flag.abbrev}='))
return (flag.name != '' && arg == '${prefix}${flag.name}')
|| (flag.name != '' && arg.starts_with('${prefix}${flag.name}='))
|| (flag.abbrev != '' && arg == '-${flag.abbrev}')
|| (flag.abbrev != '' && arg.starts_with('-${flag.abbrev}='))
}

fn (mut flag Flag) parse_raw(args []string) ![]string {
Expand Down

0 comments on commit 7170f9d

Please sign in to comment.