pacak / bpaf

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

Release 0.9.7 #321

Closed pacak closed 8 months ago

pacak commented 9 months ago

Now you can tell bpaf to ignore rust doc comments

#[derive(Debug, Clone, Bpaf)]
/// This gets ignored
#[bpaf(options, ignore_rustdoc)]
struct Options {
        #[bpaf(ignore_rustdoc, help("use this help instead")]
        /// help  // <- this gets ignored
        foo: String
}
/// those are options // <- this gets ignored in favor of explicit descr
#[bpaf(command, descr("descr"), header("header"), footer("footer"), help("help"))]
struct Opt;
ysndr commented 9 months ago

Is this a temporary workaround?

I would prefer if we had clearer priorities for which help gets displayed, i.e. (highest prio: 1, lowest: 4)

                                                            | priority
#[derive(Debug, Clone, Bpaf)]                               |
struct Options {                                            |
        #[bpaf(external, help("help attribute on usage")]   | 1 
        /// help docs on usage                              | 2
        foo: Foo                                            |
}                                                           |
                                                            |
#[derive(Debug, Clone, Bpaf)]                               |
#[bpaf(command, help("help attribute on command"))]         | 3
/// help docs on command                                    | 4
struct Foo;
pacak commented 9 months ago

Is this a temporary workaround?

I consider this to be a solution, but I can be persuaded otherwise :)

Priorities are not helping with a situation where you want to have a doc comment for some other purpose but don't want to add any help or group_help based on that.

Let's consider scenarios 1..4

Currently 1 and 2 are not supported at all: the only requirement for external annotation is that it contains a function that produces impl Parser<Foo> which doesn't support help. In practice it just uses this function to start a chain and if foo happens to implement help - it would work. Even if I add support for converting 1 and 2 into chained .help(xxx) calls - currently it won't be enough - code for foo is generated with impl Parser<Foo> so method help is not present so need to make more changes.

Adding support for 1 is not a breaking change, adding support for 2 is.

Currently 3 is not supported and 4 serves a slightly different role. This comment will show up both when you call your app with app --help to describe foo sub command and when you call your app with app foo --help to describe the sub command itself.

To summarize

  1. I can add support for this one it will take highest priority, I can probably add group_help to go along with it too.
  2. This is a breaking change, this doc comment can be parsed as either help or group_help to match the behavior of a struct comment and most likely users will have to use rustdoc_ignore to keep their code working
  3. I can add support for that and it should take priority over 4
  4. Should be already working
ysndr commented 9 months ago

Ah you're right 1 and 2 are both ignored

The only reason why that would be nice to have is for consistency:

struct Options {

    #[bpaf(flag, help("flag is doing this")]
    flag: bool,

    #[bpaf(argument, help("arg is doing that")]
    arg: String,

    #[bpaf(external, help("foo is doing foo stuff")]
    foo: Foo
}

But looking at it, its also annoying to add that foo help in multiple places (e.g. if foo is a group).

I think if we get just 3 working i can work with that.


This ignore_rustdoc helps with "accidental documentation" just for bikeshedding the wording, you add this to not have any help on an attribute (otherwise you use help("help") which takes precedence over ///, so.. how about either help() (no argument to help) or no_help instead?


The other issue #319 was about documenting "groups of groups"

/// container help
struct Container {
    #[bpaf(external)]
    group: Group
}

/// group help
enum Group {
    ...
}

I think i can solve this by just adding #[bpaf(options)] to Container i wasnt aware container().to_options() would be this substantially different..

pacak commented 9 months ago

I think if we get just 3 working i can work with that.

I'll try to add it shortly.


how about either help() (no argument to help) or no_help instead?

I thought about it, but this means also specifying group_help() or no_group_help and the user needs to pick the right one. ignore_rustdoc seem to be universal and easier to teach.


i wasnt aware container().to_options() would be this substantially different..

In one case doc comment is treated as a group help, in the other case - it's a description.

FWIW I added it here: https://github.com/pacak/bpaf/issues/150

pacak commented 9 months ago

I think if we get just 3 working i can work with that.

#[derive(Debug, Clone, Bpaf)]
#[bpaf(command, help("help attribute on command"))] // <- 3
/// help docs on command // <- 4
struct Foo;

FWIW 4 creates something like this:

pure(Foo).descr("help docs on command").to_options().command("foo")

command will fallback on embedded option parser for documentation, but not the other way around.

While 3 will generate something like this:

pure(Foo).to_options().command("foo").help("help docs on command")

You'll have to use something like this to get it to work

#[derive(Debug, Clone, Bpaf)]
#[bpaf(command, descr("help attribute on command"))]
struct Foo;
ysndr commented 9 months ago

I guess that's fine Does that also allow you to set header and footer inline?

pacak commented 9 months ago

Does that also allow you to set header and footer inline?

It should be possible even in the current version. I'm adding tests for this just in case.

pacak commented 8 months ago

@ysndr I added support for (3) overriding (4), test are passing. Can you check if it solves your problem?

ysndr commented 8 months ago

Seems to work, thanks!

The only thing I'm still confused with (no a regression of this PR) is formatting newlines:

within a `descr`  --> turns into

lorem ipsum           lorem ipsum dolor sit amet (no newline, I get that)
dolor sit amet

-------------------------------------------------------------------------

lorem ipsum           lorem ipsum                (newline, good so far) 
                      dolor sit amet. 
dolor sit amet

-------------------------------------------------------------------------

lorem ipsum           lorem ipsum                (newline, one space indented? 
                       dolor sit amet.           I guess its trying to continue
                                                 the previous (empty) line connecting 
dolor sit amet                                   it with a space?)

-------------------------------------------------------------------------

lorem ipsum           lorem ipsum                (needing 4 \n to have one empty line
                                                  was a bit unexpected)
                      dolor sit amet.            

dolor sit amet
pacak commented 8 months ago

The only thing I'm still confused with (no a regression of this PR) is formatting newlines:

If we are talking about rustdoc comments, not descr annotation by itself I'm explicitly handling only a few cases, they are listed here: https://docs.rs/bpaf/0.9.8/bpaf/struct.OptionParser.html#method.descr

If behavior is different from describing - it's a bug and I'll fix it :) Will look into that.