peterbourgon / ff

Flags-first package for configuration

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ffcli.DefaultUsageFunc: Match output of FlagSet.PrintDefaults

abhinav opened this issue · comments

This issue is to discuss a possible change in behavior in advance of a PR.
Currently, -h on a ffcli.Command prints a FLAGS section like the following:

  -b=false  bool
  -d 0s     time.Duration
  -f 0      float64
  -i 0      int
  -s ...    string
  -x ...    collection of strings (repeatable)

Things to note:

  • Flags use the placeholder "..." instead of "string", "int", or something more helpful.
  • Flags are always on the same line as the flag usage. Usage text has to shift right if a flag with a different length is added.
  • Defaults are printed in the help message instead of being put at the end of the usage text, which adds another case when usage text has to shift right.
  • Usage text shifting right adds uncertainty to how much horizontal space is available to a help message for a flag.
  • Doesn't handle newlines in the flag usage text; it'll wrap to the next line instead of being indented to match.

FlagSet.PrintDefaults, on the other hand, prints:

  -b        bool
  -d duration
            time.Duration
  -f float
            float64
  -i int
            int
  -s string
            string
  -x value
            collection of strings (repeatable)

Only short boolean flags are on the same line -- if they fit in that space. All other usage text is on the next line and indented.

Not visible in this example:

  • non-zero defaults are added at the end in the form (default: foo)

  • newlines in usage text are adjusted to match indentation of the rest of the text

  • if the help text wraps a word with backticks, for example:

    path to input `file`
    

    then that word is treated as the placeholder in the help:

    -f file
              path to input file
    

It's not terribly difficult to change DefaultUsageFunc to match this behavior, but it is a change in behavior.
Are you open to such a change or would you prefer that users write a custom UsageFunc for this?

Guess this is close-able?

Note quite ready to close. #106 was an incremental less-controversial change.

I wanted your opinion before I made the changes proposed in this issue.
In short, there are a fair number of differences between the output of ffcli.DefaultUsageFunc and FlagSet.PrintDefaults.
I'm happy to make DefaultUsageFunc match FlagSet.PrintDefaults, but I want to know if you're okay with that change.

I'm happy to make changes like the one that was merged, but I definitely don't want ff.DefaultUsageFunc to match flag.FlagSet.PrintDefaults — I consider the latter to be pretty user-unfriendly, overall.

edit: Sorry, I failed to parse the OP. No, I think it's important to keep each flag on a single line, basically.

That's a completely reasonable position to hold.
Just for clarity, I'll enumerate the differences between DefaultUsageFunc and PrintDefaults:

  • flag and help are on separate lines if flag is longer than a couple characters
  • help can be multi-line and its indentation is adjusted accordingly
  • flag value in help (-foo bar) is the type of the value (-foo sting) or the name specified with back-ticks (per #106)
  • default value is at the end of the help text (e.g. -f file path to output file (default: "foo"))

There are a couple independent changes that could be made here:

  1. Split flag and help across two lines if flag is long — you've indicated this is undesirable
  2. Support multi-line flag help message — I suspect this would be acceptable
  3. Move default value to the end of the help text; this will have the effect of only printing flag type (-f string) or back-ticked value name (-f file) instead of default value in help (-f out.txt)

I'm willing to make all or a subset of these changes depending on what you like or dislike about flag.PrintDefaults.
I'm also happy to close this issue if you feel that further alignment with flag.PrintDefaults is a poorer user-experience.

Lastly, another alternative is: DefaultUsageFunc retains its current behavior, and a second alternative is added (ffcli.StdUsageFunc?) that matches the behavior of flag.PrintDefaults. If we do this, it will likely make sense for a ffcli.Command with a nil usage func to inherit it from its parent so that a program specifies the override once only.

Split flag and help across two lines if flag is long — you've indicated this is undesirable

👍

Support multi-line flag help message — I suspect this would be acceptable

I'd say this is out of scope for DefaultUsageFunc, and something you should solve with your own implementation. (IMO multi-line flag help messages are a code smell, so to speak, and should be fixed, though I understand reasonable people may disagree.)

Move default value to the end of the help text; this will have the effect of only printing flag type (-f string) or back-ticked value name (-f file) instead of default value in help (-f out.txt)

I don't have strong opinions here.

Move default value to the end of the help text; this will have the effect of only printing flag type (-f string) or back-ticked >> value name (-f file) instead of default value in help (-f out.txt)

I don't have strong opinions here.

Likewise.

Honestly, the only one I considered actionable is multi-line help, but I'm okay with calling that not ffcli's problem.
Command.Usage provides the ability to plug in arbitrary behavior so DefaultUsageFunc doesn't have to do it all.
I will close the issue since I don't see anything else actionable.

Thanks for the discussion!