args icon indicating copy to clipboard operation
args copied to clipboard

Support positional args

Open seaneagan opened this issue 9 years ago • 5 comments

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)

seaneagan avatar May 08 '15 21:05 seaneagan

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.

nex3 avatar May 08 '15 21:05 nex3

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?

seaneagan avatar May 14 '15 16:05 seaneagan

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.

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.

nex3 avatar May 14 '15 20:05 nex3

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.

seaneagan avatar May 15 '15 13:05 seaneagan

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.

gerardsimons avatar Mar 26 '21 09:03 gerardsimons