spawn-cli 0.9.0

A command-line tool for creating files and folders from a template.
use anyhow::Result;

use crate::template::{Template, config::Var};

pub(super) fn prompt<'a>(template: &'a Template<'a>, identifier: &str) -> Result<String> {
    let config = template.get_config()?;
    let var = config.get_var(identifier)?;
    let value = match var {
        Var::Text {
            identifier,
            message,
            placeholder,
            initial_value,
            default,
            ..
        } => prompt_text(
            template,
            identifier.as_ref(),
            message.as_deref(),
            placeholder.as_deref(),
            initial_value.as_deref(),
            default.as_deref(),
        )?,
        Var::Select {
            identifier: _,
            message,
            options,
            help_message,
        } => prompt_select(message.as_deref(), &options, help_message.as_deref())?,
    };

    Ok(value)
}

fn prompt_text(
    template: &Template,
    identifier: &str,
    message: Option<&str>,
    placeholder: Option<&str>,
    initial_value: Option<&str>,
    default: Option<&str>,
) -> Result<String> {
    let plugins = template.get_plugins()?;
    let message = message.unwrap_or("");
    let mut prompt = cliclack::input(message);
    if let Some(placeholder) = placeholder {
        prompt = prompt.placeholder(placeholder);
    }
    if let Some(value) = initial_value.or(default) {
        prompt = prompt.default_input(value);
    }
    let validator = {
        let plugins = plugins.clone();
        let ident = identifier.to_string();

        move |input: &String| match plugins.validate(&ident, input) {
            Ok(Ok(())) => Ok(()),
            Ok(Err(message)) => Err(message),
            Err(e) => Err(e.to_string()),
        }
    };
    let mut prompt = prompt.validate(validator);
    let value: String = prompt.interact()?;

    Ok(value)
}

fn prompt_select(
    message: Option<&str>,
    options: &[String],
    help_message: Option<&str>,
) -> Result<String> {
    let message = message.unwrap_or("");
    let mut prompt = cliclack::select(message);
    for (i, option) in options.iter().enumerate() {
        let hint = if i == 0 {
            help_message.unwrap_or("")
        } else {
            ""
        };
        prompt = prompt.item(option.clone(), option, hint);
    }
    let value = prompt.interact()?;

    Ok(value)
}