diff --git a/src/app.rs b/src/app.rs index 9ea99c4f4..83cd38f28 100644 --- a/src/app.rs +++ b/src/app.rs @@ -32,6 +32,15 @@ pub fn build() -> App<'static, 'static> { .multiple(true) .help("When to print the icons"), ) + .arg( + Arg::with_name("icon-theme") + .long("icon-theme") + .possible_value("fancy") + .possible_value("unicode") + .default_value("fancy") + .multiple(true) + .help("Whether to use fancy or unicode icons"), + ) .arg( Arg::with_name("indicators") .short("F") diff --git a/src/core.rs b/src/core.rs index db3fa44e5..61b732950 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,7 +1,7 @@ use batch::Batch; use color::{self, Colors}; use display::Display; -use flags::{Flags, WhenFlag}; +use flags::{Flags, IconTheme, WhenFlag}; use icon::{self, Icons}; use meta::{FileType, Meta}; use std::path::{Path, PathBuf}; @@ -22,18 +22,14 @@ impl Core { let mut inner_flags = flags; let color_theme = match (tty_available, flags.color) { - (true, WhenFlag::Never) => color::Theme::NoColor, - (false, WhenFlag::Auto) => color::Theme::NoColor, - (false, WhenFlag::Always) => color::Theme::Default, + (_, WhenFlag::Never) | (false, WhenFlag::Auto) => color::Theme::NoColor, _ => color::Theme::Default, }; - let icon_theme = match (tty_available, flags.icon) { - (true, WhenFlag::Never) => icon::Theme::NoIcon, - (false, WhenFlag::Never) => icon::Theme::NoIcon, - (false, WhenFlag::Auto) => icon::Theme::NoIcon, - (false, WhenFlag::Always) => icon::Theme::Default, - _ => icon::Theme::Default, + let icon_theme = match (tty_available, flags.icon, flags.icon_theme) { + (_, WhenFlag::Never, _) | (false, WhenFlag::Auto, _) => icon::Theme::NoIcon, + (_, _, IconTheme::Fancy) => icon::Theme::Fancy, + (_, _, IconTheme::Unicode) => icon::Theme::Unicode, }; if !tty_available { diff --git a/src/display.rs b/src/display.rs index 65bea2747..f56d1c618 100644 --- a/src/display.rs +++ b/src/display.rs @@ -182,7 +182,7 @@ mod tests { let output = name .render( &Colors::new(color::Theme::NoColor), - &Icons::new(icon::Theme::Default), + &Icons::new(icon::Theme::Fancy), ) .to_string(); assert_eq!(display.get_visible_width(&output), *l); diff --git a/src/flags.rs b/src/flags.rs index f1fb675a1..65954fcd4 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -14,6 +14,7 @@ pub struct Flags { pub date: DateFlag, pub color: WhenFlag, pub icon: WhenFlag, + pub icon_theme: IconTheme, pub recursion_depth: usize, } @@ -21,6 +22,7 @@ impl Flags { pub fn from_matches(matches: &ArgMatches) -> Result { let color_inputs: Vec<&str> = matches.values_of("color").unwrap().collect(); let icon_inputs: Vec<&str> = matches.values_of("icon").unwrap().collect(); + let icon_theme_inputs: Vec<&str> = matches.values_of("icon-theme").unwrap().collect(); let date_inputs: Vec<&str> = matches.values_of("date").unwrap().collect(); let dir_order_inputs: Vec<&str> = matches.values_of("group-dirs").unwrap().collect(); @@ -70,6 +72,7 @@ impl Flags { date: DateFlag::from(date_inputs[date_inputs.len() - 1]), color: WhenFlag::from(color_inputs[color_inputs.len() - 1]), icon: WhenFlag::from(icon_inputs[icon_inputs.len() - 1]), + icon_theme: IconTheme::from(icon_theme_inputs[icon_inputs.len() - 1]), directory_order: DirOrderFlag::from(dir_order_inputs[dir_order_inputs.len() - 1]), }) } @@ -91,6 +94,7 @@ impl Default for Flags { date: DateFlag::Date, color: WhenFlag::Auto, icon: WhenFlag::Auto, + icon_theme: IconTheme::Fancy, } } } @@ -159,6 +163,22 @@ impl<'a> From<&'a str> for DirOrderFlag { } } +#[derive(Clone, Debug, Copy, PartialEq, Eq)] +pub enum IconTheme { + Unicode, + Fancy, +} + +impl<'a> From<&'a str> for IconTheme { + fn from(theme: &'a str) -> Self { + match theme { + "fancy" => IconTheme::Fancy, + "unicode" => IconTheme::Unicode, + _ => panic!("invalid \"icon-theme\" flag: {}", theme), + } + } +} + #[cfg(test)] mod test { use super::Flags; diff --git a/src/icon.rs b/src/icon.rs index 97164ff66..7c2785b90 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -5,12 +5,15 @@ pub struct Icons { display_icons: bool, icons_by_name: HashMap<&'static str, &'static str>, icons_by_extension: HashMap<&'static str, &'static str>, + default_folder_icon: &'static str, + default_file_icon: &'static str, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Theme { NoIcon, - Default, + Fancy, + Unicode, } const ICON_SPACE: &str = " "; @@ -21,10 +24,30 @@ const ICON_SPACE: &str = " "; // s#\\u[0-9a-f]*#\=eval('"'.submatch(0).'"')# impl Icons { pub fn new(theme: Theme) -> Self { + let display_icons = theme == Theme::Fancy || theme == Theme::Unicode; + let (icons_by_name, icons_by_extension, default_file_icon, default_folder_icon) = + if theme == Theme::Fancy { + ( + Self::get_default_icons_by_name(), + Self::get_default_icons_by_extension(), + "\u{f016}", //  + "\u{f115}", //  + ) + } else { + ( + HashMap::new(), + HashMap::new(), + "\u{1f5cb}", // 🗋 + "\u{1f5c1}", // 🗁 + ) + }; + Self { - display_icons: theme == Theme::Default, - icons_by_name: Self::get_default_icons_by_name(), - icons_by_extension: Self::get_default_icons_by_extension(), + display_icons, + icons_by_name, + icons_by_extension, + default_file_icon, + default_folder_icon, } } @@ -37,7 +60,7 @@ impl Icons { // Check directory. if name.file_type() == FileType::Directory { - res += "\u{f115}"; //  + res += self.default_folder_icon; res += ICON_SPACE; return res; } @@ -59,7 +82,7 @@ impl Icons { } // Use the default icons. - res += "\u{f016}"; //  + res += self.default_file_icon; res += ICON_SPACE; res } @@ -313,12 +336,27 @@ mod test { let file_type = FileType::new(&meta, &Permissions::from(&meta)); let name = Name::new(&file_path, file_type); - let icon = Icons::new(Theme::Default); + let icon = Icons::new(Theme::Fancy); let icon = icon.get(&name); assert_eq!(icon, format!("{}{}", "\u{f016}", ICON_SPACE)); //  } + #[test] + fn get_default_file_icon_unicode() { + let tmp_dir = TempDir::new("test_file_type").expect("failed to create temp dir"); + let file_path = tmp_dir.path().join("file"); + File::create(&file_path).expect("failed to create file"); + let meta = file_path.metadata().expect("failed to get metas"); + + let file_type = FileType::new(&meta, &Permissions::from(&meta)); + let name = Name::new(&file_path, file_type); + let icon = Icons::new(Theme::Unicode); + let icon = icon.get(&name); + + assert_eq!(icon, format!("{}{}", "\u{1f5cb}", ICON_SPACE)); + } + #[test] fn get_directory_icon() { let tmp_dir = TempDir::new("test_file_type").expect("failed to create temp dir"); @@ -327,12 +365,26 @@ mod test { let file_type = FileType::new(&meta, &Permissions::from(&meta)); let name = Name::new(&file_path, file_type); - let icon = Icons::new(Theme::Default); + let icon = Icons::new(Theme::Fancy); let icon = icon.get(&name); assert_eq!(icon, format!("{}{}", "\u{f115}", ICON_SPACE)); //  } + #[test] + fn get_directory_icon_unicode() { + let tmp_dir = TempDir::new("test_file_type").expect("failed to create temp dir"); + let file_path = tmp_dir.path(); + let meta = file_path.metadata().expect("failed to get metas"); + + let file_type = FileType::new(&meta, &Permissions::from(&meta)); + let name = Name::new(&file_path, file_type); + let icon = Icons::new(Theme::Unicode); + let icon = icon.get(&name); + + assert_eq!(icon, format!("{}{}", "\u{1f5c1}", ICON_SPACE)); + } + #[test] fn get_directory_icon_with_ext() { let tmp_dir = TempDir::new("test_file_type.rs").expect("failed to create temp dir"); @@ -341,7 +393,7 @@ mod test { let file_type = FileType::new(&meta, &Permissions::from(&meta)); let name = Name::new(&file_path, file_type); - let icon = Icons::new(Theme::Default); + let icon = Icons::new(Theme::Fancy); let icon = icon.get(&name); assert_eq!(icon, format!("{}{}", "\u{f115}", ICON_SPACE)); //  @@ -358,7 +410,7 @@ mod test { let file_type = FileType::new(&meta, &Permissions::from(&meta)); let name = Name::new(&file_path, file_type); - let icon = Icons::new(Theme::Default); + let icon = Icons::new(Theme::Fancy); let icon = icon.get(&name); assert_eq!(icon, format!("{}{}", file_icon, ICON_SPACE)); @@ -376,7 +428,7 @@ mod test { let file_type = FileType::new(&meta, &Permissions::from(&meta)); let name = Name::new(&file_path, file_type); - let icon = Icons::new(Theme::Default); + let icon = Icons::new(Theme::Fancy); let icon = icon.get(&name); assert_eq!(icon, format!("{}{}", file_icon, ICON_SPACE)); diff --git a/src/main.rs b/src/main.rs index 6b978711e..3a6e93ba9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,12 @@ -#![cfg_attr(feature = "cargo-clippy", allow( - clippy::cast_precision_loss, - clippy::cast_sign_loss, - clippy::match_same_arms, - clippy::cast_possible_wrap -))] +#![cfg_attr( + feature = "cargo-clippy", + allow( + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::match_same_arms, + clippy::cast_possible_wrap + ) +)] #[macro_use] extern crate clap; diff --git a/src/meta/name.rs b/src/meta/name.rs index 0d997a57c..0399828d8 100644 --- a/src/meta/name.rs +++ b/src/meta/name.rs @@ -107,7 +107,7 @@ mod test { #[test] fn test_print_file_name() { let tmp_dir = TempDir::new("test_print_file_name").expect("failed to create temp dir"); - let icons = Icons::new(icon::Theme::Default); + let icons = Icons::new(icon::Theme::Fancy); // Create the file; let file_path = tmp_dir.path().join("file.txt"); @@ -127,7 +127,7 @@ mod test { #[test] fn test_print_dir_name() { let tmp_dir = TempDir::new("test_print_dir_name").expect("failed to create temp dir"); - let icons = Icons::new(icon::Theme::Default); + let icons = Icons::new(icon::Theme::Fancy); // Chreate the directory let dir_path = tmp_dir.path().join("directory"); @@ -147,7 +147,7 @@ mod test { #[test] fn test_print_symlink_name() { let tmp_dir = TempDir::new("test_symlink_name").expect("failed to create temp dir"); - let icons = Icons::new(icon::Theme::Default); + let icons = Icons::new(icon::Theme::Fancy); // Create the file; let file_path = tmp_dir.path().join("file.tmp"); @@ -173,7 +173,7 @@ mod test { #[test] fn test_print_other_type_name() { let tmp_dir = TempDir::new("test_other_type_name").expect("failed to create temp dir"); - let icons = Icons::new(icon::Theme::Default); + let icons = Icons::new(icon::Theme::Fancy); // Create the pipe; let pipe_path = tmp_dir.path().join("pipe.tmp");