TL;DR
この記事では、dialoguerというRustのライブラリを使って、Gitコマンドを実行するためのCLIツールを作成する方法を紹介します。
dialoguerは、Rustでインタラクティブなコマンドラインツールを作成するためのライブラリです。このライブラリを使うことで、非常に簡単な実装ではあるものの比較的にUXの良いCLIツールを作成することができると感じました。
作ったもの
「git-wizard」は、Gitコマンドを実行するためのインタラクティブなCLIツールです。ユーザーはツールのメニューから実行したいGitコマンドを選択し、簡単な操作でGitの基本的なコマンドを実行できます。例えば、git add
、git commit
、git push
、git status
、git branch
などの操作を手軽に行うことができます。
Vim風の操作感
dialoguerを使うと自動的にVimの使用感を持つCLIツールを作成することができます。例えば、j
を押すと下に移動し、k
を押すと上に移動するなど、Vimのキーバインドに似た操作が可能です。
- 具体コード:
このあたりの実装がcrateの中で行われているのが、とても使い勝手がよく素晴らしいと感じました。
作ったもののコード
メイン部分
main
関数では、ユーザーに対してコマンドの選択肢を表示し、その選択に応じて適切なGitコマンドを実行します。
fn main() {
let options = vec![
"ステージング (git add)",
"コミット (git commit)",
];
let term = Term::stderr();
println!("Git Wizardへようこそ!\n");
loop {
// メニューの選択
let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt("実行したいGitコマンドを選んでください (:q で終了)")
.items(&options)
.default(0)
.interact_on_opt(&term)
.unwrap();
match selection {
Some(index) => match index {
0 => {
// git add
let files = user_input_with_exit(&term, "ステージングしたいファイル/ディレクトリを指定してください (例: .)");
execute_command("git", &["add", &files]);
}
1 => {
// git commit
let message = user_input_with_exit(&term, "コミットメッセージを入力してください");
execute_command("git", &["commit", "-m", &message]);
}
_ => {
println!("不明な選択肢です。");
}
},
None => {
// 選択をキャンセル(Ctrl+CやESCが押された場合)
println!("終了します。");
break;
}
}
}
}
ユーザーが選択したコマンドに応じて、対応するGitコマンドを実行を行います。
ユーザー入力の取得
user_input_with_exit
関数では、:q
と入力された場合に終了する機能を備えつつ、ユーザーからの入力を受け付けます。
fn user_input_with_exit(term: &Term, prompt: &str) -> String {
loop {
let input: String = Input::new()
.with_prompt(prompt)
.allow_empty(true)
.interact_text()
.unwrap();
if input.trim() == ":q" {
println!("終了します。");
term.clear_last_lines(1).unwrap();
std::process::exit(0);
}
if !input.trim().is_empty() {
return input;
}
}
}
コマンドの実行
execute_command
関数は、指定されたコマンドを実行し、その結果を標準出力や標準エラーに表示します。
fn execute_command(command: &str, args: &[&str]) {
println!("\n実行中: {} {}\n", command, args.join(" "));
let output = Command::new(command)
.args(args)
.output();
match output {
Ok(output) => {
if !output.stdout.is_empty() {
println!("{}", String::from_utf8_lossy(&output.stdout));
}
if !output.stderr.is_empty() {
eprintln!("{}", String::from_utf8_lossy(&output.stderr));
}
}
Err(e) => {
eprintln!("コマンドの実行に失敗しました: {}", e);
}
}
}
最後に
RustのCLIツールを初めて作成したのですが、dialoguerを使うことで非常に簡単にインタラクティブなCLIツールを作成することができました。また、Vim風の操作感を持つことで、より使いやすいツールを作成することができたと感じました。
今までPythonやGoでCLIツールを作成していましたが、RustにもCLIツールを作成するための優れたライブラリがあることを知り、今後もRustを使ってCLIツールを作成していきたいと思います。