args
args copied to clipboard
Support positional args
Positional arguments are fully supported in unscripted. It would be nice to upstream that to args
.
Unscripted has an internal Positional
type which shares some properties with Option
, like help
, valueHelp
, allowed
, parser
(e.g. int.parse
), which can be added to a Usage
(unscripted's version of ArgParser) via an addPositional
method.
It also has a Rest
type which inherits from Positional
and defines a "rest parameter" which defines homogeneous trailing positional arguments, and which has a required
property which defines whether or not at least one value is required. It can be assigned to a Usage
via a rest
property since there can only be one of them.
Supporting positionals allows unscripted to have:
- Nice error messages upon too many or not enough positionals, or non-allowed values for a positional.
- Nice help text for positionals:
$ foo.dart --help
Usage:
foo.dart [<options>] <valueHelp1> <valueHelp2> <restValueHelp>...
<valueHelp1> <help1>
<valueHelp2> <help2>
<restValueHelp> <restHelp>
Options:
...
- Tab-completion support for positionals:
Unscripted does not support optional positionals since dart methods cannot yet have both optional named and optional positional arguments, and so supporting optional positionals would mean no "--" options could be added, but presumably args
could support it.
Proposed API
parser
..addPositional(...)
..addPositional(...)
..startOptionalPositionals()
..addPositional(...)
..addPositional(...)
..addRest(...);
If addRest
is called, and not startOptionalPositionals
, then at least rest arg must be passed.
Also, in unscripted I'm considering disallowing adding both positionals and sub-commands to the same Usage (ArgParser in args
case), since that can be ambiguous. I think right now args
assumes anything which matches a sub-command name is the sub-command and not a positional value, but the user might have intended differently. And it would also make the cli invocation hard to read when it includes both positional values and a sub-command name, I don't think I've ever seen it in practice, so shouldn't hurt to disallow it.
(Moved from http://dartbug.com/20042)
I'm skeptical of adding such a complex and detailed validation API for positional arguments. In my experience, the handling of positional arguments is very idiosyncratic; either it's something very simple like "this takes two or three arguments" or it's something very complicated that isn't worth the hassle of trying to write an API to express. I'd still prefer the much simpler minPositional
/maxPositional
API I proposed originally in issue 20042.
The above proposed API is not complex, addPositional(...)
/addRest(...)
are pretty much exactly like the existing addFlag(...)
/addOption(...)
, and startOptionalPositionals()
doesn't even take any arguments. Yet it covers any cases I'm aware of how positional arguments are passed to commands.
@nex3 can you give an example of a command-line interface which this simple API does not handle?
The above proposed API is not complex,
addPositional(...)
/addRest(...)
are pretty much exactly like the existingaddFlag(...)
/addOption(...)
, andstartOptionalPositionals()
doesn't even take any arguments. Yet it covers any cases I'm aware of how positional arguments are passed to commands.
Clearly I disagree.
@nex3 can you give an example of a command-line interface which this simple API does not handle?
It doesn't handle things like "zero or two parameters" or "allow this flag only with a positional argument" or "the first positional should be named foo
unless there's a second in which case it should be named bar
". All of these require extra munging after the arguments have been parsed.
It doesn't handle things like "zero or two parameters"
Do you have a real world example? Surely there is a better design.
or "allow this flag only with a positional argument"
That's not specific to positional arguments, it's just a special case of "allow this argument only with this other argument".
or "the first positional should be named foo unless there's a second in which case it should be named bar".
So some_command foo
or some_command bar baz
? foo
and bar
are sub-commands then, not positional arguments.
All of these require extra munging after the arguments have been parsed.
Again, this is not specific to positional arguments, or even to command-line interfaces. It's just as common with (sets of) named arguments, and with programming language interfaces to have to do "precondition checks" after the arguments have passed the built-in standardized signature checks.
I would personally think I would enjoy more structure around the positional args. I find myself using options
just so it is better self-documenting, better structured in the code and with more strict checks.