mapm-cli 6.1.0

The command-line implementation of mapm
//! Used for the `find` and `preview-all` commands
//!
//! Two params:
//! - filter list (each filter is either a `Show` or `Hide` from the `Filter` enum defined in mapm lib)
//! - Show/Hide/None views list (None translates to hide none)
use mapm::problem::Filter;
use mapm::problem::FilterAction;

use colour::*;

use std::fs;
use std::path::Path;

use crate::utils::msg;

/// Parses string vector of args for filters

pub fn parse_filters(args: &[String]) -> Vec<FilterAction> {
    let mut filters: Vec<FilterAction> = Vec::new();
    for arg in args {
        if &arg[0..1] == "!" {
            filters.push(FilterAction::Negative(parse_filter(&arg[1..])));
        } else {
            filters.push(FilterAction::Positive(parse_filter(arg)));
        }
    }
    filters
}

/// Internal function that parses each individual filter

fn parse_filter(arg: &str) -> Filter {
    match arg.find("<=") {
        Some(idx) => match arg[idx + 2..].parse::<usize>() {
            Ok(val) => Filter::Le {
                key: String::from(&arg[0..idx]),
                val,
            },
            Err(_) => {
                e_red_ln!("Filter key `{}` was passed with non-integer value `{}`, despite non-equality comparison operator `<=`", &arg[0..idx], &arg[idx+2..]);
                quit::with_code(exitcode::USAGE);
            }
        },
        None => match arg.find(">=") {
            Some(idx) => match arg[idx + 2..].parse::<usize>() {
                Ok(val) => Filter::Ge {
                    key: String::from(&arg[0..idx]),
                    val,
                },
                Err(_) => {
                    e_red_ln!("Filter key `{}` was passed with non-integer value `{}`, despite non-equality comparison operator `>=`", &arg[0..idx], &arg[idx+2..]);
                    quit::with_code(exitcode::USAGE);
                }
            },

            None => match arg.find('=') {
                Some(idx) => Filter::Eq {
                    key: String::from(&arg[0..idx]),
                    val: String::from(&arg[idx + 1..]),
                },
                None => match arg.find('<') {
                    Some(idx) => match arg[idx + 1..].parse::<usize>() {
                        Ok(val) => Filter::Lt {
                            key: String::from(&arg[0..idx]),
                            val,
                        },
                        Err(_) => {
                            e_red_ln!("Filter key `{}` was passed with non-integer value `{}`, despite non-equality comparison operator `<`", &arg[0..idx], &arg[idx+1..]);
                            quit::with_code(exitcode::USAGE);
                        }
                    },
                    None => match arg.find('>') {
                        Some(idx) => match arg[idx + 1..].parse::<usize>() {
                            Ok(val) => Filter::Gt {
                                key: String::from(&arg[0..idx]),
                                val,
                            },
                            Err(_) => {
                                e_red_ln!("Filter key `{}` was passed with non-integer value `{}`, despite non-equality comparison operator `>`", &arg[0..idx], &arg[idx+1..]);
                                quit::with_code(exitcode::USAGE);
                            }
                        },
                        None => Filter::Exists {
                            key: String::from(arg),
                        },
                    },
                },
            },
        },
    }
}

/// Returns vector of problem *names* given filters

pub fn filtered_names(filters: &[FilterAction], problem_dir: &Path) -> Vec<String> {
    let mut filtered_names: Vec<String> = Vec::new();
    for file in fs::read_dir(problem_dir).unwrap() {
        if file
            .as_ref()
            .unwrap()
            .path()
            .extension()
            .and_then(std::ffi::OsStr::to_str)
            != Some("yml")
        {
            continue;
        }
        let name = String::from(
            file.as_ref()
                .unwrap()
                .path()
                .file_stem()
                .unwrap()
                .to_str()
                .unwrap(),
        );
        let problem_res = mapm::problem::fetch_problem(&name, problem_dir);
        match problem_res {
            Ok(problem) => {
                if problem.filter(filters).is_some() {
                    filtered_names.push(name);
                }
            }
            Err(msg) => {
                e_yellow_ln!("Source of error is {}.yml", name);
                msg::print_err(&msg);
            }
        }
    }
    filtered_names
}