projm 0.3.2

Project organizer and fuzzy navigator for developers — classify, group, and jump to projects from the terminal
Documentation
use anyhow::Result;
use clap::CommandFactory;
use clap_complete::{generate, shells, Generator};

use crate::main_cli::Cli;

#[derive(clap::ValueEnum, Clone, Debug)]
pub enum CompletionShell {
    Zsh,
    Bash,
    Fish,
    Powershell,
}

pub fn emit(shell: CompletionShell) -> Result<()> {
    let mut cmd = Cli::command();
    match shell {
        CompletionShell::Zsh => write_generated(shells::Zsh, &mut cmd),
        CompletionShell::Bash => write_generated(shells::Bash, &mut cmd),
        CompletionShell::Fish => write_generated(shells::Fish, &mut cmd),
        CompletionShell::Powershell => write_generated(shells::PowerShell, &mut cmd),
    }
}

pub fn zsh_script() -> Result<String> {
    let mut cmd = Cli::command();
    generate_to_string(shells::Zsh, &mut cmd)
}

pub fn powershell_script() -> Result<String> {
    let mut cmd = Cli::command();
    generate_to_string(shells::PowerShell, &mut cmd)
}

fn write_generated<G: Generator>(generator: G, cmd: &mut clap::Command) -> Result<()> {
    let name = cmd.get_name().to_string();
    let mut stdout = std::io::stdout();
    generate(generator, cmd, name, &mut stdout);
    Ok(())
}

fn generate_to_string<G: Generator>(generator: G, cmd: &mut clap::Command) -> Result<String> {
    let name = cmd.get_name().to_string();
    let mut buf: Vec<u8> = Vec::new();
    generate(generator, cmd, name, &mut buf);
    Ok(String::from_utf8(buf)?)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn zsh_script_contains_command_name() {
        let script = zsh_script().expect("zsh completion script should be generated");
        assert!(script.contains("projm"));
    }

    #[test]
    fn powershell_script_contains_command_name() {
        let script = powershell_script().expect("powershell completion script should be generated");
        assert!(script.contains("projm"));
    }
}