lx-ls 0.10.1

The file lister with personality! 🌟
use nu_ansi_term::Style;

use crate::fs::File;
use std::collections::HashMap;
use std::sync::LazyLock;

/// Icons for media-type classes (audio, image, video).
const ICON_AUDIO: char = '\u{f001}'; //
const ICON_IMAGE: char = '\u{f1c5}'; //
const ICON_VIDEO: char = '\u{f03d}'; //

/// Converts the style used to paint a file name into the style that should be
/// used to paint an icon.
///
/// - The background colour should be preferred to the foreground colour, as
///   if one is set, it’s the more β€œobvious” colour choice.
/// - If neither is set, just use the default style.
/// - Attributes such as bold or underline should not be used to paint the
///   icon, as they can make it look weird.
pub fn iconify_style(style: Style) -> Style {
    style
        .background
        .or(style.foreground)
        .map(Style::from)
        .unwrap_or_default()
}

static MAP_BY_NAME: LazyLock<HashMap<&'static str, char>> = LazyLock::new(|| {
    let mut m = HashMap::new();
    m.insert(".Trash", '\u{f1f8}'); // ο‡Έ
    m.insert(".atom", '\u{e764}'); // 
    m.insert(".bashprofile", '\u{e615}'); // ξ˜•
    m.insert(".bashrc", '\u{f489}'); // ο’‰
    m.insert(".git", '\u{f1d3}'); // 
    m.insert(".gitattributes", '\u{f1d3}'); // 
    m.insert(".gitconfig", '\u{f1d3}'); // 
    m.insert(".github", '\u{f408}'); // 
    m.insert(".gitignore", '\u{f1d3}'); // 
    m.insert(".gitmodules", '\u{f1d3}'); // 
    m.insert(".rvm", '\u{e21e}'); // 
    m.insert(".vimrc", '\u{e62b}'); // 
    m.insert(".vscode", '\u{e70c}'); // 
    m.insert(".zshrc", '\u{f489}'); // ο’‰
    m.insert("Cargo.lock", '\u{e7a8}'); // 
    m.insert("bin", '\u{e5fc}'); // ξ—Ό
    m.insert("config", '\u{e5fc}'); // ξ—Ό
    m.insert("docker-compose.yml", '\u{f308}'); // 
    m.insert("Dockerfile", '\u{f308}'); // 
    m.insert("ds_store", '\u{f179}'); // ο…Ή
    m.insert("gitignore_global", '\u{f1d3}'); // 
    m.insert("go.mod", '\u{e626}'); // 
    m.insert("go.sum", '\u{e626}'); // 
    m.insert("gradle", '\u{e256}'); // ξ‰–
    m.insert("gruntfile.coffee", '\u{e611}'); // ξ˜‘
    m.insert("gruntfile.js", '\u{e611}'); // ξ˜‘
    m.insert("gruntfile.ls", '\u{e611}'); // ξ˜‘
    m.insert("gulpfile.coffee", '\u{e610}'); // 
    m.insert("gulpfile.js", '\u{e610}'); // 
    m.insert("gulpfile.ls", '\u{e610}'); // 
    m.insert("hidden", '\u{f023}'); // ο€£
    m.insert("include", '\u{e5fc}'); // ξ—Ό
    m.insert("lib", '\u{f121}'); // ο„‘
    m.insert("localized", '\u{f179}'); // ο…Ή
    m.insert("Makefile", '\u{f489}'); // ο’‰
    m.insert("node_modules", '\u{e718}'); // 
    m.insert("npmignore", '\u{e71e}'); // 
    m.insert("PKGBUILD", '\u{f303}'); // οŒƒ
    m.insert("rubydoc", '\u{e73b}'); // 
    m.insert("yarn.lock", '\u{e718}'); // 

    m
});

/// Check if a file matches a media-type class and return its icon.
/// Uses the class system from config, so user-defined classes are respected.
fn class_icon(file: &File<'_>) -> Option<char> {
    static CLASS_ICONS: LazyLock<Vec<(glob::Pattern, char)>> = LazyLock::new(|| {
        let classes = crate::config::resolve_classes();
        let mut mappings = Vec::new();

        let class_to_icon: &[(&str, char)] = &[
            ("music", ICON_AUDIO),
            ("lossless", ICON_AUDIO),
            ("image", ICON_IMAGE),
            ("video", ICON_VIDEO),
        ];

        for &(class_name, icon) in class_to_icon {
            if let Some(patterns) = classes.get(class_name) {
                for pat_str in patterns {
                    if let Ok(pat) = glob::Pattern::new(pat_str) {
                        mappings.push((pat, icon));
                    }
                }
            }
        }
        mappings
    });

    let name = &file.name;
    CLASS_ICONS
        .iter()
        .find(|(pat, _)| pat.matches(name))
        .map(|(_, icon)| *icon)
}

