🚁

clapでhelpのショートオプション(-h)を無効にする

2023/07/29に公開

概要

clapを使用してコマンドライン引数を解析する際、デフォルトで実装されているヘルプメッセージが便利だけど、(-h)が他のオプションと被ってしまうという場合にどうにかする方法。

バージョンなど

  • cargo: 1.69.0 (6e9a83356 2023-04-12)
  • clap: { version = "4.3.19", features = ["derive"] }

helpを無効にする

例えばheightという引数は(-hもしくは--height)で指定したいが、以下の場合、heighthelpのショートオプションが被ってしまってパニックになる。

use clap::Parser;

#[derive(Parser)]
struct Args {
    #[arg(short, long)]
    height: i32,
}

fn main() {
    let args = Args::parse();
    println!("height: {}", args.height);
}
$ cargo run -- -h 10
thread 'main' panicked at 'Command disable_short_help: Short option names must be unique for each argument, but '-h' is in use by both 'height' and 'help' (call `cmd.disable_help_flag(true)` to remove the auto-generated `--help`)'

(call cmd.disable_help_flag(true) to remove the auto-generated --help)

パニックメッセージには cmd.disable_help_flag(true)--help を無効にできると書いてある。
これをderiveベースのclapで書くには以下のように属性を指定する。

  use clap::Parser;

  #[derive(Parser)]
+ #[clap(disable_help_flag = true)]
  struct Args {
      #[arg(short, long)]
      height: i32,
 }

  fn main() {
      let args = Args::parse();
      println!("height: {}", args.height);
  }
$ cargo run -- -h 10
height: 10

これでheightの値が取得できるようになった。

ヘルプを表示したい

しかし、disable_help_flagを指定すると--helpも消滅してしまう。
ではどうするかというと、helpオプションを自分で定義する。

  use clap::Parser;

  #[derive(Parser)]
  #[clap(disable_help_flag = true)]
  struct Args {
      #[arg(short, long)]
      height: i32,

+     #[arg(long)]
+     help: Option<bool>,
  }

  fn main() {
      let args = Args::parse();
      println!("height: {}", args.height);
  }

これで--helpを指定できるようになったが、このままでは良しなにヘルプメッセージを表示してくれるわけではなく、ただのフラグです。
ここで独自のヘルプメッセージを実装しても良いですが、面倒ですよね。

let args = Args::parse();
if args.help {
    show_help("🤔");
}

ではどうするかというと、ArgAction::Help属性を指定する。

  use clap::Parser;

  #[derive(Parser)]
  #[clap(disable_help_flag = true)]
  struct Args {
      #[arg(short, long)]
      height: i32,

-     #[arg(long)]
+     #[arg(long, action = clap::ArgAction::Help)]
      help: Option<bool>,
  }

  fn main() {
      let args = Args::parse();
      println!("height: {}", args.height);
  }
$ cargo run -- --help
Usage: disable_short_help --height <HEIGHT>

Options:
  -h, --height <HEIGHT>
      --help

これで想定通りのヘルプメッセージを表示することができた。
ついでに arg_required_else_help 属性を付けることで無効な引数を指定したときにヘルプを表示するようにもできる。

Discussion