lla 0.1.6

A lightweight ls replacement
use crate::ls::LongLister;

use super::file_formater::FileFormatter;
use termion::color;
pub struct TreeFileFormatter;
use std::path::PathBuf;

#[derive(Clone)]
pub struct FSTreeItem {
    pub name: String,
    pub children: Vec<FSTreeItem>,
    pub type_: String,
    pub git_status: Option<String>,
}

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

    pub fn display_files_tree_format(
        &self,
        files: &[PathBuf],
        _long: Option<bool>,
        git: Option<bool>,
    ) {
        let mut root = FSTreeItem {
            name: ".".to_string(),
            children: Vec::new(),
            type_: "dir".to_string(),
            git_status: None,
        };

        for file in files {
            let path = file.clone();
            let mut current_node = &mut root;

            for component in path.components() {
                let component_name = component.as_os_str().to_str().unwrap().to_string();
                let child_index = current_node
                    .children
                    .iter()
                    .position(|c| c.name == component_name);

                if let Some(index) = child_index {
                    current_node = &mut current_node.children[index];
                } else {
                    let full_path = file.parent().unwrap().join(component_name.clone());
                    let path_buf = PathBuf::from(component_name.clone());

                    let new_node = FSTreeItem {
                        name: component_name.clone(),
                        children: Vec::new(),
                        type_: path_buf
                            .is_dir()
                            .then(|| "dir".to_string())
                            .unwrap_or("file".to_string()),
                        git_status: Some(self.get_git_status(full_path.to_str().unwrap())),
                    };
                    current_node.children.push(new_node);
                    let new_index = current_node.children.len() - 1;
                    current_node = &mut current_node.children[new_index];
                }
            }
        }
        self.print_tree(&root, 0, true, git);
    }

    fn get_file_color(&self, file_type: &str) -> termion::color::Fg<termion::color::Rgb> {
        match file_type {
            "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 print_tree(&self, tree: &FSTreeItem, depth: usize, is_last: bool, git: Option<bool>) {
        let mut prefix = String::new();

        for _ in 0..depth {
            prefix.push_str("");
        }
        if depth > 0 {
            prefix.push_str(if is_last { "└── " } else { "├── " });
        }

        prefix.push_str(&tree.name);
        println!("{}", prefix);

        for (i, child) in tree.children.iter().enumerate() {
            let type_color = self.get_file_color(&child.type_);
            let is_last_child = i == tree.children.len() - 1;
            let mut child = child.clone();
            let git_status = child.git_status.clone().unwrap();

            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));
            let reset_color = color::Fg(color::Rgb(255, 255, 255));
            for (status, color) in status_color_map {
                if git_status.contains(status) {
                    status_color = color;
                    break;
                }
            }
            child.name = if is_last_child {
                if let Some(git) = git {
                    if git {
                        format!(
                            "{}{}{}{}{}{}{}{}",
                            "└── ",
                            type_color,
                            child.name,
                            reset_color,
                            " ",
                            status_color,
                            git_status,
                            reset_color,
                        )
                    } else {
                        format!("{}{}{}{}", "└── ", type_color, child.name, reset_color)
                    }
                } else {
                    format!("{}{}{}{}", "└── ", type_color, child.name, reset_color)
                }
            } else {
                if let Some(git) = git {
                    if git {
                        format!(
                            "{}{}{}{}{}{}{}{}",
                            "├── ",
                            type_color,
                            child.name,
                            reset_color,
                            " ",
                            status_color,
                            git_status,
                            reset_color,
                        )
                    } else {
                        format!("{}{}{}{}", "├── ", type_color, child.name, reset_color)
                    }
                } else {
                    format!("{}{}{}{}", "├── ", type_color, child.name, reset_color)
                }
            };
            self.print_tree(&child, depth + 1, is_last_child, git);
        }
    }

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

impl FileFormatter for TreeFileFormatter {
    fn display_files(&self, files: &[PathBuf], _long: Option<bool>, git: Option<bool>) {
        self.display_files_tree_format(files, _long, git);
    }
}