andrey-zherikov / argparse

Parser for command-line arguments
https://andrey-zherikov.github.io/argparse/
Boost Software License 1.0
31 stars 6 forks source link

Please print default values for parameters and commands (if they have one) #148

Open gizmomogwai opened 10 months ago

gizmomogwai commented 10 months ago

If there are default values for subcommands or parameters, those should be highlighted in the helptext. e.g.

import std.stdio;
import argparse;

struct Cmd1 {}
struct Cmd2 {}
enum Mode {
    WALK,
    RUN,
}
struct Arguments {
    @(NamedArgument.Description("dsc for text1"))
    string text1 = "abc";
    @(NamedArgument.Description("dsc for text2"))
    string text2;
    @(NamedArgument.Description("mode to use"))
    Mode mode = Mode.WALK;
    SubCommand!(Default!Cmd1, Cmd2) subcommands;
}
mixin CLI!Arguments.main!(arguments => arguments.writeln);

outputs

Usage: argparse-issue [--text1 TEXT1] [--text2 TEXT2] [--mode {WALK,RUN}] [-h] <command> [<args>]

Available commands:
  Cmd1
  Cmd2

Optional arguments:
  --text1 TEXT1        dsc for text1
  --text2 TEXT2        dsc for text2
  --mode {WALK,RUN}    mode to use
  -h, --help           Show this help message and exit

at the moment when called with --help. It would be great if something like

Usage: argparse-issue [--text1 TEXT1] [--text2 TEXT2] [--mode {WALK,RUN}] [-h] <command> [<args>]

Available commands:
  Cmd1 (default)
  Cmd2

Optional arguments:
  --text1 TEXT1        dsc for text1 (defaults to abc)
  --text2 TEXT2        dsc for text2
  --mode {WALK,RUN}    mode to use (defaults to WALK)
  -h, --help           Show this help message and exit

could be printed.

SirNickolas commented 10 months ago

I think it is a good idea, but it needs some thinking about corner cases.

(defaults to abc)

docopt (as well as docopt.py, which gave birth to this family of libraries) uses [Default: abc] syntax (default is case-insensitive there), which we can adopt as well. Just suggesting alternatives so that we have more options to choose from.

It can probably be made user-configurable.

--text2 TEXT2 dsc for text2

--text2 is an optional argument, which does have a default value too – "". (Well, null actually.) Should we print it? (defaults to ) / [Default: ] / etc.


Fields can have arbitrary user-defined types. Will formatting them via toString suffice? And how should we determine whether we should print the default value of a custom type?

andrey-zherikov commented 10 months ago

I see few options how this can be implemented:

  1. Detection of member = value; can be partially done via COMMAND.init.member != typeof(COMMAND.member).init check. Partially - because it won't detect a case when value is the same as typeof(COMMAND.member).init (e.g. struct T { int i = 0; }).
  2. Add Default!value modifier to PositionalArgument and NamedArgument. Cons is that value will have to be duplicated: struct T { @(NamedArgument.Default!123) int i = 123; }.
  3. Add PrintDefaultValueInHelp(bool) modifier to PositionalArgument and NamedArgument.
  4. Combination on 1 and 3: default value is printed if PrintDefaultValueInHelp(true) or check 1 is true.

I think option 4 is better as it allows reasonable default behavior and flexible customization.

SirNickolas commented 10 months ago

An idea that hopefully makes the default [no pun intended] behavior even more reasonable. Unless overridden by PrintDefaultValueInHelp, that flag should be true iff T is an enum or check 1 is true. With this adjustment, the {WALK,RUN} example from the initial comment will work as proposed.