nxfetch 0.3.0

A minimal, fast and batteries included fetcher!
Documentation
use clap::Parser;
use colored::Colorize;
use itertools::{EitherOrBoth::*, Itertools};
use nxfetch::{
    args::{FetchCommand, InfoField},
    logo::Logo,
};
use std::cmp::Ordering;
use std::iter::repeat;

fn main() {
    let args = FetchCommand::parse();

    let logo = match args.no_logo || args.raw {
        false => Logo::new(args.logo),
        true => Logo::empty(),
    };

    let modules: Vec<(usize, String)> = (match args.modules.is_empty() {
        true => vec![
            // title
            InfoField::Title,
            InfoField::Empty,
            // system
            InfoField::OS,
            InfoField::Kernel,
            InfoField::Uptime,
            // hardware
            InfoField::CPU,
            InfoField::Memory,
            InfoField::Disk,
            // environment
            InfoField::Terminal,
            InfoField::Desktop,
            // colors
            InfoField::Empty,
            InfoField::ColoursDual,
        ],
        false => args.modules,
    })
    .iter()
    .map(|info_field| info_field.to_microfetcher())
    .flat_map(|fetcher| {
        fetcher
            .as_str(args.no_module_names || args.raw)
            .lines()
            .map(String::from)
            .collect::<Vec<String>>()
            .into_iter()
            .enumerate()
            .map(move |(idx, value)| {
                (
                    match (idx, args.raw) {
                        (0, true) => 0,
                        (0, false) => fetcher.get_name().len(),
                        _ => 1,
                    },
                    match idx == 0 {
                        true => value,
                        false => format!("{}{}", ". ".bold(), value),
                    },
                )
            })
    })
    .collect();

    let padding_before = if args.raw { 0 } else { args.padding_before };
    let padding_between = if args.raw || args.no_logo {
        0
    } else {
        args.padding_between
    };

    let module_name_max_len = *modules
        .iter()
        .map(|(module_name_len, _)| module_name_len)
        .max()
        .unwrap();

    let difference = logo.lines.len() as isize - modules.len() as isize;
    let (logo_vec, modules_vec): (Vec<String>, Vec<(usize, String)>) = match difference.cmp(&0) {
        Ordering::Less => (
            repeat(String::new())
                .take(difference.unsigned_abs() / 2)
                .chain(logo.lines)
                .collect(),
            modules.into_iter().collect(),
        ),
        Ordering::Equal => (logo.lines, modules),
        Ordering::Greater => (
            logo.lines,
            repeat((0, String::new()))
                .take(difference.unsigned_abs() / 2)
                .chain(modules)
                .collect(),
        ),
    };

    for pair in logo_vec.iter().zip_longest(modules_vec.iter()) {
        let (l, r, module_name_len) = match pair {
            Both(l, r) => (
                l.to_owned() + &" ".repeat(logo.max_len - Logo::get_len(l)),
                r.1.to_owned(),
                r.0,
            ),
            Left(l) => (
                l.to_owned() + &" ".repeat(logo.max_len - Logo::get_len(l)),
                " ".to_string(),
                0,
            ),
            Right(r) => (" ".repeat(logo.max_len), r.1.to_owned(), r.0),
        };

        let padding_between = if !args.no_module_names {
            padding_between + module_name_max_len - module_name_len
        } else {
            padding_between
        };

        println!(
            "{}",
            format!(
                "{}{}{}{}",
                " ".repeat(padding_before),
                l,
                " ".repeat(padding_between),
                r
            )
            .trim_end()
        );
    }
}