引き続きCLIシリーズの紹介です
cliを作ったはいいものの、やはりコマンドのシェル補完はないと厳しいですよね。
structoptで作ったCLIでも簡単に補完のスクリプトを生成できるようになっています。 structoptのベースであるclap側にその機能があり、それをstructoptで呼び出すという感じです。
structopt
早速コードを見ていきましょう。 以下はec2-searchのコードを一部省いて載せています。
use std::io; use structopt::clap::Shell; use structopt::StructOpt; #[derive(Debug, StructOpt)] struct Cli { #[structopt(subcommand)] cmd: Command, } #[derive(Debug, StructOpt)] enum Command { #[structopt(about = "Prints version information")] Version, #[structopt(about = "Prints Completion")] Completion(CompletionOpt), } #[derive(Debug, StructOpt)] enum CompletionOpt { Zsh, Bash, Fish, } #[tokio::main] async fn main() { match Cli::from_args().cmd { Command::Version => version(), Command::Completion(opt) => match opt { CompletionOpt::Bash => completion(Shell::Bash), CompletionOpt::Zsh => completion(Shell::Zsh), CompletionOpt::Fish => completion(Shell::Fish), }, } } fn version() { println!("ec2-search {}", env!("CARGO_PKG_VERSION")) } fn completion(s: Shell) { Cli::clap().gen_completions_to(env!("CARGO_BIN_NAME"), s, &mut io::stdout()) }
Cli::clap()
でclapの関数を呼べるようになっているので、これで補完スクリプトを生成する gen_completions_to
を呼び出します。
生成したものを標準出力に出したいので、stdoutに吐いています。
実際のコードは以下リンク先です。
homebrewに対応
brewでインストールさせている場合、tapのスクリプトに以下を設定することでインストール時にシェルのcompletionの設定ができます
def install bin.install 'ec2s' # bash completion output = Utils.safe_popen_read("#{bin}/ec2s", 'completion', 'bash') (bash_completion / 'ec2s').write output # zsh completion output = Utils.safe_popen_read("#{bin}/ec2s", 'completion', 'zsh') (zsh_completion / '_ec2s').write output end
この記述は何をしているかというとbashとzshの補完スクリプトを各シェルの補完用ディレクトリに保存しています。 実際には以下のようなコマンドを実行しているのと等価です。
bashの場合
$ ec2s completion bash > /usr/local/etc/bash_completion.d/ec2s
zshの場合
$ ec2s completion zsh > /usr/local/share/zsh/site-functions/_ec2s
実際のコードは以下リンクです
ハマったところ
clapには conflicts_with
というオプションを複数指定した場合に使っていないオプションを指定していると以下のような実行時エラーが発生します。
$ cargo run completion zsh Compiling ec2-search v0.9.1 (/Users/yuto/GitHub/ec2-search) Finished dev [unoptimized + debuginfo] target(s) in 26.67s Running `target/debug/ec2s completion zsh` thread 'main' panicked at 'Fatal internal error. Please consider filing a bug report at https://github.com/clap-rs/clap/issues', /Users/yuto/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-2.33.3/src/completions/zsh.rs:346:29 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
denoでも同じようなバグが発生しているので、 conflicts_with
を使う場合気をつけましょう。
以下のように生成部分をテストに含めて壊れないかチェックしておくとよいでしょう。 https://github.com/mocyuto/ec2-search/blob/v0.9.1/src/main.rs#L56-L61