codeberg_cli/render/ui/
mod.rs

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
use anyhow::Context;

pub fn multi_fuzzy_select_with_key<T>(
    items: &[T],
    prompt: impl AsRef<str>,
    is_selected: impl Fn(&T) -> bool,
    f_display: impl Fn(&T) -> String,
) -> anyhow::Result<Vec<&T>> {
    let already_selected = items
        .iter()
        .enumerate()
        .filter(|(_, elem)| is_selected(elem))
        .map(|(idx, _)| idx)
        .collect::<Vec<_>>();

    let displayed_items = items.iter().map(f_display).collect::<Vec<_>>();

    let selected_indices = inquire::MultiSelect::new(prompt.as_ref(), displayed_items)
        .with_default(&already_selected)
        .raw_prompt()
        .context("There's nothing to select from")?;

    let selected_items = selected_indices
        .into_iter()
        .map(|raw| raw.index)
        .filter_map(|idx| items.get(idx))
        .collect::<Vec<_>>();

    Ok(selected_items)
}

pub fn fuzzy_select_with_key<T>(
    items: &[T],
    prompt: impl AsRef<str>,
    f_display: impl Fn(&T) -> String,
) -> anyhow::Result<&T> {
    fuzzy_select_with_key_with_default(items, prompt, f_display, None)
}

pub fn fuzzy_select_with_key_with_default<T>(
    items: &[T],
    prompt: impl AsRef<str>,
    f_display: impl Fn(&T) -> String,
    default_index: Option<usize>,
) -> anyhow::Result<&T> {
    // return `None` if we have nothing to select from
    if items.is_empty() {
        anyhow::bail!("Nothing to select from. Aborting.")
    }

    let displayed_items = items.iter().map(f_display).collect::<Vec<_>>();

    // build standard dialogue
    let mut dialogue = inquire::Select::new(prompt.as_ref(), displayed_items);

    // optionally add default selection
    if let Some(index) = default_index {
        dialogue = dialogue.with_starting_cursor(index);
    }

    // select an item by key
    let selected_index = dialogue.raw_prompt().map_err(anyhow::Error::from)?.index;

    Ok(&items[selected_index])
}

pub fn confirm_with_prompt(prompt: &str) -> anyhow::Result<bool> {
    inquire::Confirm::new(prompt)
        .with_help_message("(y/n)?")
        .prompt()
        .map_err(anyhow::Error::from)
}