rsftch 0.5.1

Lightning fast hardware fetch tool written in rust.
use colored::Colorize;
use std::env;

mod ascii;
mod color_config;
mod fns;
mod info_config;

use crate::ascii::*;
use crate::color_config::*;
use crate::fns::*;
use crate::info_config::*;

fn main() {
    let mut args: Vec<String> = env::args().collect();
    let mut overriden_ascii: Option<String> = None;
    let mut info_custom_config: Option<String> = None;
    let mut color_custom_config: Option<String> = None;
    let mut use_info_custom_config = true;
    let mut use_color_custom_config = true;
    let mut margin: i8 = 1;

    for count in 0..args.len() {
        match args[count].as_str() {
            "-h" | "--help" | "--usage" => return help(),
            "--ignore-color-config" => use_color_custom_config = false,
            "--ignore-info-config" => use_info_custom_config = false,
            "--ignore-config" => {
                use_color_custom_config = false;
                use_info_custom_config = false;
            }
            "-m" | "--margin" => {
                if count + 1 < args.len() {
                    margin = args[count + 1].parse().unwrap();
                } else {
                    println!("{} Missing argument for margin.\n", "[ERROR]".red());
                    return help();
                }
            }
            "-o" | "--override" => {
                if count + 1 < args.len() {
                    overriden_ascii = Some(std::mem::take(&mut args[count + 1]));
                } else {
                    println!("{} Missing argument for override.\n", "[ERROR]".red());
                }
            }
            "-i" | "--info-config" => {
                if count + 1 < args.len() {
                    info_custom_config = Some(std::mem::take(&mut args[count + 1]));
                } else {
                    println!(
                        "{} Missing argument for custom info config file.\n",
                        "[ERROR]".red()
                    );
                }
            }
            "-c" | "--color-config" => {
                if count + 1 < args.len() {
                    color_custom_config = Some(std::mem::take(&mut args[count + 1]));
                } else {
                    println!(
                        "{} Missing argument for custom color config file.\n",
                        "[ERROR]".red()
                    );
                }
            }
            _ => {
                continue;
            }
        };
    }

    info(
        overriden_ascii,
        margin,
        use_info_custom_config,
        !use_color_custom_config,
        info_custom_config,
        color_custom_config,
    );
}

#[derive(Clone)]
struct InfoItem {
    title: &'static str,
    alignment_space: i8,
    icon: &'static str,
    value: String,
}

fn print_ascii(
    ascii_art: String,
    color: Color,
    overriden_colors: bool,
    custom_color_config_file: Option<String>,
) -> String {
    if !overriden_colors {
        match color {
            Color::Green => ascii_art.green().bold().to_string(),
            Color::Red => ascii_art.bright_red().bold().to_string(),
            Color::Purple => ascii_art.purple().bold().to_string(),
            Color::Yellow => ascii_art.yellow().bold().to_string(),
            Color::Blue => ascii_art.blue().bold().to_string(),
            Color::Black => ascii_art.black().bold().to_string(),
            Color::White => ascii_art.white().bold().to_string(),
        }
    } else {
        print_ascii(
            ascii_art,
            get_color_config(
                "color0".to_string(),
                !overriden_colors,
                custom_color_config_file.clone(),
            ),
            false,
            custom_color_config_file,
        )
    }
}

fn print_data(infos: &InfoItem, color: Color, connector: &'static str) -> String {
    let arrow = "~>";
    let coloreds = match color {
        Color::Green => (
            connector.green().to_string(),
            infos.icon.green().to_string(),
            arrow.green().to_string(),
        ),
        Color::Red => (
            connector.bright_red().to_string(),
            infos.icon.bright_red().to_string(),
            arrow.bright_red().to_string(),
        ),
        Color::Purple => (
            connector.purple().to_string(),
            infos.icon.purple().to_string(),
            arrow.purple().to_string(),
        ),
        Color::Yellow => (
            connector.yellow().to_string(),
            infos.icon.yellow().to_string(),
            arrow.yellow().to_string(),
        ),
        Color::Blue => (
            connector.blue().to_string(),
            infos.icon.blue().to_string(),
            arrow.blue().to_string(),
        ),
        Color::Black => (
            connector.black().to_string(),
            infos.icon.black().to_string(),
            arrow.black().to_string(),
        ),
        Color::White => (connector.to_string(), "".to_string(), arrow.to_string()),
    };

    let alignment_space = " ".repeat(infos.alignment_space as usize);

    format!(
        "{}{}  {}{}{}  {}",
        coloreds.0, coloreds.1, infos.title, alignment_space, coloreds.2, infos.value
    )
    .to_string()
}

