1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! Pick command
use super::Command;
use crate::err::Error;
use clap::{App, Arg, ArgMatches, SubCommand};

/// Abstract pick command
///
/// ```sh
/// leetcode-pick
/// Pick a problem
///
/// USAGE:
///     leetcode pick [OPTIONS] [id]
///
/// FLAGS:
///     -h, --help       Prints help information
///     -V, --version    Prints version information
///
/// OPTIONS:
///     -q, --query <query>    Fliter questions by conditions:
///                            Uppercase means negative
///                            e = easy     E = m+h
///                            m = medium   M = e+h
///                            h = hard     H = e+m
///                            d = done     D = not done
///                            l = locked   L = not locked
///                            s = starred  S = not starred
///
/// ARGS:
///     <id>    Problem id
/// ```
pub struct PickCommand;

static QUERY_HELP: &str = r#"Fliter questions by conditions:
Uppercase means negative
e = easy     E = m+h
m = medium   M = e+h
h = hard     H = e+m
d = done     D = not done
l = locked   L = not locked
s = starred  S = not starred"#;

impl Command for PickCommand {
    /// `pick` usage
    fn usage<'a, 'pick>() -> App<'a, 'pick> {
        SubCommand::with_name("pick")
            .about("Pick a problem")
            .visible_alias("p")
            .arg(Arg::with_name("id").help("Problem id").takes_value(true))
            .arg(
                Arg::with_name("query")
                    .short("q")
                    .long("query")
                    .takes_value(true)
                    .help(QUERY_HELP),
            )
            .arg(
                Arg::with_name("tag")
                    .short("t")
                    .long("tag")
                    .takes_value(true)
                    .help("Filter questions by tag"),
            )
    }

    /// `pick` handler
    fn handler(m: &ArgMatches) -> Result<(), Error> {
        use crate::cache::Cache;
        use rand::Rng;

        let cache = Cache::new()?;
        let mut problems = cache.get_problems()?;
        if problems.is_empty() {
            cache.download_problems()?;
            Self::handler(m)?;
            return Ok(());
        }

        // filtering...
        // pym scripts
        if m.is_present("plan") {
            let ids = crate::pym::exec(m.value_of("plan").unwrap_or(""))?;
            crate::helper::squash(&mut problems, ids)?;
        }

        // tag filter
        if m.is_present("tag") {
            let ids = cache
                .clone()
                .get_tagged_questions(m.value_of("tag").unwrap_or(""))?;
            crate::helper::squash(&mut problems, ids)?;
        }

        // query filter
        if m.is_present("query") {
            let query = m.value_of("query")?;
            crate::helper::filter(&mut problems, query.to_string());
        }

        if let Some(id) = m.value_of("id") {
            problems.retain(|x| x.fid.to_string() == id);
        }

        let problem = &problems[rand::thread_rng().gen_range(0, problems.len())];

        let r = cache.get_question(problem.fid);
        if r.is_err() {
            let e = r.err()?;
            eprintln!("{:?}", &e);
            if let Error::FeatureError(_) | Error::NetworkError(_) = e {
                Self::handler(m)?;
            }
        } else {
            println!("{}", r?);
        }

        Ok(())
    }
}