rustclap

Divide subcommands into groups using Clap


I am trying to create a CLI using Clap that contains a relatively large number of subcommands.From the documentation, I would have expected the following to work:

#[derive(Parser)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
    /// Determine reads mapping to sample-specific MAGs
    #[command(subcommand_help_heading = "FirstHeading")]
    Subcommand1(Subcommand1Args),

    /// Create sketches from FASTA/Q file(s)
    #[command(subcommand_help_heading = "SecondHeading")]
    Subcommand2(Subcommand2Args),
}

However, the subcommand_help_heading arguments do not change the CLI. I'm expecting the output to be similar to:

My command line interface.

Usage: my_program <COMMAND>

FirstHeading:
  subcommand1  ...

SecondHeading:
  subcommand2 ...

Options:
  -h, --help     Print help
  -V, --version  Print version


Solution

  • The usage text in clap has one section for subcommands, and therefore one heading. It shows all the available subcommands. You can set that header with subcommand_help_heading, so if your Commands struct had this additional attribute:

    #[derive(Subcommand)]
    #[command(subcommand_help_heading = "MyAwesomeHeading")]
    pub enum Commands {
      // ... snip ...
    }
    

    you would get, for --help:

    My command line interface.
    
    Usage: my_program <COMMAND>
    
    MyAwesomeHeading:
      subcommand1  Determine reads mapping to sample-specific MAGs
      subcommand2  Create sketches from FASTA/Q file(s)
      help         Print this message or the help of the given subcommand(s)
    
    Options:
      -h, --help  Print help
    

    As far as I can see there's no easy way to tell clap to include multiple subcommand headings in the main help text. But if you have multiple nested subcommands inside of your commands, then you can control the help text for them. For example, say we define the Subcommand1Args as:

    #[derive(Parser)]
    pub struct Subcommand1Args {
        #[command(subcommand)]
        sub: Subcommands1,
    }
    
    #[derive(Subcommand)]
    pub enum Subcommands1 {
        // Do A
        A,
        // Do B
        B(IntArg)
    }
    
    #[derive(Parser)]
    pub struct IntArg {
        arg: u32
    }
    

    Then by using subcommand1 --help you get:

    Determine reads mapping to sample-specific MAGs
    
    Usage: playground subcommand1 <COMMAND>
    
    FirstHeading:
      a     Do A
      b     Do B
      help  Print this message or the help of the given subcommand(s)
    
    Options:
      -h, --help  Print help
    

    You can see the FirstHeading value from subcommand_help_heading applied for Subcommand1 being used here.

    Subcommands are basically nested sub-clis, and they get their own help pages.

    Full code in play.rust-lang.