andrey-zherikov / argparse

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

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

Open gizmomogwai opened 8 months ago

gizmomogwai commented 8 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 8 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 8 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 8 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.