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..4e0e4e0 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,11 @@ 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::("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; @@ -61,7 +65,11 @@ 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::("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 85b6d1a..733a458 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,11 @@ 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::("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 f287f54..ca9b686 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,34 @@ 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::("tag").map(|s| s.as_str()).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::("category") + .map(|s| s.as_str()) + .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::("query") + .map(|s| s.as_str()) + .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 +192,7 @@ impl Command for ListCommand { } // retain if keyword exists - if let Some(keyword) = m.value_of("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/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..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 @@ -43,38 +43,38 @@ 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) - .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.value_of("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.value_of("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.value_of("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 - .value_of("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/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..d0a1578 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,12 @@ 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::("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, 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