pub fn icon_for_file(file: &File<'_>) -> char {
    if let Some(icon) = MAP_BY_NAME.get(file.name.as_str()) {
        *icon
    } else if file.points_to_directory() {
        match file.name.as_str() {
            "bin" => '\u{e5fc}',   // ξ—Ό
            ".git" => '\u{f1d3}',  // 
            ".idea" => '\u{e7b5}', // 
            _ => '\u{f115}',       // ο„•
        }
    } else if let Some(icon) = class_icon(file) {
        icon
    } else if let Some(ext) = file.ext.as_ref() {
        match ext.as_str() {
            "ai" => '\u{e7b4}',             // 
            "android" => '\u{e70e}',        // 
            "apk" => '\u{e70e}',            // 
            "apple" => '\u{f179}',          // ο…Ή
            "avi" => '\u{f03d}',            // ο€½
            "avif" => '\u{f1c5}',           // ο‡…
            "avro" => '\u{e60b}',           // ξ˜‹
            "awk" => '\u{f489}',            // ο’‰
            "bash" => '\u{f489}',           // ο’‰
            "bash_history" => '\u{f489}',   // ο’‰
            "bash_profile" => '\u{f489}',   // ο’‰
            "bashrc" => '\u{f489}',         // ο’‰
            "bat" => '\u{f17a}',            // ο…Ί
            "bats" => '\u{f489}',           // ο’‰
            "bmp" => '\u{f1c5}',            // ο‡…
            "bz" => '\u{f410}',             // 
            "bz2" => '\u{f410}',            // 
            "c" => '\u{e61e}',              // 
            "c++" => '\u{e61d}',            // 
            "cab" => '\u{e70f}',            // 
            "cc" => '\u{e61d}',             // 
            "cfg" => '\u{e615}',            // ξ˜•
            "class" => '\u{e256}',          // ξ‰–
            "clj" => '\u{e768}',            // 
            "cljs" => '\u{e76a}',           // ξͺ
            "cls" => '\u{f034}',            // 
            "cmd" => '\u{e70f}',            // 
            "coffee" => '\u{f0f4}',         // 
            "conf" => '\u{e615}',           // ξ˜•
            "cp" => '\u{e61d}',             // 
            "cpio" => '\u{f410}',           // 
            "cpp" => '\u{e61d}',            // 
            "cs" => '\u{f031b}',            // σ°Œ›
            "csh" => '\u{f489}',            // ο’‰
            "cshtml" => '\u{f1fa}',         // ο‡Ί
            "csproj" => '\u{f031b}',        // σ°Œ›
            "css" => '\u{e749}',            // 
            "csv" => '\u{f1c3}',            // 
            "csx" => '\u{f031b}',           // σ°Œ›
            "cxx" => '\u{e61d}',            // 
            "d" => '\u{e7af}',              // 
            "dart" => '\u{e798}',           // 
            "db" => '\u{f1c0}',             // 
            "deb" => '\u{e77d}',            // 
            "diff" => '\u{f440}',           // ο‘€
            "djvu" => '\u{f02d}',           // ο€­
            "dll" => '\u{e70f}',            // 
            "doc" => '\u{f1c2}',            // 
            "docx" => '\u{f1c2}',           // 
            "ds_store" => '\u{f179}',       // ο…Ή
            "DS_store" => '\u{f179}',       // ο…Ή
            "dump" => '\u{f1c0}',           // ξœ†
            "ebook" => '\u{e28b}',          // ξŠ‹
            "ebuild" => '\u{f30d}',         // 
            "editorconfig" => '\u{e615}',   // ξ˜•
            "ejs" => '\u{e618}',            // 
            "elm" => '\u{e62c}',            // 
            "env" => '\u{f462}',            // ο‘’
            "eot" => '\u{f031}',            // ο€±
            "epub" => '\u{e28a}',           // 
            "erb" => '\u{e73b}',            // 
            "erl" => '\u{e7b1}',            // 
            "ex" => '\u{e62d}',             // 
            "exe" => '\u{f17a}',            // ο…Ί
            "exs" => '\u{e62d}',            // 
            "fish" => '\u{f489}',           // ο’‰
            "flac" => '\u{f001}',           // 
            "flv" => '\u{f03d}',            // ο€½
            "font" => '\u{f031}',           // ο€±
            "fs" => '\u{e7a7}',             // 
            "fsi" => '\u{e7a7}',            // 
            "fsx" => '\u{e7a7}',            // 
            "gdoc" => '\u{f1c2}',           // 
            "gem" => '\u{e21e}',            // 
            "gemfile" => '\u{e21e}',        // 
            "gemspec" => '\u{e21e}',        // 
            "gform" => '\u{f298}',          // 
            "gif" => '\u{f1c5}',            // ο‡…
            "git" => '\u{f1d3}',            // 
            "gitattributes" => '\u{f1d3}',  // 
            "gitignore" => '\u{f1d3}',      // 
            "gitmodules" => '\u{f1d3}',     // 
            "go" => '\u{e626}',             // 
            "gradle" => '\u{e256}',         // ξ‰–
            "groovy" => '\u{e775}',         // 
            "gsheet" => '\u{f1c3}',         // 
            "gslides" => '\u{f1c4}',        // 
            "guardfile" => '\u{e21e}',      // 
            "gz" => '\u{f410}',             // 
            "h" => '\u{f0fd}',              // 
            "hbs" => '\u{e60f}',            // 
            "hpp" => '\u{f0fd}',            // 
            "hs" => '\u{e777}',             // 
            "htm" => '\u{f13b}',            // ο„»
            "html" => '\u{f13b}',           // ο„»
            "hxx" => '\u{f0fd}',            // 
            "ico" => '\u{f1c5}',            // ο‡…
            "image" => '\u{f1c5}',          // ο‡…
            "img" => '\u{e271}',            // 
            "iml" => '\u{e7b5}',            // 
            "ini" => '\u{f17a}',            // ο…Ί
            "ipynb" => '\u{e678}',          // ξ˜†
            "iso" => '\u{e271}',            // 
            "j2c" => '\u{f1c5}',            // ο‡…
            "j2k" => '\u{f1c5}',            // ο‡…
            "jad" => '\u{e256}',            // ξ‰–
            "jar" => '\u{e256}',            // ξ‰–
            "java" => '\u{e256}',           // ξ‰–
            "jfi" => '\u{f1c5}',            // ο‡…
            "jfif" => '\u{f1c5}',           // ο‡…
            "jif" => '\u{f1c5}',            // ο‡…
            "jl" => '\u{e624}',             // 
            "jmd" => '\u{f48a}',            // ο’Š
            "jp2" => '\u{f1c5}',            // ο‡…
            "jpe" => '\u{f1c5}',            // ο‡…
            "jpeg" => '\u{f1c5}',           // ο‡…
            "jpg" => '\u{f1c5}',            // ο‡…
            "jpx" => '\u{f1c5}',            // ο‡…
            "js" => '\u{e74e}',             // 
            "json" => '\u{e60b}',           // ξ˜‹
            "jsx" => '\u{e7ba}',            // 
            "jxl" => '\u{f1c5}',            // ο‡…
            "ksh" => '\u{f489}',            // ο’‰
            "latex" => '\u{f034}',          // 
            "less" => '\u{e758}',           // 
            "lhs" => '\u{e777}',            // 
            "license" => '\u{f0219}',       // σ°ˆ™
            "localized" => '\u{f179}',      // ο…Ή
            "lock" => '\u{f023}',           // ο€£
            "log" => '\u{f18d}',            // 
            "lua" => '\u{e620}',            // 
            "lz" => '\u{f410}',             // 
            "lz4" => '\u{f410}',            // 
            "lzh" => '\u{f410}',            // 
            "lzma" => '\u{f410}',           // 
            "lzo" => '\u{f410}',            // 
            "m" => '\u{e61e}',              // 
            "mm" => '\u{e61d}',             // 
            "m4a" => '\u{f001}',            // 
            "markdown" => '\u{f48a}',       // ο’Š
            "md" => '\u{f48a}',             // ο’Š
            "mjs" => '\u{e74e}',            // 
            "mk" => '\u{f489}',             // ο’‰
            "mkd" => '\u{f48a}',            // ο’Š
            "mkv" => '\u{f03d}',            // ο€½
            "mobi" => '\u{e28b}',           // ξŠ‹
            "mov" => '\u{f03d}',            // ο€½
            "mp3" => '\u{f001}',            // 
            "mp4" => '\u{f03d}',            // ο€½
            "msi" => '\u{e70f}',            // 
            "mustache" => '\u{e60f}',       // 
            "nix" => '\u{f313}',            // οŒ“
            "node" => '\u{f0399}',          // σ°Ž™
            "npmignore" => '\u{e71e}',      // 
            "odp" => '\u{f1c4}',            // 
            "ods" => '\u{f1c3}',            // 
            "odt" => '\u{f1c2}',            // 
            "ogg" => '\u{f001}',            // 
            "ogv" => '\u{f03d}',            // ο€½
            "otf" => '\u{f031}',            // ο€±
            "part" => '\u{f43a}',           // 
            "patch" => '\u{f440}',          // ο‘€
            "pdf" => '\u{f1c1}',            // 
            "php" => '\u{e73d}',            // 
            "pl" => '\u{e769}',             // 
            "plx" => '\u{e769}',            // 
            "pm" => '\u{e769}',             // 
            "png" => '\u{f1c5}',            // ο‡…
            "pod" => '\u{e769}',            // 
            "ppt" => '\u{f1c4}',            // 
            "pptx" => '\u{f1c4}',           // 
            "procfile" => '\u{e21e}',       // 
            "properties" => '\u{e60b}',     // ξ˜‹
            "ps1" => '\u{f489}',            // ο’‰
            "psd" => '\u{e7b8}',            // 
            "pxm" => '\u{f1c5}',            // ο‡…
            "py" => '\u{e606}',             // ξ˜†
            "pyc" => '\u{e606}',            // ξ˜†
            "r" => '\u{f25d}',              // 
            "rakefile" => '\u{e21e}',       // 
            "rar" => '\u{f410}',            // 
            "razor" => '\u{f1fa}',          // ο‡Ί
            "rb" => '\u{e21e}',             // 
            "rdata" => '\u{f25d}',          // 
            "rdb" => '\u{e76d}',            // 
            "rdoc" => '\u{f48a}',           // ο’Š
            "rds" => '\u{f25d}',            // 
            "readme" => '\u{f48a}',         // ο’Š
            "rlib" => '\u{e7a8}',           // 
            "rmd" => '\u{f48a}',            // ο’Š
            "rpm" => '\u{e7bb}',            // 
            "rs" => '\u{e7a8}',             // 
            "rspec" => '\u{e21e}',          // 
            "rspec_parallel" => '\u{e21e}', // 
            "rspec_status" => '\u{e21e}',   // 
            "rss" => '\u{f09e}',            // ο‚ž
            "rtf" => '\u{f0219}',           // σ°ˆ™
            "ru" => '\u{e21e}',             // 
            "rubydoc" => '\u{e73b}',        // 
            "sass" => '\u{e603}',           // ξ˜ƒ
            "scala" => '\u{e737}',          // 
            "scss" => '\u{e749}',           // 
            "sh" => '\u{f489}',             // ο’‰
            "shell" => '\u{f489}',          // ο’‰
            "slim" => '\u{e73b}',           // 
            "sln" => '\u{e70c}',            // 
            "so" => '\u{f17c}',             // ο…Ό
            "sql" => '\u{f1c0}',            // ξœ†
            "sqlite3" => '\u{e7c4}',        // ξŸ„
            "sty" => '\u{f034}',            // 
            "styl" => '\u{e600}',           // ξ˜€
            "stylus" => '\u{e600}',         // ξ˜€
            "svg" => '\u{f1c5}',            // ο‡…
            "swift" => '\u{e755}',          // 
            "t" => '\u{e769}',              // 
            "tar" => '\u{f410}',            // 
            "taz" => '\u{f410}',            // 
            "tbz" => '\u{f410}',            // 
            "tbz2" => '\u{f410}',           // 
            "tex" => '\u{f034}',            // 
            "tgz" => '\u{f410}',            // 
            "tiff" => '\u{f1c5}',           // ο‡…
            "tlz" => '\u{f410}',            // 
            "toml" => '\u{e615}',           // ξ˜•
            "torrent" => '\u{e275}',        // 
            "ts" => '\u{e628}',             // 
            "tsv" => '\u{f1c3}',            // 
            "tsx" => '\u{e7ba}',            // 
            "ttf" => '\u{f031}',            // ο€±
            "twig" => '\u{e61c}',           // 
            "txt" => '\u{f15c}',            // ο…œ
            "txz" => '\u{f410}',            // 
            "tz" => '\u{f410}',             // 
            "tzo" => '\u{f410}',            // 
            "video" => '\u{f03d}',          // ο€½
            "vim" => '\u{e62b}',            // 
            "vue" => '\u{f0844}',           // σ°‘„
            "war" => '\u{e256}',            // ξ‰–
            "wav" => '\u{f001}',            // 
            "webm" => '\u{f03d}',           // ο€½
            "webp" => '\u{f1c5}',           // ο‡…
            "windows" => '\u{f17a}',        // ο…Ί
            "woff" => '\u{f031}',           // ο€±
            "woff2" => '\u{f031}',          // ο€±
            "xhtml" => '\u{f13b}',          // ο„»
            "xls" => '\u{f1c3}',            // 
            "xlsx" => '\u{f1c3}',           // 
            "xml" => '\u{f05c0}',           // σ°—€
            "xul" => '\u{f05c0}',           // σ°—€
            "xz" => '\u{f410}',             // 
            "yaml" => '\u{f481}',           // 
            "yml" => '\u{f481}',            // 
            "zip" => '\u{f410}',            // 
            "zsh" => '\u{f489}',            // ο’‰
            "zsh-theme" => '\u{f489}',      // ο’‰
            "zshrc" => '\u{f489}',          // ο’‰
            "zst" => '\u{f410}',            // 
            _ => '\u{f15b}',                // ο…›
        }
    } else {
        '\u{f016}'
    }
}