Skip to content
Merged
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ 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"
Expand All @@ -32,6 +31,7 @@ serde = { version = "1.0.138", features = ["derive"] }
serde_json = "1.0.82"
toml = "0.5.9"
regex = "1.5.6"
scraper = "0.13.0"

[dependencies.diesel]
version = "1.4.8"
Expand Down
46 changes: 33 additions & 13 deletions src/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ 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;
use diesel::prelude::*;
Expand All @@ -26,7 +28,7 @@ pub enum Run {
Submit,
}

impl std::default::Default for Run {
impl Default for Run {
fn default() -> Self {
Run::Submit
}
Expand All @@ -37,7 +39,7 @@ impl std::default::Default for Run {
pub struct Cache(pub LeetCode);

impl Cache {
/// Ref to sqliteconnection
/// Ref to sqlite connection
fn conn(&self) -> Result<SqliteConnection, Error> {
Ok(conn(self.0.conf.storage.cache()?))
}
Expand Down Expand Up @@ -236,10 +238,10 @@ impl Cache {
&self,
run: Run,
rfid: i32,
testcase: Option<String>,
test_case: Option<String>,
) -> Result<(HashMap<&'static str, String>, [String; 2]), Error> {
trace!("pre run code...");
use crate::helper::{code_path, test_cases_path};
use crate::helper::code_path;
use std::fs::File;
use std::io::Read;

Expand All @@ -256,30 +258,48 @@ impl Cache {
let mut code: String = "".to_string();

let maybe_file_testcases: Option<String> = test_cases_path(&p)
.map(|filename| {
.map(|file_name| {
let mut tests = "".to_string();
File::open(filename)
File::open(file_name)
.and_then(|mut file_descriptor| file_descriptor.read_to_string(&mut tests))
.map(|_| Some(tests))
.unwrap_or(None)
})
.unwrap_or(None);

let maybe_all_testcases: Option<String> = if d.all_cases.is_empty() {
None
} else {
Some(d.all_cases.to_string())
};

// 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);
// 2. if test cases file exist, use the file test cases(user can edit it)
// 3. test cases from problem desc all test cases
// 4. sample test case from the task
let test_case = test_case
.or(maybe_file_testcases)
.or(maybe_all_testcases)
.unwrap_or(d.case);

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) {
solution.to_string()
} else {
code
};

json.insert("lang", conf.code.lang.to_string());
json.insert("question_id", p.id.to_string());
json.insert("typed_code", code);

// pass manually data
json.insert("name", p.name.to_string());
json.insert("data_input", testcase);
json.insert("data_input", test_case);

let url = match run {
Run::Test => conf
Expand Down Expand Up @@ -315,7 +335,7 @@ impl Cache {
async fn recur_verify(&self, rid: String) -> Result<VerifyResult, Error> {
use std::time::Duration;

trace!("Run veriy recursion...");
trace!("Run verify recursion...");
std::thread::sleep(Duration::from_micros(3000));

let json: VerifyResult = self
Expand All @@ -330,10 +350,10 @@ impl Cache {
&self,
rfid: i32,
run: Run,
testcase: Option<String>,
test_case: Option<String>,
) -> Result<VerifyResult, Error> {
trace!("Exec problem filter —— Test or Submit");
let (json, [url, refer]) = self.pre_run_code(run.clone(), rfid, testcase).await?;
let (json, [url, refer]) = self.pre_run_code(run.clone(), rfid, test_case).await?;
trace!("Pre run code result {:?}, {:?}, {:?}", json, url, refer);

let run_res: RunCode = self
Expand Down
36 changes: 33 additions & 3 deletions src/cache/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@ pub struct Problem {
pub desc: String,
}

impl Problem {
fn display_level(&self) -> &str {
match self.level {
1 => "Easy",
2 => "Medium",
3 => "Hard",
_ => "Unknown",
}
}
pub fn desc_comment(&self) -> 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();

res + "\n"
}
}

static DONE: &str = " ✔";
static ETC: &str = "...";
static LOCK: &str = "🔒";
Expand Down Expand Up @@ -124,9 +143,20 @@ pub struct Question {
pub t_content: String,
}

impl std::fmt::Display for Question {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.content.render())
impl Question {
pub fn desc(&self) -> String {
self.content.render()
}

pub fn desc_comment(&self) -> String {
let desc = self.content.render();

let mut res = desc
.lines()
.fold("/*\n".to_string(), |acc, e| acc + " * " + e + "\n");
res += " */\n";

res
}
}

Expand Down
37 changes: 22 additions & 15 deletions src/cache/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ pub fn desc(q: &mut Question, v: Value) -> Option<bool> {
stats: serde_json::from_str(o.get("stats")?.as_str()?).ok()?,
defs: serde_json::from_str(o.get("codeDefinition")?.as_str()?).ok()?,
case: o.get("sampleTestCase")?.as_str()?.to_string(),
all_cases: o.get("exampleTestcases")
.unwrap_or(o.get("sampleTestCase")?) // soft fail to the sampleTestCase
.as_str()?
.to_string(),
all_cases: o
.get("exampleTestcases")
.unwrap_or(o.get("sampleTestCase")?) // soft fail to the sampleTestCase
.as_str()?
.to_string(),
metadata: serde_json::from_str(o.get("metaData")?.as_str()?).ok()?,
test: o.get("enableRunCode")?.as_bool()?,
t_content: o
Expand Down Expand Up @@ -85,29 +86,35 @@ pub fn tags(v: Value) -> Option<Vec<String>> {
Some(res)
}

/// daily parser
/// daily parser
pub fn daily(v: Value) -> Option<i32> {
trace!("Parse daily...");
v.as_object()?
.get("data")?.as_object()?
.get("activeDailyCodingChallengeQuestion")?.as_object()?
.get("question")?.as_object()?
.get("questionFrontendId")?.as_str()?
.parse().ok()
.get("data")?
.as_object()?
.get("activeDailyCodingChallengeQuestion")?
.as_object()?
.get("question")?
.as_object()?
.get("questionFrontendId")?
.as_str()?
.parse()
.ok()
}

/// user parser
pub fn user(v: Value) -> Option<Option<(String,bool)>> {
pub fn user(v: Value) -> Option<Option<(String, bool)>> {
// None => error while parsing
// Some(None) => User not found
// Some("...") => username
let user = v.as_object()?.get("data")?
.as_object()?.get("user")?;
if *user == Value::Null { return Some(None) }
let user = v.as_object()?.get("data")?.as_object()?.get("user")?;
if *user == Value::Null {
return Some(None);
}
let user = user.as_object()?;
Some(Some((
user.get("username")?.as_str()?.to_owned(),
user.get("isCurrentUserPremium")?.as_bool()?
user.get("isCurrentUserPremium")?.as_bool()?,
)))
}

Expand Down
14 changes: 7 additions & 7 deletions src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::Error;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fs, path::PathBuf};

const DEFAULT_CONFIG: &str = r#"
const DEFAULT_CONFIG: &str = r##"
# usually you don't wanna change those
[sys]
categories = [
Expand Down Expand Up @@ -65,11 +65,12 @@ csrf = ""
session = ""

[storage]
cache = "Problems"
code = "code"
root = "~/.leetcode"
cache = "Problems"
scripts = "scripts"
"#;
# absolutely path for the code, other use root as parent dir
code = "code"
"##;

/// Sync with `~/.leetcode/config.toml`
#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -169,10 +170,9 @@ impl Storage {

/// get code path
pub fn code(&self) -> Result<String, crate::Error> {
let root = &self.root()?;
let p = PathBuf::from(root).join(&self.code);
let p = PathBuf::from(&self.code);
if !PathBuf::from(&p).exists() {
std::fs::create_dir(&p)?
fs::create_dir(&p)?
}

Ok(p.to_string_lossy().to_string())
Expand Down
10 changes: 5 additions & 5 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
err::Error,
flag::{Debug, Flag},
};
use clap::{crate_name, crate_version, App, AppSettings};
use clap::{crate_name, crate_version};

/// This should be called before calling any cli method or printing any output.
pub fn reset_signal_pipe_handler() {
Expand All @@ -24,8 +24,8 @@ pub fn reset_signal_pipe_handler() {

/// Get maches
pub async fn main() -> Result<(), Error> {
let _ = reset_signal_pipe_handler();
let m = App::new(crate_name!())
reset_signal_pipe_handler();
let m = clap::Command::new(crate_name!())
.version(crate_version!())
.about("May the Code be with You 👻")
.subcommands(vec![
Expand All @@ -38,10 +38,10 @@ pub async fn main() -> Result<(), Error> {
TestCommand::usage().display_order(7),
])
.arg(Debug::usage())
.setting(AppSettings::ArgRequiredElseHelp)
.arg_required_else_help(true)
.get_matches();

if m.is_present("debug") {
if m.contains_id("debug") {
Debug::handler()?;
} else {
env_logger::Builder::from_env(env_logger::Env::new().default_filter_or("info"))
Expand Down
9 changes: 5 additions & 4 deletions src/cmds/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use super::Command;
use crate::{cache::Cache, helper::Digit, Error};
use async_trait::async_trait;
use clap::{Command as ClapCommand, Arg, ArgMatches};
use clap::{Arg, ArgMatches, Command as ClapCommand};
use colored::Colorize;

/// Abstract `data` command
Expand Down Expand Up @@ -58,7 +58,8 @@ impl Command for DataCommand {
let out = format!(
" {}{}",
Path::new(&path)
.file_name().ok_or(Error::NoneError)?
.file_name()
.ok_or(Error::NoneError)?
.to_string_lossy()
.to_string()
.digit(65 - (len.len() as i32))
Expand All @@ -72,13 +73,13 @@ impl Command for DataCommand {
title.push_str(&"-".repeat(65));

let mut flags = 0;
if m.is_present("delete") {
if m.contains_id("delete") {
flags += 1;
cache.clean()?;
println!("{}", "ok!".bright_green());
}

if m.is_present("update") {
if m.contains_id("update") {
flags += 1;
cache.update().await?;
println!("{}", "ok!".bright_green());
Expand Down
Loading