diff --git a/src/commands/common.rs b/src/commands/common.rs index de4e721..4dc779a 100644 --- a/src/commands/common.rs +++ b/src/commands/common.rs @@ -66,3 +66,10 @@ where println!("Input was parsed from: {} into {:?}", input, output); Ok((input, output)) } + +pub fn get_lc_dir() -> Result { + use std::env; + let key = "LEETCODE_DIR"; + // val is the top level directory for the leetcode directory + env::var(key).map_err(|e| e.into()) +} diff --git a/src/commands/new.rs b/src/commands/new.rs index 7865d2a..e8a01f8 100644 --- a/src/commands/new.rs +++ b/src/commands/new.rs @@ -1,6 +1,7 @@ use std::{io::Write, str::FromStr}; -use super::common::{GQL_ENDPOINT, SESSION, TOKEN}; + +use super::common::{GQL_ENDPOINT, SESSION, TOKEN, get_lc_dir}; use anyhow::Result; use regex::Regex; use reqwest::Url; @@ -234,13 +235,7 @@ pub fn parse_from_json_to_problem(json: serde_json::Value) -> Result { } pub fn create_entry(prob: Problem) -> Result<()> { - // this should do all of the OS things like making a directory and editing files - // reference the old bash script for this - // - use std::env; - let key = "LEETCODE_DIR"; - // val is the top level directory for the leetcode directory - let lc_dir = env::var(key)?; + let lc_dir = get_lc_dir()?; // first check if the problem exists already in the Cargo.toml let cargo_path = format!("{}{}", lc_dir, "/Cargo.toml"); diff --git a/src/commands/tag.rs b/src/commands/tag.rs index ee6de83..c336deb 100644 --- a/src/commands/tag.rs +++ b/src/commands/tag.rs @@ -1,6 +1,14 @@ +use anyhow::Result; use clap::{Parser, ValueEnum}; +use regex::Regex; +use std::{ + fs::File, + io::{BufReader, Write}, +}; use strum::{EnumString, IntoStaticStr}; +use super::common::{get_lc_dir, prompt_for_input}; + #[derive(Debug, Clone, Parser, EnumString, IntoStaticStr)] pub enum TagType { // #[strum(serialize = "stack", serialize = "")] @@ -45,3 +53,102 @@ impl ValueEnum for TagCommand { &[Self::Add, Self::Remove, Self::Edit, Self::Search] } } + +impl std::fmt::Display for TagType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +pub fn tag_subcommands(cmd: &TagCommand) -> Result<()> { + match cmd { + TagCommand::Add => { + // FLAGS + // ************************************************************ + // Add should take a number and a tag/[tags] + // to apply to a problem referenced by the number provided + // + // PROMPTS + // ************************************************************ + // should prompt for a tag and a problem number + let lc_dir = get_lc_dir()?; + let (_input_tag, tag) = prompt_for_input::("Enter Tag to add: ")?; + + let (_input_num, num) = + prompt_for_input::("Enter Problem Number to add Tag to: ")?; + + let problem_dir = format!("{}{}{}", lc_dir, "src/", num); + let tag_path = format!("{}{}", problem_dir, "/TAGS"); + let tag_file = std::fs::read_to_string(tag_path.clone())?; + + // search for that tag in the problem, if it already exists, return an error of that + let re = Regex::new(format!(r"{}", tag).as_str()).unwrap(); + if let Some(_a) = re.captures(tag_file.as_str()) { + return Err(anyhow::Error::msg(format!( + "Tag `{tag}` already exists for this problem!" + ))); + } else { + let mut file = std::fs::OpenOptions::new().append(true).open(tag_path)?; + writeln!(file, "{}", tag.to_string())?; + } + + println!("Tag: {tag:?} was added to Problem: {num}"); + Ok(()) + } + TagCommand::Remove => { + // FLAGS + // ************************************************************ + // should take a number and a tag/[tags] to remove the tags from said problem + // + // PROMPTS + // ************************************************************ + // should prompt for a tag and a problem number + + let lc_dir = get_lc_dir()?; + + let (_input_num, num) = + prompt_for_input::("Enter Problem Number to remove a Tag from: ")?; + + let prompt = format!("Enter Tag to remove from Problem {}: ", num); + let (_input_tag, tag) = prompt_for_input::(prompt.as_str())?; + + let problem_dir = format!("{}{}{}", lc_dir, "src/", num); + let tag_path = format!("{}{}", problem_dir, "/TAGS"); + let tag_file = std::fs::read_to_string(tag_path.clone())?; + + // file contents without the tag that is to be removed + let mut buf = Vec::new(); + for line in tag_file.lines() { + if line.to_string() != tag.to_string() { + buf.push(line); + } + } + let buf = buf.join("\n"); + + let re = Regex::new(format!(r"{}", tag).as_str()).unwrap(); + + if let Some(_a) = re.captures(tag_file.as_str()) { + let mut file = std::fs::OpenOptions::new() + .write(true) + .truncate(true) + .open(tag_path)?; + writeln!(file, "{}", buf)?; + } else { + return Err(anyhow::Error::msg(format!( + "Tag `{tag}` doesn't exist for this problem!" + ))); + } + println!("Tag: {tag:?} was removed from Problem: {num}"); + Ok(()) + } + TagCommand::Edit => { + // should just take a number and then give a list of all tags for that problem that + // the user can adjust + todo!(); + } + TagCommand::Search => { + // given a tag, finds all problems that have that tag + todo!(); + } + } +} diff --git a/src/main.rs b/src/main.rs index 7ba1f80..0acab74 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,54 +12,17 @@ async fn main() -> Result<()> { let args = Cli::parse(); match &args.command { Commands::New { link } => { - let _ = commands::new::run(link).await; // <--- Remove this ; later as it should return all the way up to - // main + commands::new::run(link).await? // <--- Remove this ; later as it should return all the way up to + // main } Commands::Edit { num } => { // takes a number then allows the user to edit the solution // this is the mutating version of Commands::Info. - let _ = commands::edit::run(num); + commands::edit::run(num)? } - Commands::Tag { cmd } => match cmd { - TagCommand::Add => { - // FLAGS - // ************************************************************ - // Add should take a number and a tag/[tags] - // to apply to a problem referenced by the number provided - // - // PROMPTS - // ************************************************************ - // should prompt for a tag and a problem number - let (_input_tag, tag) = prompt_for_input::("Enter Tag to add: ")?; - - let (_input_num, num) = - prompt_for_input::("Enter Problem Number to add Tag to: ")?; - println!("Tag: {tag:?} was added to Problem: {num}"); - } - TagCommand::Remove => { - // FLAGS - // ************************************************************ - // should take a number and a tag/[tags] to remove the tags from said problem - // - // PROMPTS - // ************************************************************ - // should prompt for a tag and a problem number - let (_input_tag, tag) = prompt_for_input::("Enter Tag to add: ")?; - - let (_input_num, num) = - prompt_for_input::("Enter Problem Number to remove Tag from: ")?; - println!("Tag: {tag:?} was removed from Problem: {num}"); - } - TagCommand::Edit => { - // should just take a number and then give a list of all tags for that problem that - // the user can adjust - } - TagCommand::Search => { - // given a tag, finds all problems that have that tag - } - }, + Commands::Tag { cmd } => tag_subcommands(cmd)?, Commands::Info { num } => { // takes a number and prints a bunch of info about the problem }