replace icons in grid with devicons + color (#14827)

# Description

This PR replaces the home-grown icons in the `grid` command with the
`devicons` crate.

### Before

![image](https://github.com/user-attachments/assets/05e8de84-1655-45b9-ab88-40b8faa0d950)

### After

![image](https://github.com/user-attachments/assets/2134e92d-fba8-41f7-a630-fd83c0a9449c)


# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the
tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
Darren Schroeder 2025-01-14 16:51:30 -06:00 committed by GitHub
parent 301d1370c4
commit 8ce14a7c86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 19 additions and 661 deletions

10
Cargo.lock generated
View File

@ -1598,6 +1598,15 @@ dependencies = [
"syn 2.0.90",
]
[[package]]
name = "devicons"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830e47e2f330cf4fdd5a958dcef921b9523ffc21ab6713aa5e77ba2cce03904b"
dependencies = [
"lazy_static",
]
[[package]]
name = "dialoguer"
version = "0.11.0"
@ -3775,6 +3784,7 @@ dependencies = [
"crossterm 0.28.1",
"csv",
"data-encoding",
"devicons",
"dialoguer",
"digest",
"dirs",

View File

@ -80,6 +80,7 @@ crossbeam-channel = "0.5.8"
crossterm = "0.28.1"
csv = "1.3"
ctrlc = "3.4"
devicons = "0.6.12"
dialoguer = { default-features = false, version = "0.11" }
digest = { default-features = false, version = "0.10" }
dirs = "5.0"

View File

@ -45,6 +45,7 @@ chrono-humanize = { workspace = true }
chrono-tz = { workspace = true }
crossterm = { workspace = true, optional = true }
csv = { workspace = true }
devicons = { workspace = true }
dialoguer = { workspace = true, default-features = false, features = ["fuzzy-select"] }
digest = { workspace = true, default-features = false }
dtparse = { workspace = true }

View File

@ -1,6 +1,6 @@
// use super::icons::{icon_for_file, iconify_style_ansi_to_nu};
use super::icons::icon_for_file;
use devicons::icon_for_file;
use lscolors::Style;
use nu_color_config::lookup_ansi_color_style;
use nu_engine::{command_prelude::*, env_to_string};
use nu_protocol::Config;
use nu_term_grid::grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions};
@ -214,13 +214,9 @@ fn create_grid_output(
if icons_param {
let no_ansi = nu_utils::strip_ansi_unlikely(&value);
let path = cwd.join(no_ansi.as_ref());
let icon = icon_for_file(&path, call.head)?;
let file_icon = icon_for_file(&path, &None);
let ls_colors_style = ls_colors.style_for_path(path);
let icon_style = match ls_colors_style {
Some(c) => c.to_nu_ansi_term_style(),
None => nu_ansi_term::Style::default(),
};
let icon_style = lookup_ansi_color_style(file_icon.color);
let ansi_style = ls_colors_style
.map(Style::to_nu_ansi_term_style)
@ -228,7 +224,7 @@ fn create_grid_output(
let item = format!(
"{} {}",
icon_style.paint(String::from(icon)),
icon_style.paint(String::from(file_icon.icon)),
ansi_style.paint(value)
);
@ -247,8 +243,8 @@ fn create_grid_output(
} else if icons_param {
let no_ansi = nu_utils::strip_ansi_unlikely(&value);
let path = cwd.join(no_ansi.as_ref());
let icon = icon_for_file(&path, call.head)?;
let item = format!("{} {}", String::from(icon), value);
let file_icon = icon_for_file(&path, &None);
let item = format!("{} {}", String::from(file_icon.icon), value);
let mut cell = Cell::from(item);
cell.alignment = Alignment::Left;
grid.add(cell);

View File

@ -1,649 +0,0 @@
use nu_protocol::{ShellError, Span};
use std::sync::LazyLock;
use std::{collections::HashMap, path::Path};
// Attribution: Thanks exa. Most of this file is taken from around here
// https://github.com/ogham/exa/blob/dbd11d38042284cc890fdd91760c2f93b65e8553/src/output/icons.rs
pub trait FileIcon {
fn icon_file(&self, file: &Path) -> Option<char>;
}
#[derive(Copy, Clone)]
pub enum Icons {
Audio,
Image,
Video,
}
impl Icons {
pub fn value(self) -> char {
match self {
Self::Audio => '\u{f001}',
Self::Image => '\u{f1c5}',
Self::Video => '\u{f03d}',
}
}
}
// keeping this for now in case we have to revert to ansi style instead of crossterm style
// Helper function to convert ansi_term style to nu_ansi_term. unfortunately
// this is necessary because ls_colors has a dependency on ansi_term vs nu_ansi_term
// double unfortunately, now we have a dependency on both. we may have to bring
// in ls_colors crate to nushell
// pub fn iconify_style_ansi_to_nu<'a>(style: ansi_term::Style) -> nu_ansi_term::Style {
// let bg = match style.background {
// Some(c) => match c {
// ansi_term::Color::Black => Some(nu_ansi_term::Color::Black),
// ansi_term::Color::Red => Some(nu_ansi_term::Color::Red),
// ansi_term::Color::Green => Some(nu_ansi_term::Color::Green),
// ansi_term::Color::Yellow => Some(nu_ansi_term::Color::Yellow),
// ansi_term::Color::Blue => Some(nu_ansi_term::Color::Blue),
// ansi_term::Color::Purple => Some(nu_ansi_term::Color::Purple),
// ansi_term::Color::Cyan => Some(nu_ansi_term::Color::Cyan),
// ansi_term::Color::White => Some(nu_ansi_term::Color::White),
// ansi_term::Color::Fixed(f) => Some(nu_ansi_term::Color::Fixed(f)),
// ansi_term::Color::RGB(r, g, b) => Some(nu_ansi_term::Color::Rgb(r, g, b)),
// },
// None => None,
// };
// let fg = match style.foreground {
// Some(c) => match c {
// ansi_term::Color::Black => Some(nu_ansi_term::Color::Black),
// ansi_term::Color::Red => Some(nu_ansi_term::Color::Red),
// ansi_term::Color::Green => Some(nu_ansi_term::Color::Green),
// ansi_term::Color::Yellow => Some(nu_ansi_term::Color::Yellow),
// ansi_term::Color::Blue => Some(nu_ansi_term::Color::Blue),
// ansi_term::Color::Purple => Some(nu_ansi_term::Color::Purple),
// ansi_term::Color::Cyan => Some(nu_ansi_term::Color::Cyan),
// ansi_term::Color::White => Some(nu_ansi_term::Color::White),
// ansi_term::Color::Fixed(f) => Some(nu_ansi_term::Color::Fixed(f)),
// ansi_term::Color::RGB(r, g, b) => Some(nu_ansi_term::Color::Rgb(r, g, b)),
// },
// None => None,
// };
// let nu_style = nu_ansi_term::Style {
// foreground: fg,
// background: bg,
// is_blink: style.is_blink,
// is_bold: style.is_bold,
// is_dimmed: style.is_dimmed,
// is_hidden: style.is_hidden,
// is_italic: style.is_italic,
// is_underline: style.is_underline,
// is_reverse: style.is_reverse,
// is_strikethrough: style.is_strikethrough,
// };
// nu_style
// .background
// .or(nu_style.foreground)
// .map(nu_ansi_term::Style::from)
// .unwrap_or_default()
// }
static MAP_BY_NAME: LazyLock<HashMap<&'static str, char>> = LazyLock::new(|| {
[
(".Trash", '\u{f1f8}'), // 
(".atom", '\u{e764}'), // 
(".bashprofile", '\u{e615}'), // 
(".bashrc", '\u{f489}'), // 
(".git", '\u{f1d3}'), // 
(".gitattributes", '\u{f1d3}'), // 
(".gitconfig", '\u{f1d3}'), // 
(".github", '\u{f408}'), // 
(".gitignore", '\u{f1d3}'), // 
(".gitmodules", '\u{f1d3}'), // 
(".rvm", '\u{e21e}'), // 
(".vimrc", '\u{e62b}'), // 
(".vscode", '\u{e70c}'), // 
(".zshrc", '\u{f489}'), // 
("Cargo.lock", '\u{e7a8}'), // 
("bin", '\u{e5fc}'), // 
("config", '\u{e5fc}'), // 
("docker-compose.yml", '\u{f308}'), // 
("Dockerfile", '\u{f308}'), // 
("Earthfile", '\u{f0ac}'), // 
("ds_store", '\u{f179}'), // 
("gitignore_global", '\u{f1d3}'), // 
("gitlab-ci.yml", '\u{f296}'), // 
("go.mod", '\u{e626}'), // 
("go.sum", '\u{e626}'), // 
("gradle", '\u{e256}'), // 
("gradle", '\u{e70e}'), // 
("gruntfile.coffee", '\u{e611}'), // 
("gruntfile.js", '\u{e611}'), // 
("gruntfile.ls", '\u{e611}'), // 
("gulpfile.coffee", '\u{e610}'), // 
("gulpfile.js", '\u{e610}'), // 
("gulpfile.ls", '\u{e610}'), // 
("hidden", '\u{f023}'), // 
("include", '\u{e5fc}'), // 
("lib", '\u{f121}'), // 
("localized", '\u{f179}'), // 
("Makefile", '\u{e779}'), // 
("node_modules", '\u{e718}'), // 
("npmignore", '\u{e71e}'), // 
("rubydoc", '\u{e73b}'), // 
("yarn.lock", '\u{e718}'), // 
]
.into_iter()
.collect()
});
pub fn icon_for_file(file_path: &Path, span: Span) -> Result<char, ShellError> {
let extensions = Box::new(FileExtensions);
let fp = format!("{}", file_path.display());
if let Some(icon) = MAP_BY_NAME.get(&fp[..]) {
Ok(*icon)
} else if file_path.is_dir() {
let str = file_path
.file_name()
.ok_or_else(|| ShellError::GenericError {
error: "File name error".into(),
msg: "Unable to get file name".into(),
span: Some(span),
help: None,
inner: vec![],
})?
.to_str()
.ok_or_else(|| ShellError::GenericError {
error: "Unable to get str error".into(),
msg: "Unable to convert to str file name".into(),
span: Some(span),
help: None,
inner: vec![],
})?;
Ok(match str {
"bin" => '\u{e5fc}', // 
".git" => '\u{f1d3}', // 
".idea" => '\u{e7b5}', // 
_ => '\u{f115}', // 
})
} else if let Some(icon) = extensions.icon_file(file_path) {
Ok(icon)
} else if let Some(ext) = file_path.extension().as_ref() {
let str = ext.to_str().ok_or_else(|| ShellError::GenericError {
error: "Unable to get str error".into(),
msg: "Unable to convert to str file name".into(),
span: Some(span),
help: None,
inner: vec![],
})?;
Ok(match str {
"a" => '\u{f17c}', // 
"acf" => '\u{f1b6}', // 
"ai" => '\u{e7b4}', // 
"android" => '\u{e70e}', // 
"apk" => '\u{e70e}', // 
"apple" => '\u{f179}', // 
"asm" => '\u{e637}', // 
"avi" => '\u{f03d}', // 
"avro" => '\u{e60b}', // 
"awk" => '\u{f489}', // 
"bash" => '\u{f489}', // 
"bash_history" => '\u{f489}', // 
"bash_profile" => '\u{f489}', // 
"bashrc" => '\u{f489}', // 
"bat" => '\u{ebc4}', // 
"bib" => '\u{e69b}', // 
"bin" => '\u{eae8}', // 
"bmp" => '\u{f1c5}', // 
"bst" => '\u{e69b}', // 
"bz" => '\u{f410}', // 
"bz2" => '\u{f410}', // 
"c" => '\u{e61e}', // 
"c++" => '\u{e61d}', // 
"cab" => '\u{e70f}', // 
"cc" => '\u{e61d}', // 
"cert" => '\u{eafa}', // 
"cfg" => '\u{e615}', // 
"cjs" => '\u{e74e}', // 
"class" => '\u{e256}', // 
"clj" => '\u{e768}', // 
"cljs" => '\u{e76a}', // 
"cls" => '\u{e69b}', // 
"cmd" => '\u{e70f}', // 
"coffee" => '\u{f0f4}', // 
"conf" => '\u{e615}', // 
"config" => '\u{e615}', // 
"cp" => '\u{e61d}', // 
"cpp" => '\u{e61d}', // 
"crt" => '\u{eafa}', // 
"cs" => '\u{f031b}', // 󰌛
"csh" => '\u{f489}', // 
"cshtml" => '\u{f1fa}', // 
"csproj" => '\u{f031b}', // 󰌛
"css" => '\u{e749}', // 
"csv" => '\u{f1c3}', // 
"csx" => '\u{f031b}', // 󰌛
"cu" => '\u{e64b}', // 
"cxx" => '\u{e61d}', // 
"d" => '\u{e7af}', // 
"dart" => '\u{e798}', // 
"db" => '\u{f1c0}', // 
"deb" => '\u{e77d}', // 
"desktop" => '\u{ebd1}', // 
"diff" => '\u{f440}', // 
"djvu" => '\u{f02d}', // 
"dll" => '\u{e70f}', // 
"doc" => '\u{f1c2}', // 
"docx" => '\u{f1c2}', // 
"drawio" => '\u{ebba}', // 
"ds_store" => '\u{f179}', // 
"DS_store" => '\u{f179}', // 
"dump" => '\u{f1c0}', // 
"ebook" => '\u{e28b}', // 
"editorconfig" => '\u{e615}', // 
"ejs" => '\u{e618}', // 
"elm" => '\u{e62c}', // 
"eml" => '\u{f003}', // 
"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}', // 
"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{e70e}', // 
"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}', // 
"ical" => '\u{eab0}', // 
"icalendar" => '\u{eab0}', // 
"ico" => '\u{f1c5}', // 
"image" => '\u{f1c5}', // 
"iml" => '\u{e7b5}', // 
"ini" => '\u{f17a}', // 
"ipynb" => '\u{e606}', // 
"iso" => '\u{e271}', // 
"jad" => '\u{e256}', // 
"jar" => '\u{e204}', // 
"java" => '\u{e204}', // 
"jpeg" => '\u{f1c5}', // 
"jpg" => '\u{f1c5}', // 
"js" => '\u{e74e}', // 
"json" => '\u{e60b}', // 
"jsx" => '\u{e7ba}', // 
"kdb" => '\u{f23e}', // 
"kdbx" => '\u{f23e}', // 
"key" => '\u{eb11}', // 
"ko" => '\u{f17c}', // 
"ksh" => '\u{f489}', // 
"latex" => '\u{e69b}', // 
"less" => '\u{e758}', // 
"lhs" => '\u{e777}', // 
"license" => '\u{f0fc3}', // 󰿃
"localized" => '\u{f179}', // 
"lock" => '\u{f023}', // 
"log" => '\u{f18d}', // 
"lua" => '\u{e620}', // 
"lz" => '\u{f410}', // 
"lzh" => '\u{f410}', // 
"lzma" => '\u{f410}', // 
"lzo" => '\u{f410}', // 
"m" => '\u{e61e}', // 
"ml" => '\u{e67a}', // 
"mli" => '\u{e67a}', // 
"mll" => '\u{e67a}', // 
"mly" => '\u{e67a}', // 
"mm" => '\u{e61d}', // 
"m4a" => '\u{f001}', // 
"magnet" => '\u{f076}', // 
"markdown" => '\u{f48a}', // 
"md" => '\u{f48a}', // 
"mjs" => '\u{e74e}', // 
"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}', // 
"o" => '\u{eae8}', // 
"odp" => '\u{f1c4}', // 
"ods" => '\u{f1c3}', // 
"odt" => '\u{f1c2}', // 
"ogg" => '\u{f001}', // 
"ogv" => '\u{f03d}', // 
"otf" => '\u{f031}', // 
"out" => '\u{eb2c}', // 
"patch" => '\u{f440}', // 
"pdf" => '\u{f1c1}', // 
"pem" => '\u{eb11}', // 
"php" => '\u{e73d}', // 
"pl" => '\u{e769}', // 
"png" => '\u{f1c5}', // 
"ppt" => '\u{f1c4}', // 
"pptx" => '\u{f1c4}', // 
"procfile" => '\u{e21e}', // 
"properties" => '\u{e60b}', // 
"ps1" => '\u{ebc7}', // 
"psd" => '\u{e7b8}', // 
"psd1" => '\u{ebc7}', // 
"psm1" => '\u{ebc7}', // 
"pxm" => '\u{f1c5}', // 
"py" => '\u{e606}', // 
"pyc" => '\u{e606}', // 
"qcow2" => '\u{e271}', // 
"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}', // 
"s" => '\u{e637}', // 
"sass" => '\u{e603}', // 
"scala" => '\u{e737}', // 
"scss" => '\u{e749}', // 
"service" => '\u{eba2}', // 
"sh" => '\u{f489}', // 
"shell" => '\u{f489}', // 
"slim" => '\u{e73b}', // 
"sln" => '\u{e70c}', // 
"so" => '\u{f17c}', // 
"sql" => '\u{f1c0}', // 
"sqlite3" => '\u{e7c4}', // 
"sty" => '\u{e69b}', // 
"styl" => '\u{e600}', // 
"stylus" => '\u{e600}', // 
"svg" => '\u{f1c5}', // 
"swift" => '\u{e755}', // 
"tar" => '\u{f410}', // 
"taz" => '\u{f410}', // 
"tbz" => '\u{f410}', // 
"tbz2" => '\u{f410}', // 
"tex" => '\u{e69b}', // 
"tiff" => '\u{f1c5}', // 
"toml" => '\u{e615}', // 
"ts" => '\u{e628}', // 
"tsv" => '\u{f1c3}', // 
"tsx" => '\u{e7ba}', // 
"ttf" => '\u{f031}', // 
"twig" => '\u{e61c}', // 
"txt" => '\u{f15c}', // 
"tz" => '\u{f410}', // 
"tzo" => '\u{f410}', // 
"unity" => '\u{e721}', // 
"unity3d" => '\u{e721}', // 
"vdi" => '\u{e271}', // 
"vhd" => '\u{e271}', // 
"video" => '\u{f03d}', // 
"vim" => '\u{e62b}', // 
"vmdk" => '\u{e271}', // 
"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}', // 
"xlsm" => '\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}', // 
"7z" => '\u{f410}', // 
_ => '\u{f15b}', // 
})
} else {
Ok('\u{f016}')
}
}
/// Whether this files extension is any of the strings that get passed in.
///
/// This will always return `false` if the file has no extension.
pub fn extension_is_one_of(path: &Path, choices: &[&str]) -> bool {
match path.extension() {
Some(os_ext) => match os_ext.to_str() {
Some(ext) => choices.contains(&ext),
None => false,
},
None => false,
}
}
/// Whether this files name, including extension, is any of the strings
/// that get passed in.
// pub fn name_is_one_of(name: &str, choices: &[&str]) -> bool {
// choices.contains(&&name[..])
// }
#[derive(Debug, Default, PartialEq, Eq)]
pub struct FileExtensions;
// TODO: We may want to re-add these FileExtensions impl fns back. I have disabled
// it now because it's hard coding colors which kind of defeats the LS_COLORS
// functionality. We may want to enable and augment at some point.
impl FileExtensions {
// /// An “immediate” file is something that can be run or activated somehow
// /// in order to kick off the build of a project. Its usually only present
// /// in directories full of source code.
// #[allow(clippy::case_sensitive_file_extension_comparisons)]
// #[allow(dead_code)]
// fn is_immediate(&self, file_path: &Path) -> bool {
// file_path
// .file_name()
// .unwrap()
// .to_str()
// .unwrap()
// .to_lowercase()
// .starts_with("readme")
// || file_path
// .file_name()
// .unwrap()
// .to_str()
// .unwrap()
// .ends_with(".ninja")
// || name_is_one_of(
// file_path.file_name().unwrap().to_str().unwrap(),
// &[
// "Makefile",
// "Cargo.toml",
// "SConstruct",
// "CMakeLists.txt",
// "build.gradle",
// "pom.xml",
// "Rakefile",
// "package.json",
// "Gruntfile.js",
// "Gruntfile.coffee",
// "BUILD",
// "BUILD.bazel",
// "WORKSPACE",
// "build.xml",
// "Podfile",
// "webpack.config.js",
// "meson.build",
// "composer.json",
// "RoboFile.php",
// "PKGBUILD",
// "Justfile",
// "Procfile",
// "Dockerfile",
// "Containerfile",
// "Vagrantfile",
// "Brewfile",
// "Gemfile",
// "Pipfile",
// "build.sbt",
// "mix.exs",
// "bsconfig.json",
// "tsconfig.json",
// ],
// )
// }
fn is_image(&self, file: &Path) -> bool {
extension_is_one_of(
file,
&[
"png", "jfi", "jfif", "jif", "jpe", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
"ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw", "svg", "stl", "eps", "dvi", "ps",
"cbr", "jpf", "cbz", "xpm", "ico", "cr2", "orf", "nef", "heif", "avif", "jxl",
],
)
}
fn is_video(&self, file: &Path) -> bool {
extension_is_one_of(
file,
&[
"avi", "flv", "m2v", "m4v", "mkv", "mov", "mp4", "mpeg", "mpg", "ogm", "ogv",
"vob", "wmv", "webm", "m2ts", "heic",
],
)
}
fn is_music(&self, file: &Path) -> bool {
extension_is_one_of(file, &["aac", "m4a", "mp3", "ogg", "wma", "mka", "opus"])
}
// Lossless music, rather than any other kind of data...
fn is_lossless(&self, file: &Path) -> bool {
extension_is_one_of(file, &["alac", "ape", "flac", "wav"])
}
// #[allow(dead_code)]
// fn is_crypto(&self, file: &Path) -> bool {
// extension_is_one_of(
// file,
// &["asc", "enc", "gpg", "pgp", "sig", "signature", "pfx", "p12"],
// )
// }
// #[allow(dead_code)]
// fn is_document(&self, file: &Path) -> bool {
// extension_is_one_of(
// file,
// &[
// "djvu", "doc", "docx", "dvi", "eml", "eps", "fotd", "key", "keynote", "numbers",
// "odp", "odt", "pages", "pdf", "ppt", "pptx", "rtf", "xls", "xlsx",
// ],
// )
// }
// #[allow(dead_code)]
// fn is_compressed(&self, file: &Path) -> bool {
// extension_is_one_of(
// file,
// &[
// "zip", "tar", "Z", "z", "gz", "bz2", "a", "ar", "7z", "iso", "dmg", "tc", "rar",
// "par", "tgz", "xz", "txz", "lz", "tlz", "lzma", "deb", "rpm", "zst", "lz4",
// ],
// )
// }
// #[allow(dead_code)]
// fn is_temp(&self, file: &Path) -> bool {
// file.file_name().unwrap().to_str().unwrap().ends_with('~')
// || (file.file_name().unwrap().to_str().unwrap().starts_with('#')
// && file.file_name().unwrap().to_str().unwrap().ends_with('#'))
// || extension_is_one_of(file, &["tmp", "swp", "swo", "swn", "bak", "bkp", "bk"])
// }
// #[allow(dead_code)]
// fn is_compiled(&self, file: &Path) -> bool {
// if extension_is_one_of(file, &["class", "elc", "hi", "o", "pyc", "zwc", "ko"]) {
// true
// // } else if let Some(dir) = file.parent() {
// // file.get_source_files()
// // .iter()
// // .any(|path| dir.contains(path))
// } else {
// false
// }
// }
// }
// impl FileColours for FileExtensions {
// fn colour_file(&self, file: &Path) -> Option<Style> {
// use ansi_term::Colour::*;
// Some(match file {
// f if self.is_temp(f) => Fixed(244).normal(),
// f if self.is_immediate(f) => Yellow.bold().underline(),
// f if self.is_image(f) => Fixed(133).normal(),
// f if self.is_video(f) => Fixed(135).normal(),
// f if self.is_music(f) => Fixed(92).normal(),
// f if self.is_lossless(f) => Fixed(93).normal(),
// f if self.is_crypto(f) => Fixed(109).normal(),
// f if self.is_document(f) => Fixed(105).normal(),
// f if self.is_compressed(f) => Red.normal(),
// f if self.is_compiled(f) => Fixed(137).normal(),
// _ => return None,
// })
// }
}
impl FileIcon for FileExtensions {
fn icon_file(&self, file: &Path) -> Option<char> {
if self.is_music(file) || self.is_lossless(file) {
Some(Icons::Audio.value())
} else if self.is_image(file) {
Some(Icons::Image.value())
} else if self.is_video(file) {
Some(Icons::Video.value())
} else {
None
}
}
}

View File

@ -1,5 +1,4 @@
mod griddle;
mod icons;
mod table;
pub use griddle::Griddle;