lla 0.1.7

A lightweight ls replacement
use super::file_formater::FileFormatter;
use super::LongFile;
use crate::ls::LongLister;
use std::path::PathBuf;
use termion::{color, style};

pub struct DefaultFileFormatter;

impl DefaultFileFormatter {
    pub fn new() -> DefaultFileFormatter {
        DefaultFileFormatter
    }
}

impl FileFormatter for DefaultFileFormatter {
    fn display_files(&self, files: &[PathBuf], long: Option<bool>, git: Option<bool>) {
        if let Some(true) = long {
            if let Some(true) = git {
                self.display_files_git_format(files);
            } else {
                self.display_files_long_format(files);
            }
        } else {
            self.display_files_default_format(files);
        }
    }
}

impl DefaultFileFormatter {
    fn get_color_for_file_type(
        &self,
        long_file: &LongFile,
    ) -> termion::color::Fg<termion::color::Rgb> {
        match long_file.file_type.as_str() {
            "file" => color::Fg(color::Rgb(255, 255, 255)),
            "dir" => color::Fg(color::Rgb(0, 255, 255)),
            "link" => color::Fg(color::Rgb(255, 255, 0)),
            _ => color::Fg(color::Rgb(255, 0, 255)),
        }
    }

    fn get_config_files_colors(
        &self,
        long_file: &LongFile,
    ) -> termion::color::Fg<termion::color::Rgb> {
        let config_files_vec = vec![
            ".bashrc",
            ".zshrc",
            ".vimrc",
            ".gitconfig",
            "package.json",
            "Cargo.toml",
            "Gemfile",
            "Rakefile",
            "Makefile",
            "Makefile.lock",
            "docker-compose.yml",
            "docker-compose.yaml",
            "dockerfile",
            "pnpm-lock.yaml",
            "pnpmfile.js",
            ".npmrc",
            "yarn.lock",
            "yarn.lock",
        ];
        let is_dir = long_file.file_type == "dir";
        for config_file in config_files_vec {
            if long_file.name == config_file {
                return color::Fg(color::Rgb(255, 0, 255));
            }
        }
        if is_dir {
            return color::Fg(color::Rgb(0, 255, 255));
        }
        color::Fg(color::Rgb(255, 255, 255))
    }

    fn display_files_default_format(&self, files: &[PathBuf]) {
        for file in files {
            if let Some(name) = file.file_name() {
                if let Some(name_str) = name.to_str() {
                    if file.is_dir() {
                        println!("{}{}{}", color::Fg(color::Blue), name_str, style::Reset);
                    } else {
                        println!("{}", name_str);
                    }
                }
            }
        }
    }

    fn display_files_long_format(&self, files: &[PathBuf]) {
        if files.is_empty() {
            return;
        }
        let mut max_total: usize = 0;
        for file in files {
            let long_file = LongFile::new(file);
            let total = long_file.date.format("%b %e %H:%M").to_string().len() - 2;
            if total > max_total {
                max_total = total;
            }
        }

        for file in files {
            let long_file = LongFile::new(file);
            println!(
                "{} {} {} {:>width$} {} {:>4} {} {:>width$} {} {:>width$} {} {:>width$} {} {:>width$} {}",
                self.get_color_for_file_type(&long_file),
                long_file.permissions,
                color::Fg(color::Reset),
                long_file.links,
                color::Fg(color::LightBlue),
                long_file.user,
                color::Fg(color::Reset),
                long_file.group,
                color::Fg(color::LightGreen),
                LongLister::new().format_size(long_file.size),
                color::Fg(color::Reset),
                long_file.date.format("%b %e %H:%M"),
                color::Fg(color::Reset),
                self.get_config_files_colors(&long_file),
                long_file.name,
                width = max_total - 2
            );
        }
    }

    fn display_files_git_format(&self, files: &[PathBuf]) {
        if files.is_empty() {
            return;
        }

        let max_total = self.calculate_max_total(files);

        for file in files {
            let long_file = LongFile::new(file);
            let git_status = self.get_git_status(&long_file.name);
            let status_color_map = vec![
                ("?", color::Fg(color::Rgb(255, 255, 0))),
                ("A", color::Fg(color::Rgb(0, 255, 0))),
                ("M", color::Fg(color::Rgb(255, 0, 0))),
                ("R", color::Fg(color::Rgb(255, 0, 255))),
                ("C", color::Fg(color::Rgb(255, 0, 255))),
                ("D", color::Fg(color::Rgb(255, 0, 0))),
                ("!", color::Fg(color::Rgb(255, 0, 255))),
            ];

            let mut status_color = color::Fg(color::Rgb(255, 255, 255));
            for (status, color) in status_color_map {
                if git_status.contains(status) {
                    status_color = color;
                    break;
                }
            }

            println!(
                "{} {} {} {:>width$} {} {:>4} {} {:>width$} {} {:>width$} {} {:>width$} {} {:>width$} {} {} {} {}",
                self.get_color_for_file_type(&long_file),
                long_file.permissions,
                color::Fg(color::Reset),
                long_file.links,
                color::Fg(color::LightBlue),
                long_file.user,
                color::Fg(color::Reset),
                long_file.group,
                color::Fg(color::LightGreen),
                LongLister::new().format_size(long_file.size),
                color::Fg(color::Reset),
                long_file.date.format("%b %e %H:%M"),
                color::Fg(color::Reset),
                status_color,
                git_status,
                color::Fg(color::Reset),
                self.get_config_files_colors(&long_file),
                long_file.name,
                width = max_total - 2
            );
        }
    }
    fn calculate_max_total(&self, files: &[PathBuf]) -> usize {
        let mut max_total: usize = 0;
        for file in files {
            let long_file = LongFile::new(file);
            let total = long_file.date.format("%b %e %H:%M").to_string().len() - 2;
            if total > max_total {
                max_total = total;
            }
        }
        max_total
    }

    fn get_git_status(&self, file_name: &str) -> String {
        let git_status = LongLister::new().get_git_status(file_name);
        return git_status;
    }
}