diff --git a/src/leetcode_api_runner.rs b/src/leetcode_api_runner.rs index a11e4cb..4719915 100644 --- a/src/leetcode_api_runner.rs +++ b/src/leetcode_api_runner.rs @@ -23,12 +23,22 @@ pub struct LeetcodeApiRunner { } impl LeetcodeApiRunner { - pub async fn new(rcs: &RuntimeConfigSetup) -> Self { - let api = UserApi::new(&rcs.config.leetcode_token).await.unwrap(); - LeetcodeApiRunner { + pub async fn new(rcs: &RuntimeConfigSetup) -> Result { + Ok(LeetcodeApiRunner { rcs: rcs.clone(), - api, - } + api: UserApi::new(&rcs.config.leetcode_token).await.map_err( + |_| { + io::Error::new( + io::ErrorKind::NotConnected, + format!( + "An error occurred while creating the API client. \ + Check your token in your configuration file: {}", + rcs.config_file.display() + ), + ) + }, + )?, + }) } pub async fn get_problem_info(&self, id: u32) -> io::Result { @@ -46,6 +56,26 @@ impl LeetcodeApiRunner { Ok(format!("{} {}: {}\n{}", id, difficulty, title, description)) } + /// Fetches the problem name by its ID. + pub async fn get_problem_name(&self, id: u32) -> io::Result { + let pb = self.api.set_problem_by_id(id).await.unwrap(); + Ok(pb.description().unwrap().name.clone()) + } + + /// Fetches the available languages for a given problem ID. + pub async fn get_available_languages( + &self, id: &u32, + ) -> io::Result> { + let problem = self.api.set_problem_by_id(*id).await?; + + Ok(problem + .code_snippets() + .expect("No code snippets found.") + .iter() + .map(|snippet| snippet.langSlug.clone()) + .collect::>()) + } + pub async fn start_problem( &self, id: u32, language: ProgrammingLanguage, ) -> io::Result { diff --git a/src/main.rs b/src/main.rs index e7b22c8..2d748ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use clap::Parser; use leetcode_cli::{ utils::{ parse_programming_language, + prompt_for_language, spin_the_spinner, }, Cli, @@ -15,7 +16,7 @@ async fn main() -> Result<(), Box> { let cli = Cli::parse(); let mut rcs = RuntimeConfigSetup::new(); rcs.status()?; - let api_runner = LeetcodeApiRunner::new(&rcs).await; + let api_runner = LeetcodeApiRunner::new(&rcs).await?; match &cli.command { Commands::Info { @@ -33,11 +34,29 @@ async fn main() -> Result<(), Box> { id, language, } => { - let default = &rcs.config.default_language.unwrap(); - let lang = match language { - Some(lang) => parse_programming_language(lang)?, - None => parse_programming_language(default)?, + let default_lang = rcs + .config + .default_language + .clone() + .unwrap_or_else(|| "not found".to_string()); + let mut lang = match language { + Some(lang) => parse_programming_language(lang), + None => parse_programming_language(&default_lang), }; + let mut spin = spin_the_spinner("Gathering problem info..."); + let problem_name = api_runner.get_problem_name(*id).await?; + let available_languages = + api_runner.get_available_languages(&id).await?; + spin.stop(); + while lang.is_err() { + lang = prompt_for_language( + id, + &problem_name, + &available_languages, + ) + .and_then(|lang| parse_programming_language(&lang)); + } + let lang = lang.unwrap(); let mut spin = spin_the_spinner("Starting problem setup..."); let start_problem = api_runner.start_problem(*id, lang).await; spin.stop(); diff --git a/src/utils.rs b/src/utils.rs index feb87da..25b1a10 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -34,7 +34,7 @@ pub fn write_to_file( pub fn parse_programming_language( lang: &str, -) -> Result { +) -> Result { match lang.to_ascii_lowercase().as_str() { "cpp" | "c++" => Ok(leetcoderustapi::ProgrammingLanguage::CPP), "java" => Ok(leetcoderustapi::ProgrammingLanguage::Java), @@ -62,7 +62,10 @@ pub fn parse_programming_language( "dart" => Ok(leetcoderustapi::ProgrammingLanguage::Dart), "pandas" => Ok(leetcoderustapi::ProgrammingLanguage::Pandas), "react" => Ok(leetcoderustapi::ProgrammingLanguage::React), - _ => Err(format!("Unsupported language: {}", lang)), + _ => Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("Unsupported language: {}", lang), + )), } } @@ -159,3 +162,27 @@ pub fn extension_programming_language( pub fn spin_the_spinner(message: &str) -> spinners::Spinner { spinners::Spinner::new(spinners::Spinners::Dots12, message.to_string()) } + +pub fn prompt_for_language( + id: &u32, problem_name: &str, available_languages: &[String], +) -> Result { + println!( + "\nPlease enter a valid Leetcode programming language.\nHere is a \ + list of available languages for the problem {} - {}\n{}", + id, + problem_name, + available_languages + .iter() + .map(|l| l.to_string()) + .collect::>() + .join(", ") + ); + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + let trimmed = input.trim().to_string(); + if trimmed.is_empty() { + Err(io::Error::new(io::ErrorKind::InvalidInput, "No language entered")) + } else { + Ok(trimmed) + } +}