fn criteria_picker()

in src/main.rs [1086:1160]


fn criteria_picker(
    out: &Arc<dyn Out>,
    store_criteria: &SortedMap<CriteriaName, CriteriaEntry>,
    criteria_guess: Vec<CriteriaName>,
    prompt: Option<&impl AsRef<str>>,
) -> Result<Vec<CriteriaName>, CertifyError> {
    let criteria_mapper = CriteriaMapper::new(store_criteria);

    let mut chosen_criteria = criteria_guess;
    if let Some(prompt) = prompt {
        // Prompt for criteria
        loop {
            out.clear_screen()?;
            writeln!(out, "{}", prompt.as_ref());
            for (criteria_idx, criteria_name) in criteria_mapper.all_criteria_names().enumerate() {
                if chosen_criteria.iter().any(|s| s == criteria_name) {
                    writeln!(
                        out,
                        "  {}. {}",
                        criteria_idx + 1,
                        out.style().green().bold().apply_to(criteria_name)
                    );
                } else {
                    writeln!(
                        out,
                        "  {}. {}",
                        criteria_idx + 1,
                        out.style().bold().dim().apply_to(criteria_name)
                    );
                }
            }

            writeln!(out);
            writeln!(out, "current selection: {:?}", chosen_criteria);
            writeln!(out, "(press ENTER to accept the current criteria)");
            let input = out.read_line_with_prompt("> ")?;
            let input = input.trim();
            if input.is_empty() {
                if chosen_criteria.is_empty() {
                    return Err(CertifyError::NoCriteriaChosen);
                }
                // User done selecting criteria
                break;
            }

            // FIXME: these errors get cleared away right away
            let answer = if let Ok(val) = input.parse::<usize>() {
                val
            } else {
                // ERRORS: immediate error print to output for feedback, non-fatal
                writeln!(out, "error: not a valid integer");
                continue;
            };
            if answer == 0 || answer > criteria_mapper.len() {
                // ERRORS: immediate error print to output for feedback, non-fatal
                writeln!(out, "error: not a valid criteria");
                continue;
            }

            let selection = criteria_mapper.criteria_name(answer - 1).to_owned();
            if chosen_criteria.contains(&selection) {
                chosen_criteria.retain(|x| x != &selection);
            } else {
                chosen_criteria.push(selection);
            }
        }
    }

    // Round-trip this through the criteria_mapper to clean up `implies` relationships
    let criteria_set = criteria_mapper.criteria_from_list(&chosen_criteria);
    Ok(criteria_mapper
        .criteria_names(&criteria_set)
        .map(|s| s.to_owned())
        .collect::<Vec<_>>())
}