1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::config::{Catalog, CatalogEntry, CatalogError};

use crate::util::{Source, SourceError};
use crate::Archetect;
use crate::vendor::read_input::shortcut::input;
use crate::vendor::read_input::InputBuild;
use std::collections::{HashMap, HashSet};

#[derive(Debug)]
pub enum CatalogSelectError {
    EmptyCatalog,
    SourceError(SourceError),
    UnsupportedCatalogSource(String),
}

impl From<SourceError> for CatalogSelectError {
    fn from(cause: SourceError) -> Self {
        CatalogSelectError::SourceError(cause)
    }
}

pub fn you_are_sure(message: &str) -> bool {
    input::<bool>()
        .prompting_on_stderr()
        .msg(format!("{} [false]: ", message))
        .default(false)
        .get()
}

pub fn select_from_catalog(
    archetect: &Archetect,
    catalog: &Catalog,
    current_source: &Source,
) -> Result<CatalogEntry, CatalogError> {
    let mut catalog = catalog.clone();
    let mut current_source = current_source.clone();

    loop {
        if catalog.entries().is_empty() {
            return Err(CatalogError::EmptyCatalog);
        }

        let choice = select_from_entries(archetect, catalog.entries_owned())?;

        match choice {
            CatalogEntry::Catalog { description: _, source } => {
                let source = Source::detect(archetect, &source, Some(current_source))?;
                current_source = source.clone();
                catalog = Catalog::load(source)?;
            }
            CatalogEntry::Archetype {
                description: _,
                source: _,
            } => {
                return Ok(choice);
            }
            CatalogEntry::Group {
                description: _,
                entries: _,
            } => unreachable!(),
        }
    }
}

pub fn select_from_entries(
    _archetect: &Archetect,
    mut entry_items: Vec<CatalogEntry>,
) -> Result<CatalogEntry, CatalogError> {
    if entry_items.is_empty() {
        return Err(CatalogError::EmptyGroup);
    }

    loop {
        let mut choices = entry_items
            .iter()
            .enumerate()
            .map(|(id, entry)| (id + 1, entry.clone()))
            .collect::<HashMap<_, _>>();

        for (id, entry) in entry_items.iter().enumerate() {
            eprintln!("{:>2}) {}", id + 1, entry.description());
        }

        let test_values = choices.keys().map(|v| *v).collect::<HashSet<_>>();
        let result = input::<usize>()
            .prompting_on_stderr()
            .msg("\nSelect an entry: ")
            .add_test(move |value| test_values.contains(value))
            .err("Please enter the number of a selection from the list.")
            .repeat_msg("Select an entry: ")
            .get();

        let choice = choices.remove(&result).unwrap();

        match choice {
            CatalogEntry::Group {
                description: _,
                entries,
            } => {
                entry_items = entries;
            }
            CatalogEntry::Catalog {
                description: _,
                source: _,
            } => return Ok(choice),
            CatalogEntry::Archetype {
                description: _,
                source: _,
            } => return Ok(choice),
        }
    }
}