argparse: Allow usage without optspecs

It's still useful without, for instance to implement a command that
takes no options, or to check min-args or max-args.

(technically no optspecs, no min/max args and --ignore-unknown does
nothing, but that's a very specific error that we don't need to forbid)

Fixes #9006
This commit is contained in:
Fabian Boehm 2022-06-27 16:59:12 +02:00
parent fee5a9125a
commit 993448d552
3 changed files with 26 additions and 19 deletions

View File

@ -64,10 +64,11 @@ If ``$argv`` is empty then there is nothing to parse and ``argparse`` returns ze
The ``or return`` means that the function returns ``argparse``'s status if it failed, so if it goes on ``argparse`` succeeded.
The ``--`` argument is required. You do not have to include any arguments after the ``--`` but you must include the ``--``. For example, this is acceptable::
The ``--`` argument is required. You do not have to include any option specifications or arguments after the ``--`` but you must include the ``--``. For example, this is acceptable::
set -l argv
set -l argv foo
argparse 'h/help' 'n/name' -- $argv
argparse --min-args=1 -- $argv
But this is not::

View File

@ -353,11 +353,6 @@ static int collect_option_specs(argparse_cmd_opts_t &opts, int *optind, int argc
return STATUS_INVALID_ARGS;
}
if (opts.options.empty()) {
streams.err.append_format(_(L"%ls: No option specs were provided\n"), cmd);
return STATUS_INVALID_ARGS;
}
return STATUS_CMD_OK;
}
@ -428,9 +423,13 @@ static int parse_cmd_opts(argparse_cmd_opts_t &opts, int *optind, //!OCLINT(hig
if (opts.print_help) return STATUS_CMD_OK;
if (argc == w.woptind || std::wcscmp(L"--", argv[w.woptind - 1]) == 0) {
if (std::wcscmp(L"--", argv[w.woptind - 1]) == 0) {
--w.woptind;
}
if (argc == w.woptind) {
// The user didn't specify any option specs.
streams.err.append_format(_(L"%ls: No option specs were provided\n"), cmd);
streams.err.append_format(_(L"%ls: Missing -- separator\n"), cmd);
return STATUS_INVALID_ARGS;
}

View File

@ -1,15 +1,16 @@
#RUN: %fish %s
##########
set -g LANG C
# NOTE: This uses argparse, which touches the local variables.
# Any call that isn't an error should be enclosed in a begin/end block!
# Start by verifying a bunch of error conditions.
# These are *argparse* errors, and therefore bugs in the script,
# so they print a stack trace.
# No args is an error
# No args (not even --) is an error
argparse
#CHECKERR: argparse: No option specs were provided
#CHECKERR: argparse: Missing -- separator
#CHECKERR: checks/argparse.fish (line {{\d+}}):
#CHECKERR: argparse
#CHECKERR: ^
@ -23,13 +24,14 @@ argparse h/help
#CHECKERR: ^
#CHECKERR: (Type 'help argparse' for related documentation)
# Flags but no option specs is an error
argparse -s -- hello
#CHECKERR: argparse: No option specs were provided
#CHECKERR: checks/argparse.fish (line {{\d+}}):
#CHECKERR: argparse -s -- hello
#CHECKERR: ^
#CHECKERR: (Type 'help argparse' for related documentation)
# Flags but no option specs is not an error
begin
argparse -s -- hello
echo $status
# CHECK: 0
set -l
# CHECK: argv hello
end
# Invalid option specs
argparse h-
@ -67,7 +69,10 @@ argparse h-help=x
begin
argparse --name min-max --min-args 1 h/help --
#CHECKERR: min-max: expected >= 1 arguments; got 0
argparse --name min-max --min-args 1 --
#CHECKERR: min-max: expected >= 1 arguments; got 0
argparse --name min-max --min-args 1 --max-args 3 h/help -- arg1
argparse --name min-max --min-args 1 --max-args 3 -- arg1
argparse --name min-max --min-args 1 --max-args 3 h/help -- arg1 arg2
argparse --name min-max --min-args 1 --max-args 3 h/help -- --help arg1 arg2 arg3
argparse --name min-max --min-args 1 --max-args 3 h/help -- arg1 arg2 -h arg3 arg4
@ -76,6 +81,8 @@ begin
argparse --name min-max --max-args 1 h/help -- arg1
argparse --name min-max --max-args 1 h/help -- arg1 arg2
#CHECKERR: min-max: expected <= 1 arguments; got 2
argparse --name min-max --max-args 1 -- arg1 arg2
#CHECKERR: min-max: expected <= 1 arguments; got 2
end
# Invalid \"#-val\" spec