use std::path::PathBuf;
use anyhow::Result;
use clap::CommandFactory;
use clap_complete::Shell;
use crate::Cli;
use crate::constants;
pub fn run(shell: Shell) -> Result<()> {
let mut command = Cli::command();
let bin_name = invoked_as();
clap_complete::generate(shell, &mut command, bin_name, &mut std::io::stdout());
Ok(())
}
fn invoked_as() -> String {
std::env::args_os()
.next()
.map(PathBuf::from)
.and_then(|path| {
path.file_stem()
.map(|stem| stem.to_string_lossy().into_owned())
})
.filter(|name| !name.is_empty())
.unwrap_or_else(|| constants::APP_NAME.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_shell_produces_a_script() {
for shell in [
Shell::Bash,
Shell::Zsh,
Shell::Fish,
Shell::PowerShell,
Shell::Elvish,
] {
let mut command = Cli::command();
let mut buffer: Vec<u8> = Vec::new();
clap_complete::generate(shell, &mut command, "devp", &mut buffer);
let script = String::from_utf8(buffer).expect("completion script is UTF-8");
assert!(!script.is_empty(), "{shell} produced nothing");
assert!(
script.contains("devp"),
"{shell} script does not name the binary"
);
assert!(
script.contains("stats"),
"{shell} script is missing a subcommand"
);
}
}
#[test]
fn the_binary_name_falls_back_to_the_canonical_one() {
assert!(!invoked_as().is_empty());
}
}