pacak / bpaf

Command line parser with applicative interface
337 stars 17 forks source link

Weird formatiing of "multi value" options in usage #322

Open ysndr opened 8 months ago

ysndr commented 8 months ago

When defining adjacent parsers for mutli value options as described in the docs, the generataed help messages seem a bit misaligned:

parser ```rust #[derive(Debug, Clone, Bpaf)] #[bpaf(options)] pub struct Options { /// flag before to show isse better before: bool, /// ignored comment btw 🤔 #[bpaf(external, many)] point: Vec, #[bpaf(short, long)] /// Face the camera towards the first point rotate: bool, } #[derive(Debug, Clone, Bpaf)] #[bpaf(adjacent)] struct Point { #[bpaf(long)] /// Point coordinates point: (), #[bpaf(positional("X"))] /// X coordinate of a point x: usize, #[bpaf(positional("Y"))] /// Y coordinate of a point y: usize, #[bpaf(positional("Z"))] /// Height of a point above the plane z: f64, } fn main() { println!("{:?}", options().run()) } ```
Usage: prog [--before] [-p X Y Z]... [-r]

Available options:
        --before  flag before to show isse better                
  -p X Y Z                                                      !  1
        --point   Point coordinates                             !  2
    X             X coordinate of a point                       !  3
    Y             Y coordinate of a point                       !  3
    Z             Height of a point above the plane             !  3

    -r, --rotate  Face the camera towards the first point       !  4
    -h, --help    Prints help information                       !  4
  1. the combined adjacent flag is dedented and misaligned with the other flags
  2. the "flag portion" is aligned with all other flags (and aligned with --long flags if no short was provided
  3. the arguments are left aligned letting them stand out if there is no short flag
  4. because of the dedent (1) other flags that might be following, appear to be still in the context of the adjacent thing

I mean, I can tell that adjacent is not "specialized" to multi value flags, so i assume it just shows a summary of the group and then the individual components, whatever those are, the formating is a bit odd nonetheless

I dont know if this is helpful, but better options might be

1) align summary with other arguments ``` Usage: prog [--before] [-p X Y Z]... [-r] Available options: --before flag before to show isse better -p, --point X Y Z -p, --point Point coordinates X X coordinate of a point Y Y coordinate of a point Z Height of a point above the plane -r, --rotate Face the camera towards the first point -h, --help Prints help information ``` It throws the flag components of the `adjacent` out of alignment with the rest of the arguments but that might be ok (?) since its a sub description anyway.
2) first class support for multi value options ``` Usage: prog [--before] [-p X Y Z]... [-r] Available options: --before flag before to show isse better -p, --point X Y Z Point coordinates X X coordinate of a point Y Y coordinate of a point Z Height of a point above the plane -r, --rotate Face the camera towards the first point -h, --help Prints help information ``` maybe a combination of argument and external could work, where bpaf knows that we define an option so we dont need to `point: ()` "fake parser", or an "argument" parser is inferred if the first component is a `point: ()` flag.

Another example of wonky alignment in production ``` Usage: flox config [-l | -r | --set | --set-number | --set-bool | --delete=] Available options: -l, --list List the current values of all configurable parameters -r, --reset Reset all configurable parameters to their default values without further confirmation. --set --set set to Configuration key configuration Value --set-number --set-number Set to Configuration Value (i32) --set-bool --set-bool Set to Configuration Value (bool) --delete= Configuration key -h, --help Prints help information ```
pacak commented 8 months ago

I was trying to give more space to labels defining -p X Y Z part as a subsection header, then -p, --point and the rest of the things inside as items in this group. I like how your second proposed variant looks like though at least on a relatively narrow input. I'll see what it takes to render current adjacent groups like that.

/// ignored comment btw 🤔

At best I can turn those into group_help. external fields means it's impl Parser - can't attach help to that.