use std::io::{self, Write}; use anyhow::{Context, Result}; use clap::CommandFactory; use clap_complete::{Shell, generate}; use crate::cli::Ahab; pub fn completions(shell: Shell) -> Result<()> { let script = script(shell); let mut stdout = io::stdout().lock(); match stdout.write_all(&script).and_then(|()| stdout.flush()) { Err(e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()), result => result.context("writing the completion script"), } } fn script(shell: Shell) -> Vec { let mut cmd = Ahab::command(); let name = cmd.get_name().to_string(); let mut script = Vec::new(); generate(shell, &mut cmd, name, &mut script); script } #[cfg(test)] mod tests { use super::{Ahab, Shell, script}; use clap::{CommandFactory, ValueEnum}; #[test] fn every_shell_gets_a_script_covering_the_subcommands() { // asked of the parser rather than listed here, which is a list that // silently stops covering the newest command let subcommands: Vec = Ahab::command() .get_subcommands() .map(|sub| sub.get_name().to_string()) .collect(); assert!(subcommands.len() > 1, "{subcommands:?}"); for shell in Shell::value_variants() { let out = String::from_utf8(script(*shell)).expect("script is utf8"); for subcommand in &subcommands { assert!( out.contains(subcommand), "{shell:?} script never mentions {subcommand}" ); } } } }