From 42061d0ba3972b4adbbcf548cf9c1258df2869b0 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 22 Oct 2022 23:24:57 +0800 Subject: [PATCH 1/5] feat: upgrade clap version to 4 --- Cargo.toml | 2 +- src/cache/mod.rs | 2 +- src/cmds/data.rs | 18 ++++++++------- src/cmds/edit.rs | 17 ++++++++------ src/cmds/exec.rs | 8 +++---- src/cmds/list.rs | 49 +++++++++++++++++++++++------------------ src/cmds/mod.rs | 2 +- src/cmds/pick.rs | 28 +++++++++++------------ src/cmds/stat.rs | 2 +- src/cmds/test.rs | 14 ++++++------ src/flag.rs | 6 ++--- src/plugins/leetcode.rs | 2 +- 12 files changed, 80 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ab4163..5da9c82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ readme = './README.md' [dependencies] async-trait = "0.1.56" tokio = { version = "1.19.2", features = ["full"] } -clap = { version = "3.2.10", features = ["cargo"] } +clap = { version = "4", features = ["cargo"] } colored = "2.0.0" dirs = "4.0.0" env_logger = "0.9.0" diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 345b3ea..6ec86cb 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -55,7 +55,7 @@ impl Cache { } pub fn update_after_ac(self, rid: i32) -> Result<(), Error> { - let c = conn((&self.0.conf.storage.cache()?).to_owned()); + let c = conn(self.0.conf.storage.cache()?); let target = problems.filter(id.eq(rid)); diesel::update(target).set(status.eq("ac")).execute(&c)?; Ok(()) diff --git a/src/cmds/data.rs b/src/cmds/data.rs index c590458..cb66e39 100644 --- a/src/cmds/data.rs +++ b/src/cmds/data.rs @@ -2,7 +2,7 @@ use super::Command; use crate::{cache::Cache, helper::Digit, Error}; use async_trait::async_trait; -use clap::{Arg, ArgMatches, Command as ClapCommand}; +use clap::{Arg, ArgAction, ArgMatches, Command as ClapCommand}; use colored::Colorize; /// Abstract `data` command @@ -25,23 +25,25 @@ pub struct DataCommand; #[async_trait] impl Command for DataCommand { /// `data` command usage - fn usage<'a>() -> ClapCommand<'a> { + fn usage() -> ClapCommand { ClapCommand::new("data") .about("Manage Cache") .visible_alias("d") .arg( - Arg::with_name("delete") + Arg::new("delete") .display_order(1) .short('d') .long("delete") - .help("Delete cache"), + .help("Delete cache") + .action(ArgAction::SetTrue), ) .arg( - Arg::with_name("update") + Arg::new("update") .display_order(2) .short('u') .long("update") - .help("Update cache"), + .help("Update cache") + .action(ArgAction::SetTrue), ) } @@ -73,13 +75,13 @@ impl Command for DataCommand { title.push_str(&"-".repeat(65)); let mut flags = 0; - if m.contains_id("delete") { + if m.get_flag("delete") { flags += 1; cache.clean()?; println!("{}", "ok!".bright_green()); } - if m.contains_id("update") { + if m.get_flag("update") { flags += 1; cache.update().await?; println!("{}", "ok!".bright_green()); diff --git a/src/cmds/edit.rs b/src/cmds/edit.rs index a6ec981..5d7df48 100644 --- a/src/cmds/edit.rs +++ b/src/cmds/edit.rs @@ -25,20 +25,20 @@ pub struct EditCommand; #[async_trait] impl Command for EditCommand { /// `edit` usage - fn usage<'a>() -> ClapCommand<'a> { + fn usage() -> ClapCommand { ClapCommand::new("edit") .about("Edit question by id") .visible_alias("e") .arg( - Arg::with_name("lang") + Arg::new("lang") .short('l') .long("lang") - .takes_value(true) + .num_args(1) .help("Edit with specific language"), ) .arg( - Arg::with_name("id") - .takes_value(true) + Arg::new("id") + .num_args(1) .required(true) .help("question id"), ) @@ -51,7 +51,7 @@ impl Command for EditCommand { use std::io::Write; use std::path::Path; - let id: i32 = m.value_of("id").ok_or(Error::NoneError)?.parse()?; + let id: i32 = m.get_one::<&str>("id").ok_or(Error::NoneError)?.parse()?; let cache = Cache::new()?; let problem = cache.get_problem(id)?; let mut conf = cache.to_owned().0.conf; @@ -61,7 +61,10 @@ impl Command for EditCommand { let p_desc_comment = problem.desc_comment(&conf); // condition language if m.contains_id("lang") { - conf.code.lang = m.value_of("lang").ok_or(Error::NoneError)?.to_string(); + conf.code.lang = m + .get_one::<&str>("lang") + .ok_or(Error::NoneError)? + .to_string(); conf.sync()?; } diff --git a/src/cmds/exec.rs b/src/cmds/exec.rs index 85b6d1a..e458669 100644 --- a/src/cmds/exec.rs +++ b/src/cmds/exec.rs @@ -25,13 +25,13 @@ pub struct ExecCommand; #[async_trait] impl Command for ExecCommand { /// `exec` usage - fn usage<'a>() -> ClapCommand<'a> { + fn usage() -> ClapCommand { ClapCommand::new("exec") .about("Submit solution") .visible_alias("x") .arg( - Arg::with_name("id") - .takes_value(true) + Arg::new("id") + .num_args(1) .required(true) .help("question id"), ) @@ -41,7 +41,7 @@ impl Command for ExecCommand { async fn handler(m: &ArgMatches) -> Result<(), crate::Error> { use crate::cache::{Cache, Run}; - let id: i32 = m.value_of("id").ok_or(Error::NoneError)?.parse()?; + let id: i32 = m.get_one::<&str>("id").ok_or(Error::NoneError)?.parse()?; let cache = Cache::new()?; let res = cache.exec_problem(id, Run::Submit, None).await?; diff --git a/src/cmds/list.rs b/src/cmds/list.rs index f287f54..255b43e 100644 --- a/src/cmds/list.rs +++ b/src/cmds/list.rs @@ -36,7 +36,7 @@ use super::Command; use crate::{cache::Cache, err::Error, helper::Digit}; use async_trait::async_trait; -use clap::{Arg, ArgMatches, Command as ClapCommand}; +use clap::{Arg, ArgAction, ArgMatches, Command as ClapCommand}; /// Abstract `list` command /// /// ## handler @@ -72,56 +72,56 @@ static LIST_AFTER_HELP: &str = r#"EXAMPLES: #[async_trait] impl Command for ListCommand { /// `list` command usage - fn usage<'a>() -> ClapCommand<'a> { + fn usage() -> ClapCommand { ClapCommand::new("list") .about("List problems") .visible_alias("l") .arg( - Arg::with_name("category") + Arg::new("category") .short('c') .long("category") - .takes_value(true) + .num_args(1) .help(CATEGORY_HELP), ) .arg( - Arg::with_name("plan") + Arg::new("plan") .short('p') .long("plan") - .takes_value(true) + .num_args(1) .help("Invoking python scripts to filter questions"), ) .arg( - Arg::with_name("query") + Arg::new("query") .short('q') .long("query") - .takes_value(true) + .num_args(1) .help(QUERY_HELP), ) .arg( - Arg::with_name("range") + Arg::new("range") .short('r') .long("range") - .takes_value(true) - .min_values(2) + .num_args(2..) .help("Filter questions by id range"), ) .after_help(LIST_AFTER_HELP) .arg( - Arg::with_name("stat") + Arg::new("stat") .short('s') .long("stat") - .help("Show statistics of listed problems"), + .help("Show statistics of listed problems") + .action(ArgAction::SetTrue), ) .arg( - Arg::with_name("tag") + Arg::new("tag") .short('t') .long("tag") - .takes_value(true) + .num_args(1) .help("Filter questions by tag"), ) .arg( - Arg::with_name("keyword") - .takes_value(true) + Arg::new("keyword") + .num_args(1) .help("Keyword in select query"), ) } @@ -156,26 +156,31 @@ impl Command for ListCommand { // filter tag if m.contains_id("tag") { let ids = cache - .get_tagged_questions(m.value_of("tag").unwrap_or("")) + .get_tagged_questions(m.get_one::<&str>("tag").copied().unwrap_or("")) .await?; crate::helper::squash(&mut ps, ids)?; } // filter category if m.contains_id("category") { - ps.retain(|x| x.category == m.value_of("category").unwrap_or("algorithms")); + ps.retain(|x| { + x.category + == m.get_one::<&str>("category") + .copied() + .unwrap_or("algorithms") + }); } // filter query if m.contains_id("query") { - let query = m.value_of("query").ok_or(Error::NoneError)?; + let query = m.get_one::<&str>("query").ok_or(Error::NoneError)?; crate::helper::filter(&mut ps, query.to_string()); } // filter range if m.contains_id("range") { let num_range: Vec = m - .values_of("range") + .get_many::("range") .ok_or(Error::NoneError)? .into_iter() .map(|x| x.parse::().unwrap_or(0)) @@ -184,7 +189,7 @@ impl Command for ListCommand { } // retain if keyword exists - if let Some(keyword) = m.value_of("keyword") { + if let Some(keyword) = m.get_one::<&str>("keyword") { let lowercase_kw = keyword.to_lowercase(); ps.retain(|x| x.name.to_lowercase().contains(&lowercase_kw)); } diff --git a/src/cmds/mod.rs b/src/cmds/mod.rs index 58a9dc3..7bf957f 100644 --- a/src/cmds/mod.rs +++ b/src/cmds/mod.rs @@ -18,7 +18,7 @@ use clap::{ArgMatches, Command as ClapCommand}; #[async_trait] pub trait Command { /// Usage of the specific command - fn usage<'a>() -> ClapCommand<'a>; + fn usage() -> ClapCommand; /// The handler will deal [args, options,...] from the command-line async fn handler(m: &ArgMatches) -> Result<(), Error>; diff --git a/src/cmds/pick.rs b/src/cmds/pick.rs index cba7e5d..476ed7c 100644 --- a/src/cmds/pick.rs +++ b/src/cmds/pick.rs @@ -43,37 +43,37 @@ s = starred S = not starred"#; #[async_trait] impl Command for PickCommand { /// `pick` usage - fn usage<'a>() -> ClapCommand<'a> { + fn usage() -> ClapCommand { ClapCommand::new("pick") .about("Pick a problem") .visible_alias("p") - .arg(Arg::with_name("id").help("Problem id").takes_value(true)) + .arg(Arg::new("id").help("Problem id").num_args(1)) .arg( - Arg::with_name("plan") + Arg::new("plan") .short('p') .long("plan") - .takes_value(true) + .num_args(1) .help("Invoking python scripts to filter questions"), ) .arg( - Arg::with_name("query") + Arg::new("query") .short('q') .long("query") - .takes_value(true) + .num_args(1) .help(QUERY_HELP), ) .arg( - Arg::with_name("tag") + Arg::new("tag") .short('t') .long("tag") - .takes_value(true) + .num_args(1) .help("Filter questions by tag"), ) .arg( - Arg::with_name("daily") + Arg::new("daily") .short('d') .long("daily") - .takes_value(false) + .num_args(1) .help("Pick today's daily challenge"), ) } @@ -96,7 +96,7 @@ impl Command for PickCommand { #[cfg(feature = "pym")] { if m.contains_id("plan") { - let ids = crate::pym::exec(m.value_of("plan").unwrap_or(""))?; + let ids = crate::pym::exec(m.get_one::<&str>("plan").unwrap_or(&""))?; crate::helper::squash(&mut problems, ids)?; } } @@ -105,14 +105,14 @@ impl Command for PickCommand { if m.contains_id("tag") { let ids = cache .clone() - .get_tagged_questions(m.value_of("tag").unwrap_or("")) + .get_tagged_questions(m.get_one::<&str>("tag").unwrap_or(&"")) .await?; crate::helper::squash(&mut problems, ids)?; } // query filter if m.contains_id("query") { - let query = m.value_of("query").ok_or(Error::NoneError)?; + let query = m.get_one::<&str>("query").ok_or(Error::NoneError)?; crate::helper::filter(&mut problems, query.to_string()); } @@ -123,7 +123,7 @@ impl Command for PickCommand { }; let fid = m - .value_of("id") + .get_one::<&str>("id") .and_then(|id| id.parse::().ok()) .or(daily_id) .unwrap_or_else(|| { diff --git a/src/cmds/stat.rs b/src/cmds/stat.rs index 147392b..913064a 100644 --- a/src/cmds/stat.rs +++ b/src/cmds/stat.rs @@ -22,7 +22,7 @@ pub struct StatCommand; #[async_trait] impl Command for StatCommand { /// `stat` usage - fn usage<'a>() -> ClapCommand<'a> { + fn usage() -> ClapCommand { ClapCommand::new("stat") .about("Show simple chart about submissions") .visible_alias("s") diff --git a/src/cmds/test.rs b/src/cmds/test.rs index 62b4fc4..1bdce5e 100644 --- a/src/cmds/test.rs +++ b/src/cmds/test.rs @@ -25,19 +25,19 @@ pub struct TestCommand; #[async_trait] impl Command for TestCommand { /// `test` usage - fn usage<'a>() -> ClapCommand<'a> { + fn usage() -> ClapCommand { ClapCommand::new("test") .about("Test question by id") .visible_alias("t") .arg( - Arg::with_name("id") - .takes_value(true) + Arg::new("id") + .num_args(1) .required(true) .help("question id"), ) .arg( - Arg::with_name("testcase") - .takes_value(true) + Arg::new("testcase") + .num_args(1) .required(false) .help("custom testcase"), ) @@ -46,8 +46,8 @@ impl Command for TestCommand { /// `test` handler async fn handler(m: &ArgMatches) -> Result<(), Error> { use crate::cache::{Cache, Run}; - let id: i32 = m.value_of("id").ok_or(Error::NoneError)?.parse()?; - let testcase = m.value_of("testcase"); + let id: i32 = m.get_one::<&str>("id").ok_or(Error::NoneError)?.parse()?; + let testcase = m.get_one::<&str>("testcase"); let case_str: Option = match testcase { Some(case) => Option::from(case.replace("\\n", "\n")), _ => None, diff --git a/src/flag.rs b/src/flag.rs index 6706a06..cb509f9 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -12,7 +12,7 @@ use env_logger::Env; /// Abstract flag trait pub trait Flag { - fn usage<'a>() -> Arg<'a>; + fn usage() -> Arg; fn handler() -> Result<(), Error>; } @@ -20,8 +20,8 @@ pub trait Flag { pub struct Debug; impl Flag for Debug { - fn usage<'a>() -> Arg<'a> { - Arg::with_name("debug") + fn usage() -> Arg { + Arg::new("debug") .short('d') .long("debug") .help("debug mode") diff --git a/src/plugins/leetcode.rs b/src/plugins/leetcode.rs index e06627f..141c765 100644 --- a/src/plugins/leetcode.rs +++ b/src/plugins/leetcode.rs @@ -230,7 +230,7 @@ impl LeetCode { json: Some(json), mode: Mode::Post, name: "get_problem_detail", - url: (&self.conf.sys.urls["graphql"]).to_string(), + url: self.conf.sys.urls["graphql"].to_string(), } .send(&self.client) .await From aebb9d52bac771e608151036add466ae207a4be2 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 22 Oct 2022 23:51:10 +0800 Subject: [PATCH 2/5] fix: runtime error --- src/cmds/edit.rs | 9 +++++++-- src/cmds/exec.rs | 6 +++++- src/cmds/list.rs | 13 ++++++++----- src/cmds/pick.rs | 22 +++++++++++++++------- src/cmds/test.rs | 8 ++++++-- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/cmds/edit.rs b/src/cmds/edit.rs index 5d7df48..4e0e4e0 100644 --- a/src/cmds/edit.rs +++ b/src/cmds/edit.rs @@ -51,7 +51,11 @@ impl Command for EditCommand { use std::io::Write; use std::path::Path; - let id: i32 = m.get_one::<&str>("id").ok_or(Error::NoneError)?.parse()?; + let id: i32 = m + .get_one::("id") + .map(|s| s.as_str()) + .ok_or(Error::NoneError)? + .parse()?; let cache = Cache::new()?; let problem = cache.get_problem(id)?; let mut conf = cache.to_owned().0.conf; @@ -62,7 +66,8 @@ impl Command for EditCommand { // condition language if m.contains_id("lang") { conf.code.lang = m - .get_one::<&str>("lang") + .get_one::("lang") + .map(|s| s.as_str()) .ok_or(Error::NoneError)? .to_string(); conf.sync()?; diff --git a/src/cmds/exec.rs b/src/cmds/exec.rs index e458669..733a458 100644 --- a/src/cmds/exec.rs +++ b/src/cmds/exec.rs @@ -41,7 +41,11 @@ impl Command for ExecCommand { async fn handler(m: &ArgMatches) -> Result<(), crate::Error> { use crate::cache::{Cache, Run}; - let id: i32 = m.get_one::<&str>("id").ok_or(Error::NoneError)?.parse()?; + let id: i32 = m + .get_one::("id") + .map(|s| s.as_str()) + .ok_or(Error::NoneError)? + .parse()?; let cache = Cache::new()?; let res = cache.exec_problem(id, Run::Submit, None).await?; diff --git a/src/cmds/list.rs b/src/cmds/list.rs index 255b43e..ca9b686 100644 --- a/src/cmds/list.rs +++ b/src/cmds/list.rs @@ -156,7 +156,7 @@ impl Command for ListCommand { // filter tag if m.contains_id("tag") { let ids = cache - .get_tagged_questions(m.get_one::<&str>("tag").copied().unwrap_or("")) + .get_tagged_questions(m.get_one::("tag").map(|s| s.as_str()).unwrap_or("")) .await?; crate::helper::squash(&mut ps, ids)?; } @@ -165,15 +165,18 @@ impl Command for ListCommand { if m.contains_id("category") { ps.retain(|x| { x.category - == m.get_one::<&str>("category") - .copied() + == m.get_one::("category") + .map(|s| s.as_str()) .unwrap_or("algorithms") }); } // filter query if m.contains_id("query") { - let query = m.get_one::<&str>("query").ok_or(Error::NoneError)?; + let query = m + .get_one::("query") + .map(|s| s.as_str()) + .ok_or(Error::NoneError)?; crate::helper::filter(&mut ps, query.to_string()); } @@ -189,7 +192,7 @@ impl Command for ListCommand { } // retain if keyword exists - if let Some(keyword) = m.get_one::<&str>("keyword") { + if let Some(keyword) = m.get_one::("keyword").map(|s| s.as_str()) { let lowercase_kw = keyword.to_lowercase(); ps.retain(|x| x.name.to_lowercase().contains(&lowercase_kw)); } diff --git a/src/cmds/pick.rs b/src/cmds/pick.rs index 476ed7c..e5102e8 100644 --- a/src/cmds/pick.rs +++ b/src/cmds/pick.rs @@ -2,7 +2,7 @@ use super::Command; use crate::err::Error; use async_trait::async_trait; -use clap::{Arg, ArgMatches, Command as ClapCommand}; +use clap::{Arg, ArgAction, ArgMatches, Command as ClapCommand}; /// Abstract pick command /// /// ```sh @@ -73,8 +73,8 @@ impl Command for PickCommand { Arg::new("daily") .short('d') .long("daily") - .num_args(1) - .help("Pick today's daily challenge"), + .help("Pick today's daily challenge") + .action(ArgAction::SetTrue), ) } @@ -96,7 +96,11 @@ impl Command for PickCommand { #[cfg(feature = "pym")] { if m.contains_id("plan") { - let ids = crate::pym::exec(m.get_one::<&str>("plan").unwrap_or(&""))?; + let ids = crate::pym::exec( + m.get_one::("plan") + .map(|s| s.as_str()) + .unwrap_or(""), + )?; crate::helper::squash(&mut problems, ids)?; } } @@ -105,14 +109,17 @@ impl Command for PickCommand { if m.contains_id("tag") { let ids = cache .clone() - .get_tagged_questions(m.get_one::<&str>("tag").unwrap_or(&"")) + .get_tagged_questions(m.get_one::("tag").map(|s| s.as_str()).unwrap_or("")) .await?; crate::helper::squash(&mut problems, ids)?; } // query filter if m.contains_id("query") { - let query = m.get_one::<&str>("query").ok_or(Error::NoneError)?; + let query = m + .get_one::("query") + .map(|s| s.as_str()) + .ok_or(Error::NoneError)?; crate::helper::filter(&mut problems, query.to_string()); } @@ -123,7 +130,8 @@ impl Command for PickCommand { }; let fid = m - .get_one::<&str>("id") + .get_one::("id") + .map(|s| s.as_str()) .and_then(|id| id.parse::().ok()) .or(daily_id) .unwrap_or_else(|| { diff --git a/src/cmds/test.rs b/src/cmds/test.rs index 1bdce5e..d0a1578 100644 --- a/src/cmds/test.rs +++ b/src/cmds/test.rs @@ -46,8 +46,12 @@ impl Command for TestCommand { /// `test` handler async fn handler(m: &ArgMatches) -> Result<(), Error> { use crate::cache::{Cache, Run}; - let id: i32 = m.get_one::<&str>("id").ok_or(Error::NoneError)?.parse()?; - let testcase = m.get_one::<&str>("testcase"); + let id: i32 = m + .get_one::("id") + .map(|s| s.as_str()) + .ok_or(Error::NoneError)? + .parse()?; + let testcase = m.get_one::("testcase").map(|s| s.as_str()); let case_str: Option = match testcase { Some(case) => Option::from(case.replace("\\n", "\n")), _ => None, From 07c9474ded0035549fd76aff16000361179f33f4 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 12 Dec 2022 23:38:32 +0800 Subject: [PATCH 3/5] fix: list py plan crash, and opt the clap get_one --- src/cmds/edit.rs | 8 ++------ src/cmds/exec.rs | 7 ++----- src/cmds/list.rs | 22 ++++++++++------------ src/cmds/pick.rs | 25 +++++++++++-------------- src/cmds/test.rs | 9 +++------ 5 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/cmds/edit.rs b/src/cmds/edit.rs index 4e0e4e0..f7e490b 100644 --- a/src/cmds/edit.rs +++ b/src/cmds/edit.rs @@ -40,6 +40,7 @@ impl Command for EditCommand { Arg::new("id") .num_args(1) .required(true) + .value_parser(clap::value_parser!(i32)) .help("question id"), ) } @@ -51,11 +52,7 @@ impl Command for EditCommand { use std::io::Write; use std::path::Path; - let id: i32 = m - .get_one::("id") - .map(|s| s.as_str()) - .ok_or(Error::NoneError)? - .parse()?; + let id = *m.get_one::("id").ok_or(Error::NoneError)?; let cache = Cache::new()?; let problem = cache.get_problem(id)?; let mut conf = cache.to_owned().0.conf; @@ -67,7 +64,6 @@ impl Command for EditCommand { if m.contains_id("lang") { conf.code.lang = m .get_one::("lang") - .map(|s| s.as_str()) .ok_or(Error::NoneError)? .to_string(); conf.sync()?; diff --git a/src/cmds/exec.rs b/src/cmds/exec.rs index 733a458..f25f9b4 100644 --- a/src/cmds/exec.rs +++ b/src/cmds/exec.rs @@ -33,6 +33,7 @@ impl Command for ExecCommand { Arg::new("id") .num_args(1) .required(true) + .value_parser(clap::value_parser!(i32)) .help("question id"), ) } @@ -41,11 +42,7 @@ impl Command for ExecCommand { async fn handler(m: &ArgMatches) -> Result<(), crate::Error> { use crate::cache::{Cache, Run}; - let id: i32 = m - .get_one::("id") - .map(|s| s.as_str()) - .ok_or(Error::NoneError)? - .parse()?; + let id: i32 = *m.get_one::("id").ok_or(Error::NoneError)?; let cache = Cache::new()?; let res = cache.exec_problem(id, Run::Submit, None).await?; diff --git a/src/cmds/list.rs b/src/cmds/list.rs index ca9b686..f18a953 100644 --- a/src/cmds/list.rs +++ b/src/cmds/list.rs @@ -102,6 +102,7 @@ impl Command for ListCommand { .short('r') .long("range") .num_args(2..) + .value_parser(clap::value_parser!(i32)) .help("Filter questions by id range"), ) .after_help(LIST_AFTER_HELP) @@ -148,7 +149,7 @@ impl Command for ListCommand { #[cfg(feature = "pym")] { if m.contains_id("plan") { - let ids = crate::pym::exec(m.value_of("plan").unwrap_or(""))?; + let ids = crate::pym::exec(m.get_one::("plan").unwrap_or(&"".to_string()))?; crate::helper::squash(&mut ps, ids)?; } } @@ -156,7 +157,7 @@ impl Command for ListCommand { // filter tag if m.contains_id("tag") { let ids = cache - .get_tagged_questions(m.get_one::("tag").map(|s| s.as_str()).unwrap_or("")) + .get_tagged_questions(m.get_one::("tag").unwrap_or(&"".to_string())) .await?; crate::helper::squash(&mut ps, ids)?; } @@ -165,34 +166,31 @@ impl Command for ListCommand { if m.contains_id("category") { ps.retain(|x| { x.category - == m.get_one::("category") - .map(|s| s.as_str()) - .unwrap_or("algorithms") + == *m + .get_one::("category") + .unwrap_or(&"algorithms".to_string()) }); } // filter query if m.contains_id("query") { - let query = m - .get_one::("query") - .map(|s| s.as_str()) - .ok_or(Error::NoneError)?; + let query = m.get_one::("query").ok_or(Error::NoneError)?; crate::helper::filter(&mut ps, query.to_string()); } // filter range if m.contains_id("range") { let num_range: Vec = m - .get_many::("range") + .get_many::("range") .ok_or(Error::NoneError)? + .map(|id| *id) .into_iter() - .map(|x| x.parse::().unwrap_or(0)) .collect(); ps.retain(|x| num_range[0] <= x.fid && x.fid <= num_range[1]); } // retain if keyword exists - if let Some(keyword) = m.get_one::("keyword").map(|s| s.as_str()) { + if let Some(keyword) = m.get_one::("keyword") { let lowercase_kw = keyword.to_lowercase(); ps.retain(|x| x.name.to_lowercase().contains(&lowercase_kw)); } diff --git a/src/cmds/pick.rs b/src/cmds/pick.rs index e5102e8..9fc136f 100644 --- a/src/cmds/pick.rs +++ b/src/cmds/pick.rs @@ -47,7 +47,12 @@ impl Command for PickCommand { ClapCommand::new("pick") .about("Pick a problem") .visible_alias("p") - .arg(Arg::new("id").help("Problem id").num_args(1)) + .arg( + Arg::new("id") + .value_parser(clap::value_parser!(i32)) + .help("Problem id") + .num_args(1), + ) .arg( Arg::new("plan") .short('p') @@ -96,11 +101,7 @@ impl Command for PickCommand { #[cfg(feature = "pym")] { if m.contains_id("plan") { - let ids = crate::pym::exec( - m.get_one::("plan") - .map(|s| s.as_str()) - .unwrap_or(""), - )?; + let ids = crate::pym::exec(m.get_one::("plan").unwrap_or(&"".to_string()))?; crate::helper::squash(&mut problems, ids)?; } } @@ -109,17 +110,14 @@ impl Command for PickCommand { if m.contains_id("tag") { let ids = cache .clone() - .get_tagged_questions(m.get_one::("tag").map(|s| s.as_str()).unwrap_or("")) + .get_tagged_questions(m.get_one::("tag").unwrap_or(&"".to_string())) .await?; crate::helper::squash(&mut problems, ids)?; } // query filter if m.contains_id("query") { - let query = m - .get_one::("query") - .map(|s| s.as_str()) - .ok_or(Error::NoneError)?; + let query = m.get_one::("query").ok_or(Error::NoneError)?; crate::helper::filter(&mut problems, query.to_string()); } @@ -130,9 +128,8 @@ impl Command for PickCommand { }; let fid = m - .get_one::("id") - .map(|s| s.as_str()) - .and_then(|id| id.parse::().ok()) + .get_one::("id") + .map(|id| *id) .or(daily_id) .unwrap_or_else(|| { // Pick random without specify id diff --git a/src/cmds/test.rs b/src/cmds/test.rs index d0a1578..af72014 100644 --- a/src/cmds/test.rs +++ b/src/cmds/test.rs @@ -33,6 +33,7 @@ impl Command for TestCommand { Arg::new("id") .num_args(1) .required(true) + .value_parser(clap::value_parser!(i32)) .help("question id"), ) .arg( @@ -46,12 +47,8 @@ impl Command for TestCommand { /// `test` handler async fn handler(m: &ArgMatches) -> Result<(), Error> { use crate::cache::{Cache, Run}; - let id: i32 = m - .get_one::("id") - .map(|s| s.as_str()) - .ok_or(Error::NoneError)? - .parse()?; - let testcase = m.get_one::("testcase").map(|s| s.as_str()); + let id: i32 = *m.get_one::("id").ok_or(Error::NoneError)?; + let testcase = m.get_one::("testcase"); let case_str: Option = match testcase { Some(case) => Option::from(case.replace("\\n", "\n")), _ => None, From 0c59b3a7362d360bb7d093bb622f9b2e44904dbb Mon Sep 17 00:00:00 2001 From: David Date: Wed, 14 Dec 2022 16:24:36 +0800 Subject: [PATCH 4/5] feat: only debug mode can use RUST_LOG env control the log level --- src/cli.rs | 6 ++++-- src/flag.rs | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 3ec98bf..6198939 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -8,6 +8,7 @@ use crate::{ flag::{Debug, Flag}, }; use clap::{crate_name, crate_version}; +use log::LevelFilter; /// This should be called before calling any cli method or printing any output. pub fn reset_signal_pipe_handler() { @@ -41,10 +42,11 @@ pub async fn main() -> Result<(), Error> { .arg_required_else_help(true) .get_matches(); - if m.contains_id("debug") { + if m.get_flag("debug") { Debug::handler()?; } else { - env_logger::Builder::from_env(env_logger::Env::new().default_filter_or("info")) + env_logger::Builder::new() + .filter_level(LevelFilter::Info) .format_timestamp(None) .init(); } diff --git a/src/flag.rs b/src/flag.rs index cb509f9..5517153 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -7,7 +7,7 @@ //! -V, --version Prints version information //! ``` use crate::err::Error; -use clap::Arg; +use clap::{Arg, ArgAction}; use env_logger::Env; /// Abstract flag trait @@ -25,10 +25,11 @@ impl Flag for Debug { .short('d') .long("debug") .help("debug mode") + .action(ArgAction::SetTrue) } fn handler() -> Result<(), Error> { - env_logger::Builder::from_env(Env::default().default_filter_or("leetcode")).init(); + env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init(); Ok(()) } From 0f16f5a395f44df02ef40b3efea4c45e0edc46c3 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 14 Dec 2022 17:42:50 +0800 Subject: [PATCH 5/5] fix: issue#93 --- src/cache/models.rs | 11 +++++++---- src/cli.rs | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cache/models.rs b/src/cache/models.rs index 0a9a6ab..f74cb28 100644 --- a/src/cache/models.rs +++ b/src/cache/models.rs @@ -290,7 +290,7 @@ impl std::fmt::Display for VerifyResult { match &self.status.status_code { 10 => { - if self.correct_answer { + if matches!(self.result_type, Run::Test) && self.correct_answer { // Pass Tests write!( f, @@ -305,9 +305,12 @@ impl std::fmt::Display for VerifyResult { &"\nExpected:".after_spaces(6), eca, )? - } else if !self.submit.compare_result.is_empty() { + } else if matches!(self.result_type, Run::Submit) + && !self.submit.compare_result.is_empty() + { + // only Submit execute this branch // Submit Successfully - // TODO: result shoule be all 1; + // TODO: result should be all 1; // Lines below are sucks... let cache = super::Cache::new().expect("cache gen failed"); cache @@ -315,7 +318,7 @@ impl std::fmt::Display for VerifyResult { self.submit .question_id .parse() - .expect("submit succcessfully, parse question_id to i32 failed"), + .expect("submit successfully, parse question_id to i32 failed"), ) .expect("update ac to cache failed"); diff --git a/src/cli.rs b/src/cli.rs index 6198939..90d1756 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -23,7 +23,7 @@ pub fn reset_signal_pipe_handler() { } } -/// Get maches +/// Get matches pub async fn main() -> Result<(), Error> { reset_signal_pipe_handler(); let m = clap::Command::new(crate_name!())