ewels / rich-click

Format click help output nicely with rich.
https://ewels.github.io/rich-click/
MIT License
604 stars 34 forks source link

Show commands before options #200

Open mirpedrol opened 4 months ago

mirpedrol commented 4 months ago

Hello!

Is there a way to show the command groups before the options on the help output?

We are using rich-click on nf-core with the following help output (see screenshot) and we would like to see the commands at the top, as those are more important than the options we show.

image

I would be happy to contribute if this can help. I would appreciate any pointers on how to achieve this. Thank you!

ewels commented 4 months ago

Thanks for writing this up @mirpedrol 👍🏻 I think it should basically be a question of having a config option that allows these lines to be executed in the opposite order:

https://github.com/ewels/rich-click/blob/76625934a66275b9a8f9328ffa50ea8907b62a29/src/rich_click/rich_command.py#L294-L296

I might be oversimplifying it though. And it's worth thinking about what the best way to handle this config is, I know @dwreeves you've been working on refactoring a lot of the configuration lately.. Any thoughts on this?

dwreeves commented 4 months ago

The way to do that right now without needing to wait on us would be something like this:

import rich_click as click

class CustomRichGroup(click.RichGroup):

    def format_options(self, ctx, formatter) -> None:
        from rich_click.rich_help_rendering import get_rich_options
        self.format_commands(ctx, formatter)
        get_rich_options(self, ctx, formatter)

@click.group(cls=CustomRichGroup)
def cli():
    ...

I tested this in my code and it works!

Also, I believe the above code only works for versions 1.8+; I believe in 1.7 we didn't separate out commands+options, and in prior versions subclassing was not well-supported.


We could also implement this as a config option. It will take me either until this or next weekend to get around to it, though, but it's a relatively simple change.

dwreeves commented 4 months ago

Also, I should say, if you'd like to contribute to this, you certainly can, but we need to think through implementation.

My first thought is we could do something like COMMANDS_BEFORE_OPTIONS: bool = False as a config option. I don't see anything wrong with that.

The issue though is that, in 1.9 (target release is end of year), we intended on doing a complete revamp of the "panels" functionality (currently called "groups"). See #179 for more info on that. I don't know what the implementation will ultimately end up being for panels, but a possible implementation of that might be the act of combining all panels into a single interface and distinguishing them by type, e.g. panel_type: Literal["command", "option", "argument"].

And if we opt to have panels=? as an interface for all panels, then one way to sort the panels would be something like this:

@click.group
@click.argument("bar") 
@click.option("--foo")
@click.rich_config({"show_arguments": True}, panels=["Arguments", "Commands", "Options"])  # defines order
def cli():
    ...

^ That said, if we implement this, then my suggestion of subclassing breaks in 1.9! 😆 Since we'd need to re-combine the format_options + format_commands and break from how base click does things. 🙊 No good solutions, eh....


Anyway, to bridge the gap in the meanwhile (since this is targeted for 6 months out), would could add COMMANDS_BEFORE_OPTIONS: bool = False, and the way this could work in 1.9 to preserve backwards compat is that it sorts the panels in the instance where the panels are not being sorted manually.

ewels commented 4 months ago

Anyway, to bridge the gap in the meanwhile (since this is targeted for 6 months out), would could add COMMANDS_BEFORE_OPTIONS: bool = False, and the way this could work in 1.9 to preserve backwards compat is that it sorts the panels in the instance where the panels are not being sorted manually.

This sounds like a sensible plan of action 👍🏻

Thanks @dwreeves !

mirpedrol commented 4 months ago

Hi @dwreeves, thanks for all the information! I have tried your suggestion of adding a custom CustomRichGroup class and it works great. I think we can pin the version of rich-click to 1.8.* until the new release is out. And I can also try to implement COMMANDS_BEFORE_OPTIONS: bool = False as a long term solution.