upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/cli_helpers.rs
blob: 91f6dde53ea26737969bd6814c8af4dfea1aa995 (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use confy::ConfyError;
use dialoguer::{theme::ColorfulTheme, Input, MultiSelect, Confirm};
use nostr::{EventId, prelude::{Nip19Event, FromBech32}};

use crate::config::{MyConfig, save_conifg};
/// Renders a dialoguer multi select prompt with a free-form option
pub fn multi_select_with_add(
    proposed:Vec<String>,
    selected:Vec<bool>,
    prompt: &str,
    add_prompt: &str,
) -> Vec<String> {
    // add option with add_prompt
    let mut options:Vec<String> = proposed.clone();
    options.push(add_prompt.to_string());
    let mut options_selected = selected.clone();
    options_selected.push(false);
    // present options
    let chosen : Vec<usize> = MultiSelect::new()
        .with_prompt(prompt)
        .items(&options)
        .defaults(&options_selected)
        .report(false)
        .interact()
        .unwrap();
    // reduce options list
    let mut new_proposed: Vec<String> = [].to_vec();
    for (i, _el) in proposed.iter().enumerate() {
        if chosen.contains(&i) {
            new_proposed.push(proposed[i].clone())
        }
    }
    let mut new_selected: Vec<bool> = vec![true;new_proposed.len()];
    // if add_prompt selected
    let last = chosen.last();
    if last == None || *last.unwrap() == options.len() - 1 {
        // get user to input new item
        let new_relay: String = Input::with_theme(&ColorfulTheme::default())
            .with_prompt(add_prompt)
            .report(false)
            .interact_text()
            .unwrap();
        // prepare new proposed options
        // if new item is not blank add it as a selected option
        if new_relay.len() > 0 {
            new_proposed.push(new_relay);
            new_selected.push(true);
        }
        // re run selection
        return multi_select_with_add(
            new_proposed,
            new_selected,
            prompt,
            add_prompt,
        )
    }
    else {
        let mut items: Vec<String> = [].to_vec();
        for i in chosen {
            items.push(options[i].clone());
        }
        println!("{}: {:?}",prompt,items);
        return items;
    }
}

pub fn select_relays(cfg:&mut MyConfig, selected_defaults:&Vec<String>) -> Result<Vec<String>,ConfyError> {
    // set default relays (selected by default)
    let default_relays =
        if selected_defaults.is_empty() { cfg.default_relays.clone() }
        else { selected_defaults.clone() };
    // set full proposed list
    let mut proposed_relays = default_relays.clone();
    // add config defaults to proposed unless duplicate
    for s in &cfg.default_relays {
        if !(proposed_relays.iter().any(|df| s.eq(df))) {
            proposed_relays.push(s.clone());
        }
    }
    // add example options to proposed list unless duplicate
    for s in vec![
        String::from("wss://relay.damus.io"),
        String::from("wss://nostr.wine"),
        String::from("wss://nos.lol"),
    ] {
        if !(proposed_relays.iter().any(|df| s.eq(df))) {
            proposed_relays.push(s.clone());
        }
    }
    // select only cli attribute relays or thie first in the proposed list
    // this does the same thing but which is more idiumatic?
    // let mut selected: Vec<bool> = vec![];
    // for i in 0..proposed_relays.len() {
    //     selected.push(i < relays.len());
    // }
    let selected: Vec<bool> = proposed_relays
        .iter()
        .enumerate()
        .map(|r| r.0 < default_relays.len() ).collect();

    // get user relay selection 
    let relay_selection: Vec<String> = crate::cli_helpers::multi_select_with_add(
        proposed_relays,
        selected,
        "Relays",
        "Other Relay"
    );

    // offer to save as default config
    if relay_selection.ne(&cfg.default_relays) {
        if Confirm::with_theme(&ColorfulTheme::default())
        .with_prompt("Save relays as ngit default?")
        .default(true)
        .interact()
        .unwrap() {
            cfg.default_relays = relay_selection.clone();
            save_conifg(&cfg);
        }
    }
    Ok(relay_selection)
}

pub fn valid_event_id_from_input(
    proposed_event_id: Option<String>,
    prompt:&String,
) -> EventId {
    let mut string_param = proposed_event_id.clone();
    loop {
        string_param = match string_param {
            None => {
                let response: String = Input::with_theme(&ColorfulTheme::default())
                    .with_prompt(prompt.clone())
                    .report(true)
                    .interact_text()
                    .unwrap();
                Some(response)
            }
            Some(ref s) => { Some(s.clone()) },
        };

        let _valid_id = match Nip19Event::from_bech32(&string_param.clone().unwrap()) {
            Ok(n19) => { break n19.event_id }
            Err(_) => {
                match EventId::from_bech32(&string_param.clone().unwrap()) {
                    Ok(id) => { break id }
                    Err(_) => {
                        match EventId::from_hex(&string_param.clone().unwrap()) {
                            Ok(id) => { break id }
                            Err(_) => {
                                println!("not a valid nevent, note or hex string. try again.");
                                string_param = None;
                                continue;
                            }
                        }
                    }
                }
            }
        };
    }
}