# Using `clap` Clap stands for Command Line Argument Parser, and put simply, it's a great library for making command-line stuff with Rust. Even Cargo, Rust's package manager, depends on it [4], and it's been downloaded over 300 million times [5]. Rather than going over everything clap can do, I'll go over how I've used it in my `disk-read-benchmark` program I'll be using in my next blog post. ## Basics First off, we need to install `clap`; make sure to enable its `derive` feature as that's what we'll be using. ```sh cargo add clap --features derive ``` First off, we need to get a bit of code just to start off: ```rust use clap::{Parser, Subcommand}; #[derive(Parser)] #[command(version, about, long_about = None)] pub struct Cli { #[command(subcommand)] pub command: Commands, } ``` This has the built-in "version" and "about" options, with the long "about" option disabled. Next, we need to list all out commands we'll have: ```rust #[derive(Subcommand)] pub enum Commands { ///Run this thing Run, ///Delete the stuff that thing does Delete, } ``` The documentation comments (`///`) should *not* have a space after the slashes, as otherwise the program will have an extra space where it shouldn't. Finally, we create the `main()` function. First it parses everything, then checks what command was run and runs the relevant code. ```rust fn main() { let cli = Cli::parse(); match cli.command { Commands::Run { run(); } Commands::Delete { delete(); } } } ``` That's all you need to know to use `clap` at a very basic level; for more details, check out the docs [1]. But, you probably don't want to have to type in the entire command automatically, autocomplete would be nice. So I'll also go over how to use `clap_complete` as well. ## `clap_complete` Searching through the documentation [2], you'll notice that the docs don't cover how to use it with clap's derive at all. Instead, after some Googling, I found an example script in *clap*'s repository [3], which I then adapted and played around with a bit until I got it figured out. Anyways, again, we need to install `clap_complete` first: ```sh cargo add clap_complete ``` Then, add the relevant imports. We'll just being doing it for the fish shell since that's what I use, so we'll only import `Fish`; Bash, Zsh, PowerShell, and Elvish are also supported. ```rust use clap_complete::aot::{generate, Fish}; ``` Then, we need to add a command to generate the completion: ```rust #[derive(Subcommand)] pub enum Commands { ///Run this thing Run, ///Delete the stuff that thing does Delete, ///Generate fish completions FishCompletions, } ``` Next, we actually generate the completion, adding it like it's another command: ```rust match cli.command { Commands::Run { run(); } Commands::Delete { delete(); } Commands::GenerateFishCompletions => { generate( Fish, &mut Cli::command(), "example-program", &mut stdout(), ); } } ``` To explain the options for `generate()`: - `Fish`: The shell we're using. - `&mut Cli::command()`: I don't actually know what this does, but understanding ths library fully this is beyond my pay grade, especially given the somewhat lacking docs. - `"example-program"`: The name of our program - `&mut stdout()`: `stdout`, so that it can print the completions. Why does it do it this way? I don't know, it doesn't make sense to me. Why doesn't it just return it as a String? I don't know. But it works, I suppose. As an example of all this, here's my `disk-read-benchmark` program, running using all this. The commands have formatting I can't do, so it looks even better than I can even show here. ```txt ~> disk-read-benchmark Usage: disk-read-benchmark Commands: generate-bash-completions Generate bash completions generate-zsh-completions Generate zsh completions generate-fish-completions Generate fish completions grab-data Grabs the datasets used for benchmarking benchmark Runs the benchmark prep-dirs Prepares the directories so other programs can prepare their datasets run Runs it all help Print this message or the help of the given subcommand(s) Options: -h, --help Print help -V, --version Print version ~> disk-read-benchmark generate-fish-completions | source ~> disk-read-benchmark benchmark --help Runs the benchmark Usage: disk-read-benchmark benchmark Options: -h, --help Print help ``` To better see how great it looks, here's a screenshot: ![The same output, but with very nice formatting - underlining and bolding for headers and the tables](/assets/using-clap/1.png) Pressing tab twice after entering `disk-read-benchmark` displays the completions, which I can select and use like any other program's. ```txt ~> disk-read-benchmark benchmark (Runs the benchmark) grab-data (Grabs the datasets used for benchmarking) generate-bash-completions (Generate bash completions) help (Print this message or the help of the given subcommand(s)) generate-fish-completions (Generate fish completions) prep-dirs (Prepares the directories so other programs can prepare their datasets) generate-zsh-completions (Generate zsh completions) run (Runs it all) ``` ## Sources 1. 2. 3. 4. 5.