fnm 1.35.0

Fast and simple Node.js version manager
use super::command::Command;
use crate::config::FnmConfig;
use crate::shell::{infer_shell, Shell};
use crate::{cli::Cli, shell::Shells};
use clap::{CommandFactory, Parser, ValueEnum};
use clap_complete::{Generator, Shell as ClapShell};
use thiserror::Error;

#[derive(Parser, Debug)]
pub struct Completions {
    /// The shell syntax to use. Infers when missing.
    #[clap(long)]
    shell: Option<Shells>,
}

impl Command for Completions {
    type Error = Error;

    fn apply(self, _config: &FnmConfig) -> Result<(), Self::Error> {
        let mut stdio = std::io::stdout();
        let shell: Box<dyn Shell> = self
            .shell
            .map(Into::into)
            .or_else(|| infer_shell().map(Into::into))
            .ok_or(Error::CantInferShell)?;
        let shell: ClapShell = shell.into();
        let app = Cli::command();
        shell.generate(&app, &mut stdio);
        Ok(())
    }
}

#[derive(Error, Debug)]
pub enum Error {
    #[error(
        "{}\n{}\n{}\n{}",
        "Can't infer shell!",
        "fnm can't infer your shell based on the process tree.",
        "Maybe it is unsupported? we support the following shells:",
        shells_as_string()
    )]
    CantInferShell,
}

fn shells_as_string() -> String {
    Shells::value_variants()
        .iter()
        .map(|x| format!("* {x}"))
        .collect::<Vec<_>>()
        .join("\n")
}