From fda0fdd81caab1ca92eb7ed601058e6c2fdc59f5 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Sun, 21 May 2023 11:18:29 +0000 Subject: helpers and utilities --- src/cli_helpers.rs | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/cli_helpers.rs (limited to 'src/cli_helpers.rs') diff --git a/src/cli_helpers.rs b/src/cli_helpers.rs new file mode 100644 index 0000000..91f6dde --- /dev/null +++ b/src/cli_helpers.rs @@ -0,0 +1,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, + selected:Vec, + prompt: &str, + add_prompt: &str, +) -> Vec { + // add option with add_prompt + let mut options:Vec = proposed.clone(); + options.push(add_prompt.to_string()); + let mut options_selected = selected.clone(); + options_selected.push(false); + // present options + let chosen : Vec = MultiSelect::new() + .with_prompt(prompt) + .items(&options) + .defaults(&options_selected) + .report(false) + .interact() + .unwrap(); + // reduce options list + let mut new_proposed: Vec = [].to_vec(); + for (i, _el) in proposed.iter().enumerate() { + if chosen.contains(&i) { + new_proposed.push(proposed[i].clone()) + } + } + let mut new_selected: Vec = 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 = [].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) -> Result,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 = vec![]; + // for i in 0..proposed_relays.len() { + // selected.push(i < relays.len()); + // } + let selected: Vec = proposed_relays + .iter() + .enumerate() + .map(|r| r.0 < default_relays.len() ).collect(); + + // get user relay selection + let relay_selection: Vec = 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, + 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; + } + } + } + } + } + }; + } +} \ No newline at end of file -- cgit v1.2.3