fn info(
    overriden_ascii: Option<String>,
    margin: i8,
    use_custom_info_config: bool,
    use_custom_color_config: bool,
    custom_info_config_file: Option<String>,
    custom_color_config_file: Option<String>,
) {
    let distro = InfoItem {
        title: "distro",
        alignment_space: 2,
        icon: "",
        value: get_os_release_pretty_name(overriden_ascii.clone(), "NAME")
            .expect("Failed getting distro name"),
    };

    let hostname = InfoItem {
        title: "host",
        alignment_space: 4,
        icon: "󱩛",
        value: uname_n(),
    };

    let shell = InfoItem {
        title: "shell",
        alignment_space: 3,
        icon: "",
        value: shell_name(),
    };

    let kernel = InfoItem {
        title: "kernel",
        alignment_space: 2,
        icon: "",
        value: uname_r(),
    };

    let packs = InfoItem {
        title: "packs",
        alignment_space: 3,
        icon: "󰿺",
        value: get_packages(),
    };

    let user = InfoItem {
        title: "user",
        alignment_space: 4,
        icon: "",
        value: whoami(),
    };

    let term = InfoItem {
        title: "term",
        alignment_space: 4,
        icon: "",
        value: get_terminal(),
    };

    let de = InfoItem {
        title: "de/wm",
        alignment_space: 3,
        icon: "",
        value: get_wm(),
    };

    let cpu = InfoItem {
        title: "cpu",
        alignment_space: 5,
        icon: "󰍛",
        value: get_cpu_info(),
    };

    let mem = InfoItem {
        title: "mem",
        alignment_space: 5,
        icon: "",
        value: get_mem(),
    };

    let res = InfoItem {
        title: "res",
        alignment_space: 5,
        icon: "",
        value: get_res(),
    };

    let uptime = InfoItem {
        title: "uptime",
        alignment_space: 2,
        icon: "󰄉",
        value: match get_uptime() {
            Err(_err) => "".to_string(),
            Ok(time) => time,
        },
    };

    let gpu = InfoItem {
        title: "gpu",
        alignment_space: 5,
        icon: "󰍹",
        value: match get_gpu_info() {
            Err(_err) => "".to_string(),
            Ok(gpu_info) => gpu_info,
        },
    };

    let parse_json_lists = |set| {
        let mut info_set: Vec<InfoItem> = vec![];
        for i in get_info(set, use_custom_info_config, custom_info_config_file.clone()) {
            let info = match i.as_str() {
                "os" | "distro" => &distro,
                "host" | "hostname" => &hostname,
                "shell" => &shell,
                "kernel" => &kernel,
                "packs" | "packages" => &packs,
                "user" | "username" => &user,
                "term" | "terminal" => &term,
                "de" | "dewm" | "wm" => &de,
                "cpu" | "processor" => &cpu,
                "gpu" | "graphics" => &gpu,
                "mem" | "memory" => &mem,
                "uptime" => &uptime,
                "res" | "display" | "resolution" => &res,
                _ => &distro,
            };
            info_set.push(info.clone());
        }
        info_set
    };

    let info_set1 = parse_json_lists("info1");
    let info_set2 = parse_json_lists("info2");
    let info_set3 = parse_json_lists("info3");

    let margin_spaces = " ".repeat(margin as usize);
    let distroascii = print_ascii(
        get_distro_ascii(overriden_ascii),
        get_color_config(
            "color0".to_string(),
            use_custom_color_config,
            custom_color_config_file.clone(),
        ),
        !use_custom_color_config,
        custom_color_config_file.clone(),
    );
    let infos1 = (1, info_set1);
    let infos2 = (2, info_set2);
    let infos3 = (3, info_set3);
    let mut info_sets = vec![infos1, infos2, infos3];

    println!("{}\n", distroascii);

    for (idx, infos) in info_sets.iter_mut().enumerate() {
        if idx > 0 {
            println!();
        }

        loop_over_data(
            &mut infos.1,
            margin_spaces.clone(),
            infos.0,
            use_custom_color_config,
            custom_color_config_file.clone(),
        );
    }
}

fn loop_over_data(
    list: &mut Vec<InfoItem>,
    margin: String,
    section: i8,
    use_custom_config: bool,
    custom_color_config_file: Option<String>,
) {
    list.retain(|s| !s.value.is_empty());
    let last = list.len();

    for (idx, item) in list.iter_mut().enumerate() {
        let connector: &'static str;
        let color = get_color_config(
            format!("color{}", section),
            use_custom_config,
            custom_color_config_file.clone(),
        );

        if idx == 0 {
            connector = "╭─";
        } else if idx == last - 1 {
            connector = "╰─";
        } else {
            connector = "├─";
        }

        println!("{}{}", margin, print_data(item, color, connector));
    }
}