upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/bin/ngit/sub_commands/init.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-08-07 17:52:22 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2025-08-07 17:52:22 +0100
commit92c2362a9bed1bc1f256e7948e087c4102b7c4f9 (patch)
tree700bf840ba52a8bd576afcfbe532a669f104dfcb /src/bin/ngit/sub_commands/init.rs
parent8724af191f520a822214109f75a1851856c74fd2 (diff)
parentfa7adf840ac2d78defee398a61b60888f615622a (diff)
Merge branch 'add-prs-to-ngit-send'
Diffstat (limited to 'src/bin/ngit/sub_commands/init.rs')
-rw-r--r--src/bin/ngit/sub_commands/init.rs137
1 files changed, 24 insertions, 113 deletions
diff --git a/src/bin/ngit/sub_commands/init.rs b/src/bin/ngit/sub_commands/init.rs
index eaaf83d..98daee4 100644
--- a/src/bin/ngit/sub_commands/init.rs
+++ b/src/bin/ngit/sub_commands/init.rs
@@ -9,15 +9,17 @@ use std::{
9 9
10use anyhow::{Context, Result, bail}; 10use anyhow::{Context, Result, bail};
11use console::{Style, Term}; 11use console::{Style, Term};
12use dialoguer::theme::{ColorfulTheme, Theme};
13use ngit::{ 12use ngit::{
14 UrlWithoutSlash, 13 UrlWithoutSlash,
15 cli_interactor::{PromptChoiceParms, PromptConfirmParms, PromptMultiChoiceParms}, 14 cli_interactor::{
15 PromptChoiceParms, PromptConfirmParms, multi_select_with_custom_value,
16 show_multi_input_prompt_success,
17 },
16 client::{Params, send_events}, 18 client::{Params, send_events},
17 git::nostr_url::{CloneUrl, NostrUrlDecoded}, 19 git::nostr_url::{CloneUrl, NostrUrlDecoded},
18 repo_ref::{ 20 repo_ref::{
19 detect_existing_grasp_servers, extract_npub, extract_pks, normalize_grasp_server_url, 21 detect_existing_grasp_servers, extract_npub, extract_pks,
20 save_repo_config_to_yaml, 22 format_grasp_server_url_as_relay_url, normalize_grasp_server_url, save_repo_config_to_yaml,
21 }, 23 },
22}; 24};
23use nostr::{ 25use nostr::{
@@ -266,11 +268,23 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
266 ); 268 );
267 let mut selections: Vec<bool> = vec![true; options.len()]; // Initialize selections based on existing options 269 let mut selections: Vec<bool> = vec![true; options.len()]; // Initialize selections based on existing options
268 let empty = options.is_empty(); 270 let empty = options.is_empty();
271 for user_grasp_option in user_ref.grasp_list.urls {
272 // Check if any option contains the user_grasp_option as a substring
273 if !options
274 .iter()
275 .any(|option| option.contains(user_grasp_option.as_str()))
276 {
277 options.push(user_grasp_option.to_string()); // Add if not found
278 selections.push(empty); // mark as selected if no existing grasp otherwise not
279 }
280 }
281
282 let empty = options.is_empty();
269 for fallback in fallback_grasp_servers { 283 for fallback in fallback_grasp_servers {
270 // Check if any option contains the fallback as a substring 284 // Check if any option contains the fallback as a substring
271 if !options.iter().any(|option| option.contains(fallback)) { 285 if !options.iter().any(|option| option.contains(fallback)) {
272 options.push(fallback.clone()); // Add fallback if not found 286 options.push(fallback.clone()); // Add fallback if not found
273 selections.push(empty); // mark as selected if no existing ngit relay otherwise not 287 selections.push(empty); // mark as selected if no existing selections otherwise not
274 } 288 }
275 } 289 }
276 let selected = multi_select_with_custom_value( 290 let selected = multi_select_with_custom_value(
@@ -727,6 +741,11 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
727 web, 741 web,
728 relays: relays.clone(), 742 relays: relays.clone(),
729 blossoms, 743 blossoms,
744 hashtags: if let Some(repo_ref) = repo_ref {
745 repo_ref.hashtags
746 } else {
747 vec![]
748 },
730 trusted_maintainer: user_ref.public_key, 749 trusted_maintainer: user_ref.public_key,
731 maintainers_without_annoucnement: None, 750 maintainers_without_annoucnement: None,
732 maintainers: maintainers.clone(), 751 maintainers: maintainers.clone(),
@@ -848,93 +867,6 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
848 Ok(()) 867 Ok(())
849} 868}
850 869
851fn multi_select_with_custom_value<F>(
852 prompt: &str,
853 custom_choice_prompt: &str,
854 mut choices: Vec<String>,
855 mut defaults: Vec<bool>,
856 validate_choice: F,
857) -> Result<Vec<String>>
858where
859 F: Fn(&str) -> Result<String>,
860{
861 let mut selected_choices = vec![];
862
863 // Loop to allow users to add more choices
864 loop {
865 // Add 'add another' option at the end of the choices
866 let mut current_choices = choices.clone();
867 current_choices.push(if current_choices.is_empty() {
868 "add".to_string()
869 } else {
870 "add another".to_string()
871 });
872
873 // Create default selections based on the provided defaults
874 let mut current_defaults = defaults.clone();
875 current_defaults.push(current_choices.len() == 1); // 'add another' should not be selected by default
876
877 // Prompt for selections
878 let selected_indices: Vec<usize> = Interactor::default().multi_choice(
879 PromptMultiChoiceParms::default()
880 .with_prompt(prompt)
881 .dont_report()
882 .with_choices(current_choices.clone())
883 .with_defaults(current_defaults),
884 )?;
885
886 // Collect selected choices
887 selected_choices.clear(); // Clear previous selections to update
888 for &index in &selected_indices {
889 if index < choices.len() {
890 // Exclude 'add another' option
891 selected_choices.push(choices[index].clone());
892 }
893 }
894
895 // Check if 'add another' was selected
896 if selected_indices.contains(&(choices.len())) {
897 // Last index is 'add another'
898 let mut new_choice: String;
899 loop {
900 new_choice = Interactor::default().input(
901 PromptInputParms::default()
902 .with_prompt(custom_choice_prompt)
903 .dont_report()
904 .optional(),
905 )?;
906
907 if new_choice.is_empty() {
908 break;
909 }
910 // Validate the new choice
911 match validate_choice(&new_choice) {
912 Ok(valid_choice) => {
913 new_choice = valid_choice; // Use the fixed version of the input
914 break; // Valid choice, exit the loop
915 }
916 Err(err) => {
917 // Inform the user about the validation error
918 println!("Error: {err}");
919 }
920 }
921 }
922
923 // Add the new choice to the choices vector
924 if !new_choice.is_empty() {
925 choices.push(new_choice.clone()); // Add new choice to the end of the list
926 selected_choices.push(new_choice); // Automatically select the new choice
927 defaults.push(true); // Set the new choice as selected by default
928 }
929 } else {
930 // Exit the loop if 'add another' was not selected
931 break;
932 }
933 }
934
935 Ok(selected_choices)
936}
937
938fn format_grasp_server_url_as_clone_url( 870fn format_grasp_server_url_as_clone_url(
939 url: &str, 871 url: &str,
940 public_key: &PublicKey, 872 public_key: &PublicKey,
@@ -953,14 +885,6 @@ fn format_grasp_server_url_as_clone_url(
953 )) 885 ))
954} 886}
955 887
956fn format_grasp_server_url_as_relay_url(url: &str) -> Result<String> {
957 let grasp_server_url = normalize_grasp_server_url(url)?;
958 if grasp_server_url.contains("http://") {
959 return Ok(grasp_server_url.replace("http://", "ws://"));
960 }
961 Ok(format!("wss://{grasp_server_url}"))
962}
963
964fn format_grasp_server_url_as_blossom_url(url: &str) -> Result<String> { 888fn format_grasp_server_url_as_blossom_url(url: &str) -> Result<String> {
965 let grasp_server_url = normalize_grasp_server_url(url)?; 889 let grasp_server_url = normalize_grasp_server_url(url)?;
966 if grasp_server_url.contains("http://") { 890 if grasp_server_url.contains("http://") {
@@ -982,19 +906,6 @@ fn parse_relay_url(s: &str) -> Result<RelayUrl> {
982 .context(format!("failed to parse relay url: {s}")) 906 .context(format!("failed to parse relay url: {s}"))
983} 907}
984 908
985pub fn show_multi_input_prompt_success(label: &str, values: &[String]) {
986 let values_str: Vec<&str> = values.iter().map(std::string::String::as_str).collect();
987 eprintln!("{}", {
988 let mut s = String::new();
989 let _ = ColorfulTheme::default().format_multi_select_prompt_selection(
990 &mut s,
991 label,
992 &values_str,
993 );
994 s
995 });
996}
997
998fn push_main_or_master_branch(git_repo: &Repo) -> Result<()> { 909fn push_main_or_master_branch(git_repo: &Repo) -> Result<()> {
999 let main_branch_name = { 910 let main_branch_name = {
1000 let local_branches = git_repo 911 let local_branches = git_repo