From 3c7c5c65b2d581dd986e7207eef62e5fec397b69 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 2 Jul 2022 22:23:56 +0800 Subject: [PATCH 01/10] fix: clippy warning for rust 1.61 stable --- src/cache/mod.rs | 97 ++++++++++++++++++++++++--------------------- src/cache/models.rs | 27 ++++++++----- src/cfg.rs | 9 +++-- src/cmds/test.rs | 11 +++-- tests/de.rs | 1 - 5 files changed, 79 insertions(+), 66 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 5e1309f..a3cc7fa 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -9,10 +9,10 @@ use self::sql::*; use crate::{cfg, err::Error, plugins::LeetCode}; use colored::Colorize; use diesel::prelude::*; +use reqwest::Response; use serde::de::DeserializeOwned; use serde_json::Value; use std::collections::HashMap; -use reqwest::Response; /// sqlite connection pub fn conn(p: String) -> SqliteConnection { @@ -60,32 +60,27 @@ impl Cache { Ok(()) } - async fn get_user_info(&self) -> Result<(String,bool), Error> { - let user = parser::user( - self.clone().0 - .get_user_info().await? - .json().await? - ); + async fn get_user_info(&self) -> Result<(String, bool), Error> { + let user = parser::user(self.clone().0.get_user_info().await?.json().await?); match user { None => Err(Error::NoneError), Some(None) => Err(Error::CookieError), - Some(Some((s,b))) => Ok((s,b)) + Some(Some((s, b))) => Ok((s, b)), } } async fn is_session_bad(&self) -> bool { // i.e. self.get_user_info().contains_err(Error::CookieError) - match self.get_user_info().await { - Err(Error::CookieError) => true, - _ => false - } + matches!(self.get_user_info().await, Err(Error::CookieError)) } async fn resp_to_json(&self, resp: Response) -> Result { - let maybe_json: Result = resp.json().await; + let maybe_json: Result = resp.json().await; if maybe_json.is_err() && self.is_session_bad().await { Err(Error::CookieError) - } else { Ok(maybe_json?) } + } else { + Ok(maybe_json?) + } } /// Download leetcode problems to db @@ -123,7 +118,7 @@ impl Cache { Ok(p) } - /// Get daily problem + /// Get daily problem pub async fn get_daily_problem_id(&self) -> Result { parser::daily( self.clone() @@ -131,8 +126,9 @@ impl Cache { .get_question_daily() .await? .json() // does not require LEETCODE_SESSION - .await? - ).ok_or(Error::NoneError) + .await?, + ) + .ok_or(Error::NoneError) } /// Get problems from cache @@ -179,13 +175,14 @@ impl Cache { debug!("{:#?}", &json); match parser::desc(&mut rdesc, json) { None => return Err(Error::NoneError), - Some(false) => return - if self.is_session_bad().await { + Some(false) => { + return if self.is_session_bad().await { Err(Error::CookieError) } else { Err(Error::PremiumError) - }, - Some(true) => () + } + } + Some(true) => (), } // update the question @@ -215,7 +212,8 @@ impl Cache { .await? .json() .await?, - ).ok_or(Error::NoneError)?; + ) + .ok_or(Error::NoneError)?; let t = Tag { r#tag: rslug.to_string(), r#refs: serde_json::to_string(&ids)?, @@ -258,22 +256,20 @@ impl Cache { let mut code: String = "".to_string(); let maybe_file_testcases: Option = test_cases_path(&p) - .map(|filename| { - let mut tests = "".to_string(); - File::open(filename) - .and_then(|mut file_descriptor| file_descriptor.read_to_string(&mut tests)) - .map(|_| Some(tests)) - .unwrap_or(None) - }) - .unwrap_or(None); + .map(|filename| { + let mut tests = "".to_string(); + File::open(filename) + .and_then(|mut file_descriptor| file_descriptor.read_to_string(&mut tests)) + .map(|_| Some(tests)) + .unwrap_or(None) + }) + .unwrap_or(None); // Takes test cases using following priority // 1. cli parameter // 2. test cases from the file // 3. sample test case from the task - let testcase = testcase - .or(maybe_file_testcases) - .unwrap_or(d.case); + let testcase = testcase.or(maybe_file_testcases).unwrap_or(d.case); File::open(code_path(&p, None)?)?.read_to_string(&mut code)?; @@ -286,10 +282,19 @@ impl Cache { json.insert("data_input", testcase); let url = match run { - Run::Test => conf.sys.urls.get("test").ok_or(Error::NoneError)?.replace("$slug", &p.slug), + Run::Test => conf + .sys + .urls + .get("test") + .ok_or(Error::NoneError)? + .replace("$slug", &p.slug), Run::Submit => { json.insert("judge_type", "large".to_string()); - conf.sys.urls.get("submit").ok_or(Error::NoneError)?.replace("$slug", &p.slug) + conf.sys + .urls + .get("submit") + .ok_or(Error::NoneError)? + .replace("$slug", &p.slug) } }; @@ -297,7 +302,11 @@ impl Cache { json, [ url, - conf.sys.urls.get("problems").ok_or(Error::NoneError)?.replace("$slug", &p.slug), + conf.sys + .urls + .get("problems") + .ok_or(Error::NoneError)? + .replace("$slug", &p.slug), ], )) } @@ -309,13 +318,9 @@ impl Cache { trace!("Run veriy recursion..."); std::thread::sleep(Duration::from_micros(3000)); - let json: VerifyResult = self.resp_to_json( - self - .clone() - .0 - .verify_result(rid.clone()) - .await? - ).await?; + let json: VerifyResult = self + .resp_to_json(self.clone().0.verify_result(rid.clone()).await?) + .await?; Ok(json) } @@ -343,8 +348,10 @@ impl Cache { // Check if leetcode accepted the Run request if match run { Run::Test => run_res.interpret_id.is_empty(), - Run::Submit => run_res.submission_id == 0 - } { return Err(Error::CookieError) } + Run::Submit => run_res.submission_id == 0, + } { + return Err(Error::CookieError); + } let mut res: VerifyResult = VerifyResult::default(); while res.state != "SUCCESS" { diff --git a/src/cache/models.rs b/src/cache/models.rs index 2624233..bedc089 100644 --- a/src/cache/models.rs +++ b/src/cache/models.rs @@ -57,15 +57,15 @@ impl std::fmt::Display for Problem { 1 => { id.push_str(&SPACE.repeat(2)); id.push_str(&self.fid.to_string()); - id.push_str(&SPACE.to_string()); + id.push_str(SPACE); } 2 => { - id.push_str(&SPACE.to_string()); + id.push_str(SPACE); id.push_str(&self.fid.to_string()); - id.push_str(&SPACE.to_string()); + id.push_str(SPACE); } 3 => { - id.push_str(&SPACE.to_string()); + id.push_str(SPACE); id.push_str(&self.fid.to_string()); } 4 => { @@ -268,7 +268,7 @@ impl std::fmt::Display for VerifyResult { &"Runtime: ".before_spaces(7).dimmed(), &self.status.status_runtime.dimmed(), &"\nYour input:".after_spaces(4), - &self.data_input.replace("\n", "↩ "), + &self.data_input.replace('\n', "↩ "), &"\nOutput:".after_spaces(8), ca, &"\nExpected:".after_spaces(6), @@ -342,7 +342,7 @@ impl std::fmt::Display for VerifyResult { " Runtime: ".dimmed(), &self.status.status_runtime.dimmed(), &"\nYour input:".after_spaces(4), - &self.data_input.replace("\n", "↩ "), + &self.data_input.replace('\n', "↩ "), &"\nOutput:".after_spaces(8), ca, &"\nExpected:".after_spaces(6), @@ -373,7 +373,7 @@ impl std::fmt::Display for VerifyResult { .bold() .yellow(), &"Last case:".after_spaces(5).dimmed(), - &self.submit.last_testcase.replace("\n", "↩ ").dimmed(), + &self.submit.last_testcase.replace('\n', "↩ ").dimmed(), &"\nOutput:".after_spaces(8), self.code_output[0], &"\nExpected:".after_spaces(6), @@ -385,7 +385,7 @@ impl std::fmt::Display for VerifyResult { "\n{}\n\n{}{}\n", &self.status.status_msg.yellow().bold(), &"Last case:".after_spaces(5).dimmed(), - &self.data_input.replace("\n", "↩ "), + &self.data_input.replace('\n', "↩ "), )?, // Output Timeout Exceeded // @@ -393,7 +393,12 @@ impl std::fmt::Display for VerifyResult { // if anybody reach this, welcome to fix this! 13 | 14 => write!(f, "\n{}\n", &self.status.status_msg.yellow().bold(),)?, // Runtime error - 15 => write!(f, "\n{}\n{}\n'", &self.status.status_msg.red().bold(), &self.status.runtime_error)?, + 15 => write!( + f, + "\n{}\n{}\n'", + &self.status.status_msg.red().bold(), + &self.status.runtime_error + )?, // Compile Error 20 => write!( f, @@ -436,7 +441,7 @@ impl std::fmt::Display for VerifyResult { f, "{}{}", &"Stdout:".after_spaces(8).purple(), - &self.std_output.replace("\n", &"\n".after_spaces(15)) + &self.std_output.replace('\n', &"\n".after_spaces(15)) ) } else { write!(f, "") @@ -495,7 +500,7 @@ mod verify { #[serde(default)] pub status_runtime: String, #[serde(default)] - pub runtime_error: String + pub runtime_error: String, } #[derive(Debug, Default, Deserialize)] diff --git a/src/cfg.rs b/src/cfg.rs index ba57d59..410088d 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -5,9 +5,9 @@ //! //! + Edit leetcode.toml at `~/.leetcode/leetcode.toml` directly //! + Use `leetcode config` to update it +use crate::Error; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs, path::PathBuf}; -use crate::Error; const DEFAULT_CONFIG: &str = r#" # usually you don't wanna change those @@ -150,8 +150,11 @@ pub struct Storage { impl Storage { /// convert root path pub fn root(&self) -> Result { - let home = dirs::home_dir().ok_or(Error::NoneError)?.to_string_lossy().to_string(); - let path = self.root.replace("~", &home); + let home = dirs::home_dir() + .ok_or(Error::NoneError)? + .to_string_lossy() + .to_string(); + let path = self.root.replace('~', &home); Ok(path) } diff --git a/src/cmds/test.rs b/src/cmds/test.rs index 37c0e7f..bf88011 100644 --- a/src/cmds/test.rs +++ b/src/cmds/test.rs @@ -1,6 +1,6 @@ //! Test command -use crate::Error; use super::Command; +use crate::Error; use async_trait::async_trait; use clap::{App, ArgMatches}; @@ -49,11 +49,10 @@ impl Command for TestCommand { use crate::cache::{Cache, Run}; let id: i32 = m.value_of("id").ok_or(Error::NoneError)?.parse()?; let testcase = m.value_of("testcase"); - let case_str: Option; - match testcase { - Some(case) => case_str = Option::from(case.replace("\\n", "\n")), - _ => case_str = None, - } + let case_str: Option = match testcase { + Some(case) => Option::from(case.replace("\\n", "\n")), + _ => None, + }; let cache = Cache::new()?; let res = cache.exec_problem(id, Run::Test, case_str).await?; diff --git a/tests/de.rs b/tests/de.rs index 06d30df..2a90009 100644 --- a/tests/de.rs +++ b/tests/de.rs @@ -1,5 +1,4 @@ use leetcode_cli::cache::models::VerifyResult; -use serde_json; #[test] fn de_from_test_success() { From 925e0fa47e188e83b520e13c4a99680e05574107 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 3 Jul 2022 10:02:57 +0800 Subject: [PATCH 02/10] feat: upgrade dep version, and use Rust 2021 Edition --- Cargo.toml | 42 +++++++++++++++++++++--------------------- src/bin/lc.rs | 3 +-- src/cli.rs | 16 ++++++++-------- src/cmds/data.rs | 12 ++++++------ src/cmds/edit.rs | 11 +++++------ src/cmds/exec.rs | 9 ++++----- src/cmds/list.rs | 20 ++++++++++---------- src/cmds/mod.rs | 8 ++++---- src/cmds/pick.rs | 22 ++++++++++++---------- src/cmds/stat.rs | 8 ++++---- src/cmds/test.rs | 9 ++++----- src/flag.rs | 8 ++++---- src/plugins/chrome.rs | 9 ++++++--- 13 files changed, 89 insertions(+), 88 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 85699e8..1bce70f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ path = "src/bin/lc.rs" name = "leetcode-cli" version = "0.3.11" authors = ["clearloop "] -edition = "2018" +edition = "2021" description = "Leet your code in command-line." repository = "https://github.com/clearloop/leetcode-cli" license = "MIT" @@ -16,33 +16,33 @@ keywords = ["cli", "games", "leetcode"] readme = './README.md' [dependencies] -async-trait = "0.1.41" -tokio = "0.2.22" -clap = "2.33.0" -colored = "1.9.1" -dirs = "2.0.2" -env_logger = "0.7.1" -escaper = "0.1.0" -keyring = "0.8.0" -log = "0.4" -openssl = "0.10.26" -pyo3 = { version = "0.8.5", optional = true } -rand = "0.7.2" -serde = { version = "1.0.104", features = ["derive"] } -serde_json = "1.0.44" -toml = "0.5.5" -regex = "1" +async-trait = "0.1.56" +tokio = { version = "1", features = ["full"] } +clap = { version = "3.2.8", features = ["cargo"] } +colored = "2.0.0" +dirs = "4.0.0" +env_logger = "0.9.0" +escaper = "0.1.1" +keyring = "1.1.2" +log = "0.4.17" +openssl = "0.10.40" +pyo3 = { version = "0.16.5", optional = true } +rand = "0.8.5" +serde = { version = "1.0.138", features = ["derive"] } +serde_json = "1.0.82" +toml = "0.5.9" +regex = "1.5.6" [dependencies.diesel] -version = "1.4.3" +version = "1.4.8" features = ["sqlite"] [dependencies.reqwest] -version = "0.10.3" +version = "0.11.11" features = ["gzip", "json"] [dev-dependencies.cargo-husky] -version = "1" +version = "1.5.0" default-features = false features = ["precommit-hook", "user-hooks"] @@ -50,4 +50,4 @@ features = ["precommit-hook", "user-hooks"] pym = ["pyo3"] [target.'cfg(target_family = "unix")'.dependencies] -nix = "0.17.0" +nix = "0.24.1" diff --git a/src/bin/lc.rs b/src/bin/lc.rs index f353003..4364cb7 100644 --- a/src/bin/lc.rs +++ b/src/bin/lc.rs @@ -2,8 +2,7 @@ use leetcode_cli::cli; use tokio::runtime::Builder; fn main() { - if let Err(err) = Builder::new() - .basic_scheduler() + if let Err(err) = Builder::new_multi_thread() .enable_all() .build() .expect("Build tokio runtime failed") diff --git a/src/cli.rs b/src/cli.rs index df86b7b..f232a2d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -44,19 +44,19 @@ pub async fn main() -> Result<(), Error> { if m.is_present("debug") { Debug::handler()?; } else { - env_logger::from_env(env_logger::Env::new().default_filter_or("info")) + env_logger::Builder::from_env(env_logger::Env::new().default_filter_or("info")) .format_timestamp(None) .init(); } match m.subcommand() { - ("data", Some(sub_m)) => Ok(DataCommand::handler(sub_m).await?), - ("edit", Some(sub_m)) => Ok(EditCommand::handler(sub_m).await?), - ("exec", Some(sub_m)) => Ok(ExecCommand::handler(sub_m).await?), - ("list", Some(sub_m)) => Ok(ListCommand::handler(sub_m).await?), - ("pick", Some(sub_m)) => Ok(PickCommand::handler(sub_m).await?), - ("stat", Some(sub_m)) => Ok(StatCommand::handler(sub_m).await?), - ("test", Some(sub_m)) => Ok(TestCommand::handler(sub_m).await?), + Some(("data", sub_m)) => Ok(DataCommand::handler(sub_m).await?), + Some(("edit", sub_m)) => Ok(EditCommand::handler(sub_m).await?), + Some(("exec", sub_m)) => Ok(ExecCommand::handler(sub_m).await?), + Some(("list", sub_m)) => Ok(ListCommand::handler(sub_m).await?), + Some(("pick", sub_m)) => Ok(PickCommand::handler(sub_m).await?), + Some(("stat", sub_m)) => Ok(StatCommand::handler(sub_m).await?), + Some(("test", sub_m)) => Ok(TestCommand::handler(sub_m).await?), _ => Err(Error::MatchError), } } diff --git a/src/cmds/data.rs b/src/cmds/data.rs index 0ec57bf..2e837c9 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::{App, Arg, ArgMatches, SubCommand}; +use clap::{Command as ClapCommand, Arg, ArgMatches}; use colored::Colorize; /// Abstract `data` command @@ -25,28 +25,28 @@ pub struct DataCommand; #[async_trait] impl Command for DataCommand { /// `data` command usage - fn usage<'a, 'cache>() -> App<'a, 'cache> { - SubCommand::with_name("data") + fn usage<'a>() -> ClapCommand<'a> { + ClapCommand::new("data") .about("Manage Cache") .visible_alias("d") .arg( Arg::with_name("delete") .display_order(1) - .short("d") + .short('d') .long("delete") .help("Delete cache"), ) .arg( Arg::with_name("update") .display_order(2) - .short("u") + .short('u') .long("update") .help("Update cache"), ) } /// `data` handler - async fn handler(m: &ArgMatches<'_>) -> Result<(), Error> { + async fn handler(m: &ArgMatches) -> Result<(), Error> { use std::fs::File; use std::path::Path; diff --git a/src/cmds/edit.rs b/src/cmds/edit.rs index 21285fb..3252052 100644 --- a/src/cmds/edit.rs +++ b/src/cmds/edit.rs @@ -2,7 +2,7 @@ use crate::Error; use super::Command; use async_trait::async_trait; -use clap::{App, ArgMatches}; +use clap::{Command as ClapCommand, ArgMatches, Arg}; /// Abstract `edit` command /// @@ -25,14 +25,13 @@ pub struct EditCommand; #[async_trait] impl Command for EditCommand { /// `edit` usage - fn usage<'a, 'edit>() -> App<'a, 'edit> { - use clap::{Arg, SubCommand}; - SubCommand::with_name("edit") + fn usage<'a>() -> ClapCommand<'a> { + ClapCommand::new("edit") .about("Edit question by id") .visible_alias("e") .arg( Arg::with_name("lang") - .short("l") + .short('l') .long("lang") .takes_value(true) .help("Edit with specific language"), @@ -46,7 +45,7 @@ impl Command for EditCommand { } /// `edit` handler - async fn handler(m: &ArgMatches<'_>) -> Result<(), crate::Error> { + async fn handler(m: &ArgMatches) -> Result<(), crate::Error> { use crate::{cache::models::Question, Cache}; use std::fs::File; use std::io::Write; diff --git a/src/cmds/exec.rs b/src/cmds/exec.rs index 755fd37..e660f58 100644 --- a/src/cmds/exec.rs +++ b/src/cmds/exec.rs @@ -2,7 +2,7 @@ use crate::Error; use super::Command; use async_trait::async_trait; -use clap::{App, ArgMatches}; +use clap::{Command as ClapCommand, ArgMatches, Arg}; /// Abstract Exec Command /// @@ -25,9 +25,8 @@ pub struct ExecCommand; #[async_trait] impl Command for ExecCommand { /// `exec` usage - fn usage<'a, 'edit>() -> App<'a, 'edit> { - use clap::{Arg, SubCommand}; - SubCommand::with_name("exec") + fn usage<'a>() -> ClapCommand<'a> { + ClapCommand::new("exec") .about("Submit solution") .visible_alias("x") .arg( @@ -39,7 +38,7 @@ impl Command for ExecCommand { } /// `exec` handler - async fn handler(m: &ArgMatches<'_>) -> Result<(), crate::Error> { + 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()?; diff --git a/src/cmds/list.rs b/src/cmds/list.rs index b7a9b1e..1adc6c7 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::{App, Arg, ArgMatches, SubCommand}; +use clap::{Command as ClapCommand, Arg, ArgMatches}; /// Abstract `list` command /// /// ## handler @@ -72,34 +72,34 @@ static LIST_AFTER_HELP: &str = r#"EXAMPLES: #[async_trait] impl Command for ListCommand { /// `list` command usage - fn usage<'a, 'list>() -> App<'a, 'list> { - SubCommand::with_name("list") + fn usage<'a>() -> ClapCommand<'a> { + ClapCommand::new("list") .about("List problems") .visible_alias("l") .arg( Arg::with_name("category") - .short("c") + .short('c') .long("category") .takes_value(true) .help(CATEGORY_HELP), ) .arg( Arg::with_name("plan") - .short("p") + .short('p') .long("plan") .takes_value(true) .help("Invoking python scripts to filter questions"), ) .arg( Arg::with_name("query") - .short("q") + .short('q') .long("query") .takes_value(true) .help(QUERY_HELP), ) .arg( Arg::with_name("range") - .short("r") + .short('r') .long("range") .takes_value(true) .min_values(2) @@ -108,13 +108,13 @@ impl Command for ListCommand { .after_help(LIST_AFTER_HELP) .arg( Arg::with_name("stat") - .short("s") + .short('s') .long("stat") .help("Show statistics of listed problems"), ) .arg( Arg::with_name("tag") - .short("t") + .short('t') .long("tag") .takes_value(true) .help("Filter questions by tag"), @@ -131,7 +131,7 @@ impl Command for ListCommand { /// List commands contains "-c", "-q", "-s" flags. /// + matches with `-c` will override the default keyword. /// + `-qs` - async fn handler(m: &ArgMatches<'_>) -> Result<(), Error> { + async fn handler(m: &ArgMatches) -> Result<(), Error> { trace!("Input list command..."); let cache = Cache::new()?; diff --git a/src/cmds/mod.rs b/src/cmds/mod.rs index 224d3e0..cc00a0f 100644 --- a/src/cmds/mod.rs +++ b/src/cmds/mod.rs @@ -12,16 +12,16 @@ //! ``` use crate::err::Error; use async_trait::async_trait; -use clap::{App, ArgMatches}; +use clap::{Command as ClapCommand, ArgMatches}; /// Abstract commands' trait. #[async_trait] pub trait Command { - /// Usage of the spefic command - fn usage<'a, 'c>() -> App<'a, 'c>; + /// Usage of the specific command + fn usage<'a>() -> ClapCommand<'a>; /// The handler will deal [args, options,...] from the command-line - async fn handler(m: &ArgMatches<'_>) -> Result<(), Error>; + async fn handler(m: &ArgMatches) -> Result<(), Error>; } mod data; diff --git a/src/cmds/pick.rs b/src/cmds/pick.rs index 79d2751..1308aa7 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::{App, Arg, ArgMatches, SubCommand}; +use clap::{Arg, ArgMatches, Command as ClapCommand}; /// Abstract pick command /// /// ```sh @@ -43,35 +43,35 @@ s = starred S = not starred"#; #[async_trait] impl Command for PickCommand { /// `pick` usage - fn usage<'a, 'pick>() -> App<'a, 'pick> { - SubCommand::with_name("pick") + fn usage<'a>() -> ClapCommand<'a> { + ClapCommand::new("pick") .about("Pick a problem") .visible_alias("p") .arg(Arg::with_name("id").help("Problem id").takes_value(true)) .arg( Arg::with_name("plan") - .short("p") + .short('p') .long("plan") .takes_value(true) .help("Invoking python scripts to filter questions"), ) .arg( Arg::with_name("query") - .short("q") + .short('q') .long("query") .takes_value(true) .help(QUERY_HELP), ) .arg( Arg::with_name("tag") - .short("t") + .short('t') .long("tag") .takes_value(true) .help("Filter questions by tag"), ) .arg( Arg::with_name("daily") - .short("d") + .short('d') .long("daily") .takes_value(false) .help("Pick today's daily challenge"), @@ -79,7 +79,7 @@ impl Command for PickCommand { } /// `pick` handler - async fn handler(m: &ArgMatches<'_>) -> Result<(), Error> { + async fn handler(m: &ArgMatches) -> Result<(), Error> { use crate::cache::Cache; use rand::Rng; @@ -118,7 +118,9 @@ impl Command for PickCommand { let daily_id = if m.is_present("daily") { Some(cache.get_daily_problem_id().await?) - } else { None }; + } else { + None + }; let fid = m .value_of("id") @@ -126,7 +128,7 @@ impl Command for PickCommand { .or(daily_id) .unwrap_or_else(|| { // Pick random without specify id - let problem = &problems[rand::thread_rng().gen_range(0, problems.len())]; + let problem = &problems[rand::thread_rng().gen_range(0..problems.len())]; problem.fid }); diff --git a/src/cmds/stat.rs b/src/cmds/stat.rs index b8fea24..661ca98 100644 --- a/src/cmds/stat.rs +++ b/src/cmds/stat.rs @@ -1,7 +1,7 @@ //! status command use super::Command; use async_trait::async_trait; -use clap::{App, ArgMatches, SubCommand}; +use clap::{Command as ClapCommand, ArgMatches}; use colored::Colorize; /// Abstract statues command @@ -22,14 +22,14 @@ pub struct StatCommand; #[async_trait] impl Command for StatCommand { /// `stat` usage - fn usage<'a, 'stat>() -> App<'a, 'stat> { - SubCommand::with_name("stat") + fn usage<'a>() -> ClapCommand<'a> { + ClapCommand::new("stat") .about("Show simple chart about submissions") .visible_alias("s") } /// `stat` handler - async fn handler(_m: &ArgMatches<'_>) -> Result<(), crate::err::Error> { + async fn handler(_m: &ArgMatches) -> Result<(), crate::err::Error> { use crate::{helper::Digit, Cache}; let cache = Cache::new()?; diff --git a/src/cmds/test.rs b/src/cmds/test.rs index bf88011..62b4fc4 100644 --- a/src/cmds/test.rs +++ b/src/cmds/test.rs @@ -2,7 +2,7 @@ use super::Command; use crate::Error; use async_trait::async_trait; -use clap::{App, ArgMatches}; +use clap::{Arg, ArgMatches, Command as ClapCommand}; /// Abstract Test Command /// @@ -25,9 +25,8 @@ pub struct TestCommand; #[async_trait] impl Command for TestCommand { /// `test` usage - fn usage<'a, 'edit>() -> App<'a, 'edit> { - use clap::{Arg, SubCommand}; - SubCommand::with_name("test") + fn usage<'a>() -> ClapCommand<'a> { + ClapCommand::new("test") .about("Test question by id") .visible_alias("t") .arg( @@ -45,7 +44,7 @@ impl Command for TestCommand { } /// `test` handler - async fn handler(m: &ArgMatches<'_>) -> Result<(), Error> { + 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"); diff --git a/src/flag.rs b/src/flag.rs index 0264bb2..6706a06 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, 'f>() -> Arg<'a, 'f>; + fn usage<'a>() -> Arg<'a>; fn handler() -> Result<(), Error>; } @@ -20,15 +20,15 @@ pub trait Flag { pub struct Debug; impl Flag for Debug { - fn usage<'a, 'f>() -> Arg<'a, 'f> { + fn usage<'a>() -> Arg<'a> { Arg::with_name("debug") - .short("d") + .short('d') .long("debug") .help("debug mode") } fn handler() -> Result<(), Error> { - env_logger::from_env(Env::default().default_filter_or("leetcode")).init(); + env_logger::Builder::from_env(Env::default().default_filter_or("leetcode")).init(); Ok(()) } diff --git a/src/plugins/chrome.rs b/src/plugins/chrome.rs index 8922b7a..20ba976 100644 --- a/src/plugins/chrome.rs +++ b/src/plugins/chrome.rs @@ -1,6 +1,6 @@ use crate::{cache, Error}; use diesel::prelude::*; -use keyring::Keyring; +use keyring::Entry; use openssl::{hash, pkcs5, symm}; use std::collections::HashMap; @@ -73,7 +73,7 @@ pub fn cookies() -> Result { } // Get system password - let ring = Keyring::new("Chrome Safe Storage", "Chrome"); + let ring = Entry::new("Chrome Safe Storage", "Chrome"); let pass = ring.get_password().expect("Get Password failed"); // Decode cookies @@ -86,7 +86,10 @@ pub fn cookies() -> Result { Ok(Ident { csrf: m.get("csrftoken").ok_or(Error::NoneError)?.to_string(), - session: m.get("LEETCODE_SESSION").ok_or(Error::NoneError)?.to_string(), + session: m + .get("LEETCODE_SESSION") + .ok_or(Error::NoneError)? + .to_string(), }) } From b7e128bf23f77180eec93b574b6116b8e8438c51 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 12 Jul 2022 22:38:53 +0800 Subject: [PATCH 03/10] fix: issue 80 1. use code.test config to open/close writing test file 2. use code.comment_leading to comment the desc 3. use code.comment_problem_desc to open/close the description about the problem 4. use code.start_marker to mark the code begin 5. use code.end_marker to mark the code end --- src/cache/mod.rs | 7 +++---- src/cache/models.rs | 21 ++++++++++++--------- src/cfg.rs | 31 ++++++++++++++++++++++++------- src/cmds/edit.rs | 36 +++++++++++++++++------------------- src/cmds/mod.rs | 2 -- 5 files changed, 56 insertions(+), 41 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 2eec037..2495daf 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -6,7 +6,6 @@ mod sql; use self::models::*; use self::schemas::{problems::dsl::*, tags::dsl::*}; use self::sql::*; -use crate::cmds::{CODE_END, CODE_START}; use crate::helper::test_cases_path; use crate::{cfg, err::Error, plugins::LeetCode}; use colored::Colorize; @@ -285,9 +284,9 @@ impl Cache { File::open(code_path(&p, None)?)?.read_to_string(&mut code)?; - let begin = code.find(CODE_START).unwrap_or(0); - let end = code.find(CODE_END).unwrap_or(code.len()); - let code = if let Some(solution) = code.get(begin..end) { + let begin = code.find(&conf.code.start_marker).unwrap_or(0); + let end = code.find(&conf.code.end_marker).unwrap_or(code.len()); + let code = if let Some(solution) = code.get((begin + conf.code.start_marker.len())..end) { solution.to_string() } else { code diff --git a/src/cache/models.rs b/src/cache/models.rs index b338adf..f951e44 100644 --- a/src/cache/models.rs +++ b/src/cache/models.rs @@ -39,11 +39,12 @@ impl Problem { _ => "Unknown", } } - pub fn desc_comment(&self) -> String { + pub fn desc_comment(&self, conf: &Config) -> String { let mut res = String::new(); - res += format!("// Category: {}\n", self.category).as_str(); - res += format!("// Level: {}\n", self.display_level(),).as_str(); - res += format!("// Percent: {}%\n\n", self.percent).as_str(); + let comment_leading = &conf.code.comment_leading; + res += format!("{} Category: {}\n", comment_leading, self.category).as_str(); + res += format!("{} Level: {}\n", comment_leading, self.display_level(),).as_str(); + res += format!("{} Percent: {}%\n\n", comment_leading, self.percent).as_str(); res + "\n" } @@ -148,13 +149,13 @@ impl Question { self.content.render() } - pub fn desc_comment(&self) -> String { + pub fn desc_comment(&self, conf: &Config) -> String { let desc = self.content.render(); - let mut res = desc - .lines() - .fold("/*\n".to_string(), |acc, e| acc + " * " + e + "\n"); - res += " */\n"; + let mut res = desc.lines().fold("\n".to_string(), |acc, e| { + acc + " " + conf.code.comment_leading.as_str() + " " + e + "\n" + }); + res += " \n"; res } @@ -481,7 +482,9 @@ impl std::fmt::Display for VerifyResult { } } +use crate::Config; use verify::*; + mod verify { use super::super::parser::ssr; use serde::Deserialize; diff --git a/src/cfg.rs b/src/cfg.rs index 21079e4..dc2b69c 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -57,6 +57,11 @@ favorite_delete = "https://leetcode.com/list/api/questions/$hash/$id" [code] editor = "vim" lang = "rust" +comment_problem_desc = false +comment_leading = "///" +start_marker = "@lc code=start" +end_marker = "@lc code=start" +test = true pick = "${fid}.${slug}" submission = "${fid}.${slug}.${sid}.${ac}" @@ -66,10 +71,10 @@ session = "" [storage] root = "~/.leetcode" -cache = "Problems" scripts = "scripts" -# absolutely path for the code, other use root as parent dir code = "code" +# absolutely path for the cache, other use root as parent dir +cache = "~/.cache/leetcode" "##; /// Sync with `~/.leetcode/config.toml` @@ -134,6 +139,11 @@ pub struct Code { pub editor: String, #[serde(rename(serialize = "editor-args", deserialize = "editor-args"))] pub editor_args: Option>, + pub start_marker: String, + pub end_marker: String, + pub comment_problem_desc: bool, + pub comment_leading: String, + pub test: bool, pub lang: String, pub pick: String, pub submission: String, @@ -163,16 +173,23 @@ impl Storage { /// get cache path pub fn cache(&self) -> Result { - let root = &self.root()?; - Ok(PathBuf::from(root) - .join(&self.cache) + let home = dirs::home_dir() + .ok_or(Error::NoneError)? .to_string_lossy() - .to_string()) + .to_string(); + let path = PathBuf::from(self.cache.replace('~', &home)); + if !path.is_dir() { + info!("Generate cache dir at {:?}.", &path); + fs::DirBuilder::new().recursive(true).create(&path)?; + } + + Ok(path.join("Problems").to_string_lossy().to_string()) } /// get code path pub fn code(&self) -> Result { - let p = PathBuf::from(&self.code); + let root = &self.root()?; + let p = PathBuf::from(root).join(&self.code); if !PathBuf::from(&p).exists() { fs::create_dir(&p)? } diff --git a/src/cmds/edit.rs b/src/cmds/edit.rs index 039ad2e..36f3517 100644 --- a/src/cmds/edit.rs +++ b/src/cmds/edit.rs @@ -22,9 +22,6 @@ use clap::{Arg, ArgMatches, Command as ClapCommand}; /// ``` pub struct EditCommand; -pub const CODE_START: &str = r#"// @lc code=start"#; -pub const CODE_END: &str = r#"// @lc code=end"#; - #[async_trait] impl Command for EditCommand { /// `edit` usage @@ -45,13 +42,6 @@ impl Command for EditCommand { .required(true) .help("question id"), ) - .arg( - Arg::with_name("test") - .long("test") - .short('t') - .required(false) - .help("write test file"), - ) } /// `edit` handler @@ -66,16 +56,16 @@ impl Command for EditCommand { let problem = cache.get_problem(id)?; let mut conf = cache.to_owned().0.conf; - let test_flag = m.contains_id("test"); + let test_flag = conf.code.test; - let p_desc_comment = problem.desc_comment(); + 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.sync()?; } - let lang = conf.code.lang; + let lang = &conf.code.lang; let path = crate::helper::code_path(&problem, Some(lang.to_owned()))?; if !Path::new(&path).exists() { @@ -87,20 +77,28 @@ impl Command for EditCommand { let question: Question = qr?; let mut file_code = File::create(&path)?; - let question_desc = question.desc_comment() + "\n"; + let question_desc = question.desc_comment(&conf) + "\n"; let test_path = crate::helper::test_cases_path(&problem)?; let mut file_tests = File::create(&test_path)?; let mut flag = false; for d in question.defs.0 { - if d.value == lang { + if d.value == *lang { flag = true; - file_code.write_all(p_desc_comment.as_bytes())?; - file_code.write_all(question_desc.as_bytes())?; - file_code.write_all((CODE_START.to_string() + "\n").as_bytes())?; + if conf.code.comment_problem_desc { + file_code.write_all(p_desc_comment.as_bytes())?; + file_code.write_all(question_desc.as_bytes())?; + } + file_code.write_all( + (conf.code.comment_leading.clone() + " " + &conf.code.start_marker + "\n") + .as_bytes(), + )?; file_code.write_all((d.code.to_string() + "\n").as_bytes())?; - file_code.write_all((CODE_END.to_string() + "\n").as_bytes())?; + file_code.write_all( + (conf.code.comment_leading.clone() + " " + &conf.code.end_marker + "\n") + .as_bytes(), + )?; if test_flag { file_tests.write_all(question.all_cases.as_bytes())?; diff --git a/src/cmds/mod.rs b/src/cmds/mod.rs index 30e5841..58a9dc3 100644 --- a/src/cmds/mod.rs +++ b/src/cmds/mod.rs @@ -38,5 +38,3 @@ pub use list::ListCommand; pub use pick::PickCommand; pub use stat::StatCommand; pub use test::TestCommand; - -pub use edit::{CODE_END, CODE_START}; From 91c81177930bf3da665d81b43e4facda3162f51e Mon Sep 17 00:00:00 2001 From: David Date: Tue, 12 Jul 2022 23:27:00 +0800 Subject: [PATCH 04/10] fix: create empty test file --- src/cmds/edit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmds/edit.rs b/src/cmds/edit.rs index 36f3517..332bc23 100644 --- a/src/cmds/edit.rs +++ b/src/cmds/edit.rs @@ -80,7 +80,6 @@ impl Command for EditCommand { let question_desc = question.desc_comment(&conf) + "\n"; let test_path = crate::helper::test_cases_path(&problem)?; - let mut file_tests = File::create(&test_path)?; let mut flag = false; for d in question.defs.0 { @@ -101,6 +100,7 @@ impl Command for EditCommand { )?; if test_flag { + let mut file_tests = File::create(&test_path)?; file_tests.write_all(question.all_cases.as_bytes())?; } } From 51548e03ff1cf2febdff3903131853deb4938f5a Mon Sep 17 00:00:00 2001 From: David Date: Wed, 13 Jul 2022 00:18:25 +0800 Subject: [PATCH 05/10] revert: use superscript and subscript, not ^ and _ --- src/helper.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/src/helper.rs b/src/helper.rs index c4a70a3..da7d693 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -90,9 +90,46 @@ mod filter { } } +pub fn superscript(n: u8) -> String { + match n { + x if x >= 10 => format!("{}{}", superscript(n / 10), superscript(n % 10)), + 0 => "⁰".to_string(), + 1 => "¹".to_string(), + 2 => "²".to_string(), + 3 => "³".to_string(), + 4 => "⁴".to_string(), + 5 => "⁵".to_string(), + 6 => "⁶".to_string(), + 7 => "⁷".to_string(), + 8 => "⁸".to_string(), + 9 => "⁹".to_string(), + _ => n.to_string(), + } +} + +pub fn subscript(n: u8) -> String { + match n { + x if x >= 10 => format!("{}{}", subscript(n / 10), subscript(n % 10)), + 0 => "₀".to_string(), + 1 => "₁".to_string(), + 2 => "₂".to_string(), + 3 => "₃".to_string(), + 4 => "₄".to_string(), + 5 => "₅".to_string(), + 6 => "₆".to_string(), + 7 => "₇".to_string(), + 8 => "₈".to_string(), + 9 => "₉".to_string(), + _ => n.to_string(), + } +} + /// Render html to command-line mod html { + use crate::helper::{subscript, superscript}; + use regex::Captures; use scraper::Html; + /// Html render plugin pub trait HTML { fn render(&self) -> String; @@ -100,12 +137,20 @@ mod html { impl HTML for String { fn render(&self) -> String { - let rep = self - .replace(r#""#, "") - .replace(r#""#, "^") - .replace(r#""#, "") - .replace(r#""#, "_"); - let frag = Html::parse_fragment(rep.as_str()); + let sup_re = regex::Regex::new(r"(?P[0-9]*)").unwrap(); + let sub_re = regex::Regex::new(r"(?P[0-9]*)").unwrap(); + + let res = sup_re.replace_all(&self, |cap: &Captures| { + let num: u8 = format!("{}", &cap["num"]).parse().unwrap(); + superscript(num) + }); + + let res = sub_re.replace_all(&res, |cap: &Captures| { + let num: u8 = format!("{}", &cap["num"]).parse().unwrap(); + subscript(num) + }); + + let frag = Html::parse_fragment(&res); let res = frag .root_element() From efde24fe0c20359890aa783d43949223fb2807d5 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 13 Jul 2022 21:28:52 +0800 Subject: [PATCH 06/10] fix: not generate leetcode_tmp.toml --- src/cfg.rs | 2 +- src/err.rs | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/cfg.rs b/src/cfg.rs index dc2b69c..8e11df2 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -9,7 +9,7 @@ use crate::Error; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs, path::PathBuf}; -const DEFAULT_CONFIG: &str = r##" +pub const DEFAULT_CONFIG: &str = r##" # usually you don't wanna change those [sys] categories = [ diff --git a/src/err.rs b/src/err.rs index 3ae8cc1..5f007e9 100644 --- a/src/err.rs +++ b/src/err.rs @@ -1,4 +1,5 @@ //! Errors in leetcode-cli +use crate::cfg::{root, DEFAULT_CONFIG}; use crate::cmds::{Command, DataCommand}; use colored::Colorize; use std::fmt; @@ -98,19 +99,31 @@ impl std::convert::From for Error { // toml impl std::convert::From for Error { - fn from(err: toml::de::Error) -> Self { - Error::ParseError(format!( - "{}, {}{}{}{}{}{}{}{}", - err, + fn from(_err: toml::de::Error) -> Self { + let conf = root().unwrap().join("leetcode_tmp.toml"); + std::fs::write(&conf, &DEFAULT_CONFIG[1..]).unwrap(); + #[cfg(debug_assertions)] + let err_msg = format!( + "{}, {}{}{}{}{}{}", + _err, "Parse config file failed, ", "leetcode-cli has just generated a new leetcode.toml at ", "~/.leetcode/leetcode_tmp.toml,".green().bold().underline(), " the current one at ", "~/.leetcode/leetcode.toml".yellow().bold().underline(), - "seems missing some keys, please compare to ", - "the tmp one and add them up : )\n", - ".", - )) + " seems missing some keys, Please compare the new file and add the missing keys.\n", + ); + #[cfg(not(debug_assertions))] + let err_msg = format!( + "{}{}{}{}{}{}", + "Parse config file failed, ", + "leetcode-cli has just generated a new leetcode.toml at ", + "~/.leetcode/leetcode_tmp.toml,".green().bold().underline(), + " the current one at ", + "~/.leetcode/leetcode.toml".yellow().bold().underline(), + " seems missing some keys, Please compare the new file and add the missing keys.\n", + ); + Error::ParseError(err_msg) } } From 1d6ba1b21c8d3c781e17c2e098431ee71eaef00f Mon Sep 17 00:00:00 2001 From: David Date: Wed, 13 Jul 2022 21:30:33 +0800 Subject: [PATCH 07/10] fix: clippy warning --- src/helper.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helper.rs b/src/helper.rs index da7d693..60efcd8 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -140,13 +140,13 @@ mod html { let sup_re = regex::Regex::new(r"(?P[0-9]*)").unwrap(); let sub_re = regex::Regex::new(r"(?P[0-9]*)").unwrap(); - let res = sup_re.replace_all(&self, |cap: &Captures| { - let num: u8 = format!("{}", &cap["num"]).parse().unwrap(); + let res = sup_re.replace_all(self, |cap: &Captures| { + let num: u8 = cap["num"].to_string().parse().unwrap(); superscript(num) }); let res = sub_re.replace_all(&res, |cap: &Captures| { - let num: u8 = format!("{}", &cap["num"]).parse().unwrap(); + let num: u8 = cap["num"].to_string().parse().unwrap(); subscript(num) }); From dbe72ac2b014d4e2a6aa2380216eb1d3b6cde2f9 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 13 Jul 2022 21:34:37 +0800 Subject: [PATCH 08/10] chore: upgrade dep --- Cargo.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9b37f4a..3ab4163 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,20 +17,20 @@ readme = './README.md' [dependencies] async-trait = "0.1.56" -tokio = { version = "1", features = ["full"] } -clap = { version = "3.2.8", features = ["cargo"] } +tokio = { version = "1.19.2", features = ["full"] } +clap = { version = "3.2.10", features = ["cargo"] } colored = "2.0.0" dirs = "4.0.0" env_logger = "0.9.0" -keyring = "1.1.2" +keyring = "1.2.0" log = "0.4.17" -openssl = "0.10.40" +openssl = "0.10.41" pyo3 = { version = "0.16.5", optional = true } rand = "0.8.5" -serde = { version = "1.0.138", features = ["derive"] } +serde = { version = "1.0.139", features = ["derive"] } serde_json = "1.0.82" toml = "0.5.9" -regex = "1.5.6" +regex = "1.6.0" scraper = "0.13.0" [dependencies.diesel] From 61470f1507194e00e2d31acf15b509c394a32c1e Mon Sep 17 00:00:00 2001 From: David Date: Thu, 14 Jul 2022 22:11:13 +0800 Subject: [PATCH 09/10] backwark compability --- src/cache/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 2495daf..c89c0da 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -284,10 +284,12 @@ impl Cache { File::open(code_path(&p, None)?)?.read_to_string(&mut code)?; - let begin = code.find(&conf.code.start_marker).unwrap_or(0); - let end = code.find(&conf.code.end_marker).unwrap_or(code.len()); - let code = if let Some(solution) = code.get((begin + conf.code.start_marker.len())..end) { - solution.to_string() + let begin = code.find(&conf.code.start_marker); + let end = code.find(&conf.code.end_marker); + let code = if let (Some(l), Some(r)) = (begin, end) { + code.get((l + conf.code.start_marker.len())..r) + .map(|s| s.to_string()) + .unwrap_or_else(|| code) } else { code }; From a7b1b9bb3be7f6b356f63c04333d06a2ccf6f466 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 14 Jul 2022 22:18:58 +0800 Subject: [PATCH 10/10] cfg marker trun on/off --- src/cache/mod.rs | 16 ++++++++++------ src/cfg.rs | 2 ++ src/cmds/edit.rs | 26 ++++++++++++++++++-------- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index c89c0da..345b3ea 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -284,12 +284,16 @@ impl Cache { File::open(code_path(&p, None)?)?.read_to_string(&mut code)?; - let begin = code.find(&conf.code.start_marker); - let end = code.find(&conf.code.end_marker); - let code = if let (Some(l), Some(r)) = (begin, end) { - code.get((l + conf.code.start_marker.len())..r) - .map(|s| s.to_string()) - .unwrap_or_else(|| code) + let code = if conf.code.edit_code_marker { + let begin = code.find(&conf.code.start_marker); + let end = code.find(&conf.code.end_marker); + if let (Some(l), Some(r)) = (begin, end) { + code.get((l + conf.code.start_marker.len())..r) + .map(|s| s.to_string()) + .unwrap_or_else(|| code) + } else { + code + } } else { code }; diff --git a/src/cfg.rs b/src/cfg.rs index 8e11df2..184e3e0 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -57,6 +57,7 @@ favorite_delete = "https://leetcode.com/list/api/questions/$hash/$id" [code] editor = "vim" lang = "rust" +edit_code_marker = false comment_problem_desc = false comment_leading = "///" start_marker = "@lc code=start" @@ -139,6 +140,7 @@ pub struct Code { pub editor: String, #[serde(rename(serialize = "editor-args", deserialize = "editor-args"))] pub editor_args: Option>, + pub edit_code_marker: bool, pub start_marker: String, pub end_marker: String, pub comment_problem_desc: bool, diff --git a/src/cmds/edit.rs b/src/cmds/edit.rs index 332bc23..a6ec981 100644 --- a/src/cmds/edit.rs +++ b/src/cmds/edit.rs @@ -89,15 +89,25 @@ impl Command for EditCommand { file_code.write_all(p_desc_comment.as_bytes())?; file_code.write_all(question_desc.as_bytes())?; } - file_code.write_all( - (conf.code.comment_leading.clone() + " " + &conf.code.start_marker + "\n") - .as_bytes(), - )?; + if conf.code.edit_code_marker { + file_code.write_all( + (conf.code.comment_leading.clone() + + " " + + &conf.code.start_marker + + "\n") + .as_bytes(), + )?; + } file_code.write_all((d.code.to_string() + "\n").as_bytes())?; - file_code.write_all( - (conf.code.comment_leading.clone() + " " + &conf.code.end_marker + "\n") - .as_bytes(), - )?; + if conf.code.edit_code_marker { + file_code.write_all( + (conf.code.comment_leading.clone() + + " " + + &conf.code.end_marker + + "\n") + .as_bytes(), + )?; + } if test_flag { let mut file_tests = File::create(&test_path)?;