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<_>>())
}