From 1e63b7642f43a8278066eddc921a5676c3d88721 Mon Sep 17 00:00:00 2001 From: Mick Harrigan Date: Thu, 5 Oct 2023 13:56:29 -0700 Subject: [PATCH] updated most of the tag system to be mostly functional now --- Cargo.lock | 69 +++++++++++ Cargo.toml | 1 + src/commands/common.rs | 5 +- src/commands/tag.rs | 274 +++++++++++++++++++++++++++++++++++++---- src/main.rs | 3 + 5 files changed, 326 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74d11a2..d9e2946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,12 +236,51 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + [[package]] name = "deranged" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -535,6 +574,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "rayon", "regex", "reqwest", "serde", @@ -583,6 +623,15 @@ version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -777,6 +826,26 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.3.5" diff --git a/Cargo.toml b/Cargo.toml index 591c5d4..e06bf68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ test = [] [dependencies] anyhow = "1.0.75" clap = { version = "4.4.4", features = ["derive"] } +rayon = "1.8.0" regex = "1.9.5" reqwest = { version = "0.11.20", features = ["json", "cookies"] } serde = { version = "1.0.188", features = ["serde_derive", "derive"] } diff --git a/src/commands/common.rs b/src/commands/common.rs index 4dc779a..19bde1b 100644 --- a/src/commands/common.rs +++ b/src/commands/common.rs @@ -44,6 +44,9 @@ pub enum Commands { /// Search for a problem based on name, tags, or number #[command(arg_required_else_help = true)] Search { cmd: SearchCommand }, + /// Run the LeetCode provided tests for the provided problem + #[command(arg_required_else_help = true)] + Test { num: usize }, /// Send a solution to be submitted #[command(arg_required_else_help = true)] Submit { num: usize }, @@ -63,7 +66,7 @@ where std::io::stdin().read_line(&mut input)?; let input = input.trim().to_string(); let output = input.parse::()?; - println!("Input was parsed from: {} into {:?}", input, output); + // println!("Input was parsed from: {} into {:?}", input, output); Ok((input, output)) } diff --git a/src/commands/tag.rs b/src/commands/tag.rs index c336deb..52bdcb4 100644 --- a/src/commands/tag.rs +++ b/src/commands/tag.rs @@ -1,15 +1,12 @@ use anyhow::Result; use clap::{Parser, ValueEnum}; use regex::Regex; -use std::{ - fs::File, - io::{BufReader, Write}, -}; -use strum::{EnumString, IntoStaticStr}; +use std::io::Write; +use strum::{EnumIter, EnumString, IntoEnumIterator, IntoStaticStr}; use super::common::{get_lc_dir, prompt_for_input}; -#[derive(Debug, Clone, Parser, EnumString, IntoStaticStr)] +#[derive(Debug, Clone, Parser, EnumString, IntoStaticStr, EnumIter)] pub enum TagType { // #[strum(serialize = "stack", serialize = "")] #[strum(serialize = "stack", ascii_case_insensitive)] @@ -26,6 +23,204 @@ pub enum TagType { #[strum(serialize = "backtracking", ascii_case_insensitive)] BackTracking, + + #[strum(serialize = "hashmap", ascii_case_insensitive)] + HashMap, + + #[strum(serialize = "string", ascii_case_insensitive)] + String, + + #[strum(serialize = "array", ascii_case_insensitive)] + Array, + + #[strum(serialize = "math", ascii_case_insensitive)] + Math, + + #[strum(serialize = "sorting", ascii_case_insensitive)] + Sorting, + + #[strum(serialize = "greedy", ascii_case_insensitive)] + Greedy, + + #[strum(serialize = "dfs", ascii_case_insensitive)] + DepthFirstSearch, + + #[strum(serialize = "binarysearch", ascii_case_insensitive)] + BinarySearch, + + #[strum(serialize = "database", ascii_case_insensitive)] + Database, + + #[strum(serialize = "bfs", ascii_case_insensitive)] + BreadthFirstSearch, + + #[strum(serialize = "tree", ascii_case_insensitive)] + Tree, + + #[strum(serialize = "matrix", ascii_case_insensitive)] + Matrix, + + #[strum(serialize = "twopointers", ascii_case_insensitive)] + TwoPointers, + + #[strum(serialize = "bitmanip", ascii_case_insensitive)] + BitManipulation, + + #[strum(serialize = "heap", ascii_case_insensitive)] + Heap, + + #[strum(serialize = "prefixsum", ascii_case_insensitive)] + PrefixSum, + + #[strum(serialize = "sim", ascii_case_insensitive)] + Simulation, + + #[strum(serialize = "design", ascii_case_insensitive)] + Design, + + #[strum(serialize = "counting", ascii_case_insensitive)] + Counting, + + #[strum(serialize = "slidingwindow", ascii_case_insensitive)] + SlidingWindow, + + #[strum(serialize = "unionfind", ascii_case_insensitive)] + UnionFind, + + #[strum(serialize = "ll", ascii_case_insensitive)] + LinkedList, + + #[strum(serialize = "orderedset", ascii_case_insensitive)] + OrderedSet, + + #[strum(serialize = "enum", ascii_case_insensitive)] + Enumeration, + + #[strum(serialize = "monotonicstack", ascii_case_insensitive)] + MonotonicStack, + + #[strum(serialize = "trie", ascii_case_insensitive)] + Trie, + + #[strum(serialize = "recursion", ascii_case_insensitive)] + Recursion, + + #[strum(serialize = "divideandconquer", ascii_case_insensitive)] + DivideAndConquer, + + #[strum(serialize = "numbertheory", ascii_case_insensitive)] + NumberTheory, + + #[strum(serialize = "bitmask", ascii_case_insensitive)] + Bitmask, + + #[strum(serialize = "queue", ascii_case_insensitive)] + Queue, + + #[strum(serialize = "bst", ascii_case_insensitive)] + BinarySearchTree, + + #[strum(serialize = "memo", ascii_case_insensitive)] + Memoization, + + #[strum(serialize = "segmenttree", ascii_case_insensitive)] + SegmentTree, + + #[strum(serialize = "geometry", ascii_case_insensitive)] + Geometry, + + #[strum(serialize = "topologicalsort", ascii_case_insensitive)] + TopologicalSort, + + #[strum(serialize = "binaryindexedtree", ascii_case_insensitive)] + BinaryIndexedTree, + + #[strum(serialize = "gametheory", ascii_case_insensitive)] + GameTheory, + + #[strum(serialize = "hashfunction", ascii_case_insensitive)] + HashFunction, + + #[strum(serialize = "shortestpath", ascii_case_insensitive)] + ShortestPath, + + #[strum(serialize = "combinatorics", ascii_case_insensitive)] + Combinatorics, + + #[strum(serialize = "interactive", ascii_case_insensitive)] + Interactive, + + #[strum(serialize = "stringmatching", ascii_case_insensitive)] + StringMatching, + + #[strum(serialize = "datastream", ascii_case_insensitive)] + DataStream, + + #[strum(serialize = "rollinghash", ascii_case_insensitive)] + RollingHash, + + #[strum(serialize = "brainteaser", ascii_case_insensitive)] + Brainteaser, + + #[strum(serialize = "randomized", ascii_case_insensitive)] + Randomized, + + #[strum(serialize = "monotonicqueue", ascii_case_insensitive)] + MonotonicQueue, + + #[strum(serialize = "mergesort", ascii_case_insensitive)] + MergeSort, + + #[strum(serialize = "iterator", ascii_case_insensitive)] + Iterator, + + #[strum(serialize = "concurrency", ascii_case_insensitive)] + Concurrency, + + #[strum(serialize = "2ll", ascii_case_insensitive)] + DoublyLinkedList, + + #[strum(serialize = "prob", ascii_case_insensitive)] + ProbabilityAndStatistics, + + #[strum(serialize = "quickselect", ascii_case_insensitive)] + QuickSelect, + + #[strum(serialize = "bucketsort", ascii_case_insensitive)] + BucketSort, + + #[strum(serialize = "suffixarray", ascii_case_insensitive)] + SuffixArray, + + #[strum(serialize = "minimumspanningtree", ascii_case_insensitive)] + MinimumSpanningTree, + + #[strum(serialize = "countingsort", ascii_case_insensitive)] + CountingSort, + + #[strum(serialize = "shell", ascii_case_insensitive)] + Shell, + + #[strum(serialize = "linesweep", ascii_case_insensitive)] + LineSweep, + + #[strum(serialize = "reservoirsampling", ascii_case_insensitive)] + ReservoirSampling, + + #[strum(serialize = "stronglyconnectedcomponent", ascii_case_insensitive)] + StronglyConnectedComponent, + + #[strum(serialize = "euleriancircuit", ascii_case_insensitive)] + EulerianCircuit, + + #[strum(serialize = "radixsort", ascii_case_insensitive)] + RadixSort, + + #[strum(serialize = "rejectionsampling", ascii_case_insensitive)] + RejectionSampling, + + #[strum(serialize = "biconnectedcomponent", ascii_case_insensitive)] + BiconnectedComponent, } #[derive(Debug, Clone, Parser)] @@ -38,6 +233,8 @@ pub enum TagCommand { Edit, /// Search for all problems with a specific tag Search, + /// List all the available tags for usage + List, } impl ValueEnum for TagCommand { @@ -47,10 +244,17 @@ impl ValueEnum for TagCommand { Self::Remove => clap::builder::PossibleValue::new("remove"), Self::Edit => clap::builder::PossibleValue::new("edit"), Self::Search => clap::builder::PossibleValue::new("search"), + Self::List => clap::builder::PossibleValue::new("list"), }) } fn value_variants<'a>() -> &'a [Self] { - &[Self::Add, Self::Remove, Self::Edit, Self::Search] + &[ + Self::Add, + Self::Remove, + Self::Edit, + Self::Search, + Self::List, + ] } } @@ -63,14 +267,6 @@ impl std::fmt::Display for TagType { 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: ")?; @@ -96,14 +292,6 @@ pub fn tag_subcommands(cmd: &TagCommand) -> Result<()> { 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) = @@ -144,11 +332,47 @@ pub fn tag_subcommands(cmd: &TagCommand) -> Result<()> { TagCommand::Edit => { // should just take a number and then give a list of all tags for that problem that // the user can adjust - todo!(); + println!("Under Construction!"); + Ok(()) } TagCommand::Search => { // given a tag, finds all problems that have that tag - todo!(); + let (_input_tag, tag) = prompt_for_input::("Enter the tag to search for: ")?; + + // read all TAGS files in the system to find those with said tag + let mut out = Vec::new(); + let lc_dir = get_lc_dir()?; + let paths = std::fs::read_dir(format!("{}{}", lc_dir, "src/"))?; + paths.into_iter().for_each(|path| { + if let Ok(path) = path { + let tag_file = format!("{}{}", path.path().display(), "/TAGS"); + if let Ok(file) = std::fs::read_to_string(tag_file.clone()) { + // find the tag within the file + let re = Regex::new(format!(r"{}", tag).as_str()).unwrap(); + match re.captures(file.as_str()) { + Some(_a) => out.push(path.file_name()), + None => {} + } + } else { + // this should be put into an error log + // println!("Couldn't find the TAGS file in {:?}", path.file_name()); + } + } + }); + out.iter().for_each(|path| { + println!("Problems with {}: {}", tag, path.to_str().unwrap_or("")) + }); + Ok(()) } + TagCommand::List => { + list_tags(); + Ok(()) + } + } +} + +pub fn list_tags() { + for tag in TagType::iter() { + println!("Tag: {tag}"); } } diff --git a/src/main.rs b/src/main.rs index 0acab74..7a02c80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,9 @@ async fn main() -> Result<()> { // given a number will tag this as a hidden problem that has been attempted but not // completed. This should maybe be pushed somewhere else or just not tracked. } + Commands::Test { num } => { + // same as submit but with the altered state of running the tests that LC provides + } Commands::Submit { num } => { // given a number should aim to send the code to LeetCode, but I have no idea on how // to actually send this to them and receive the response. HTTP? GraphQL? I have no