mirror of
https://github.com/eza-community/eza
synced 2024-09-06 00:13:51 +00:00
feat(ui): Make file types themeable
This commit is contained in:
parent
f149fe6afb
commit
b5174b1582
|
@ -7,11 +7,9 @@
|
|||
//! # Contributors
|
||||
//! Please keep these lists sorted. If you're using vim, :sort i
|
||||
|
||||
use ansiterm::Style;
|
||||
use phf::{phf_map, Map};
|
||||
|
||||
use crate::fs::File;
|
||||
use crate::theme::FileColours;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FileType {
|
||||
|
@ -269,7 +267,7 @@ impl FileType {
|
|||
/// Lookup the file type based on the file's name, by the file name
|
||||
/// lowercase extension, or if the file could be compiled from related
|
||||
/// source code.
|
||||
fn get_file_type(file: &File<'_>) -> Option<FileType> {
|
||||
pub(crate) fn get_file_type(file: &File<'_>) -> Option<FileType> {
|
||||
// Case-insensitive readme is checked first for backwards compatibility.
|
||||
if file.name.to_lowercase().starts_with("readme") {
|
||||
return Some(Self::Immediate)
|
||||
|
@ -291,27 +289,3 @@ impl FileType {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileTypeColor;
|
||||
|
||||
impl FileColours for FileTypeColor {
|
||||
/// Map from the file type to the display style/color for the file.
|
||||
fn colour_file(&self, file: &File<'_>) -> Option<Style> {
|
||||
use ansiterm::Colour::*;
|
||||
|
||||
match FileType::get_file_type(file) {
|
||||
Some(FileType::Compiled) => Some(Yellow.normal()),
|
||||
Some(FileType::Compressed) => Some(Red.normal()),
|
||||
Some(FileType::Crypto) => Some(Green.bold()),
|
||||
Some(FileType::Document) => Some(Green.normal()),
|
||||
Some(FileType::Image) => Some(Purple.normal()),
|
||||
Some(FileType::Immediate) => Some(Yellow.bold().underline()),
|
||||
Some(FileType::Lossless) => Some(Cyan.bold()),
|
||||
Some(FileType::Music) => Some(Cyan.normal()),
|
||||
Some(FileType::Temp) => Some(White.normal()),
|
||||
Some(FileType::Video) => Some(Purple.bold()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,19 @@ impl UiStyles {
|
|||
},
|
||||
},
|
||||
|
||||
file_type: FileType {
|
||||
image: Purple.normal(),
|
||||
video: Purple.bold(),
|
||||
music: Cyan.normal(),
|
||||
lossless: Cyan.bold(),
|
||||
crypto: Green.bold(),
|
||||
document: Green.normal(),
|
||||
compressed: Red.normal(),
|
||||
temp: White.normal(),
|
||||
compiled: Yellow.normal(),
|
||||
immediate: Yellow.bold().underline()
|
||||
},
|
||||
|
||||
punctuation: DarkGray.bold(),
|
||||
date: Blue.normal(),
|
||||
inode: Purple.normal(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use ansiterm::Style;
|
||||
|
||||
use crate::fs::File;
|
||||
use crate::info::filetype::FileType;
|
||||
use crate::output::file_name::Colours as FileNameColours;
|
||||
use crate::output::render;
|
||||
|
||||
|
@ -65,8 +66,6 @@ impl Options {
|
|||
|
||||
#[allow(trivial_casts)] // the `as Box<_>` stuff below warns about this for some reason
|
||||
pub fn to_theme(&self, isatty: bool) -> Theme {
|
||||
use crate::info::filetype::FileTypeColor;
|
||||
|
||||
if self.use_colours == UseColours::Never || (self.use_colours == UseColours::Automatic && ! isatty) {
|
||||
let ui = UiStyles::plain();
|
||||
let exts = Box::new(NoFileColours);
|
||||
|
@ -79,10 +78,10 @@ impl Options {
|
|||
|
||||
// Use between 0 and 2 file name highlighters
|
||||
let exts = match (exts.is_non_empty(), use_default_filetypes) {
|
||||
(false, false) => Box::new(NoFileColours) as Box<_>,
|
||||
(false, true) => Box::new(FileTypeColor) as Box<_>,
|
||||
( true, false) => Box::new(exts) as Box<_>,
|
||||
( true, true) => Box::new((exts, FileTypeColor)) as Box<_>,
|
||||
(false, false) => Box::new(NoFileColours) as Box<_>,
|
||||
(false, true) => Box::new(FileTypes) as Box<_>,
|
||||
( true, false) => Box::new(exts) as Box<_>,
|
||||
( true, true) => Box::new((exts, FileTypes)) as Box<_>,
|
||||
};
|
||||
|
||||
Theme { ui, exts }
|
||||
|
@ -145,13 +144,13 @@ impl Definitions {
|
|||
|
||||
|
||||
pub trait FileColours: std::marker::Sync {
|
||||
fn colour_file(&self, file: &File<'_>) -> Option<Style>;
|
||||
fn colour_file(&self, file: &File<'_>, theme: &Theme) -> Option<Style>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct NoFileColours;
|
||||
impl FileColours for NoFileColours {
|
||||
fn colour_file(&self, _file: &File<'_>) -> Option<Style> {
|
||||
fn colour_file(&self, _file: &File<'_>, _theme: &Theme) -> Option<Style> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -164,9 +163,9 @@ impl<A, B> FileColours for (A, B)
|
|||
where A: FileColours,
|
||||
B: FileColours,
|
||||
{
|
||||
fn colour_file(&self, file: &File<'_>) -> Option<Style> {
|
||||
self.0.colour_file(file)
|
||||
.or_else(|| self.1.colour_file(file))
|
||||
fn colour_file(&self, file: &File<'_>, theme: &Theme) -> Option<Style> {
|
||||
self.0.colour_file(file, theme)
|
||||
.or_else(|| self.1.colour_file(file, theme))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,17 +175,6 @@ struct ExtensionMappings {
|
|||
mappings: Vec<(glob::Pattern, Style)>,
|
||||
}
|
||||
|
||||
// Loop through backwards so that colours specified later in the list override
|
||||
// colours specified earlier, like we do with options and strict mode
|
||||
|
||||
impl FileColours for ExtensionMappings {
|
||||
fn colour_file(&self, file: &File<'_>) -> Option<Style> {
|
||||
self.mappings.iter().rev()
|
||||
.find(|t| t.0.matches(&file.name))
|
||||
.map (|t| t.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtensionMappings {
|
||||
fn is_non_empty(&self) -> bool {
|
||||
! self.mappings.is_empty()
|
||||
|
@ -197,8 +185,37 @@ impl ExtensionMappings {
|
|||
}
|
||||
}
|
||||
|
||||
// Loop through backwards so that colours specified later in the list override
|
||||
// colours specified earlier, like we do with options and strict mode
|
||||
|
||||
impl FileColours for ExtensionMappings {
|
||||
fn colour_file(&self, file: &File<'_>, _theme: &Theme) -> Option<Style> {
|
||||
self.mappings.iter().rev()
|
||||
.find(|t| t.0.matches(&file.name))
|
||||
.map (|t| t.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FileTypes;
|
||||
|
||||
impl FileColours for FileTypes {
|
||||
fn colour_file(&self, file: &File<'_>, theme: &Theme) -> Option<Style> {
|
||||
match FileType::get_file_type(file) {
|
||||
Some(FileType::Image) => Some(theme.ui.file_type.image),
|
||||
Some(FileType::Video) => Some(theme.ui.file_type.video),
|
||||
Some(FileType::Music) => Some(theme.ui.file_type.music),
|
||||
Some(FileType::Lossless) => Some(theme.ui.file_type.lossless),
|
||||
Some(FileType::Crypto) => Some(theme.ui.file_type.crypto),
|
||||
Some(FileType::Document) => Some(theme.ui.file_type.document),
|
||||
Some(FileType::Compressed) => Some(theme.ui.file_type.compressed),
|
||||
Some(FileType::Temp) => Some(theme.ui.file_type.temp),
|
||||
Some(FileType::Compiled) => Some(theme.ui.file_type.compiled),
|
||||
Some(FileType::Immediate) => Some(theme.ui.file_type.immediate),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl render::BlocksColours for Theme {
|
||||
|
@ -330,7 +347,7 @@ impl FileNameColours for Theme {
|
|||
fn mount_point(&self) -> Style { self.ui.filekinds.mount_point }
|
||||
|
||||
fn colour_file(&self, file: &File<'_>) -> Style {
|
||||
self.exts.colour_file(file).unwrap_or(self.ui.filekinds.normal)
|
||||
self.exts.colour_file(file, &self).unwrap_or(self.ui.filekinds.normal)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,6 +554,17 @@ mod customs_test {
|
|||
|
||||
test!(exa_mp: ls "", exa "mp=1;34;4" => colours c -> { c.filekinds.mount_point = Blue.bold().underline(); });
|
||||
|
||||
test!(exa_im: ls "", exa "im=38;5;128" => colours c -> { c.file_type.image = Fixed(128).normal(); });
|
||||
test!(exa_vi: ls "", exa "vi=38;5;129" => colours c -> { c.file_type.video = Fixed(129).normal(); });
|
||||
test!(exa_mu: ls "", exa "mu=38;5;130" => colours c -> { c.file_type.music = Fixed(130).normal(); });
|
||||
test!(exa_lo: ls "", exa "lo=38;5;131" => colours c -> { c.file_type.lossless = Fixed(131).normal(); });
|
||||
test!(exa_cr: ls "", exa "cr=38;5;132" => colours c -> { c.file_type.crypto = Fixed(132).normal(); });
|
||||
test!(exa_do: ls "", exa "do=38;5;133" => colours c -> { c.file_type.document = Fixed(133).normal(); });
|
||||
test!(exa_co: ls "", exa "co=38;5;134" => colours c -> { c.file_type.compressed = Fixed(134).normal(); });
|
||||
test!(exa_tm: ls "", exa "tm=38;5;135" => colours c -> { c.file_type.temp = Fixed(135).normal(); });
|
||||
test!(exa_cm: ls "", exa "cm=38;5;136" => colours c -> { c.file_type.compiled = Fixed(136).normal(); });
|
||||
test!(exa_ie: ls "", exa "ie=38;5;137" => colours c -> { c.file_type.immediate = Fixed(137).normal(); });
|
||||
|
||||
// All the while, LS_COLORS treats them as filenames:
|
||||
test!(ls_uu: ls "uu=38;5;117", exa "" => exts [ ("uu", Fixed(117).normal()) ]);
|
||||
test!(ls_un: ls "un=38;5;118", exa "" => exts [ ("un", Fixed(118).normal()) ]);
|
||||
|
|
|
@ -14,6 +14,7 @@ pub struct UiStyles {
|
|||
pub links: Links,
|
||||
pub git: Git,
|
||||
pub security_context: SecurityContext,
|
||||
pub file_type: FileType,
|
||||
|
||||
pub punctuation: Style,
|
||||
pub date: Style,
|
||||
|
@ -121,6 +122,20 @@ pub struct SecurityContext {
|
|||
pub selinux: SELinuxContext,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct FileType {
|
||||
pub image: Style,
|
||||
pub video: Style,
|
||||
pub music: Style,
|
||||
pub lossless: Style,
|
||||
pub crypto: Style,
|
||||
pub document: Style,
|
||||
pub compressed: Style,
|
||||
pub temp: Style,
|
||||
pub compiled: Style,
|
||||
pub immediate: Style,
|
||||
}
|
||||
|
||||
impl UiStyles {
|
||||
pub fn plain() -> Self {
|
||||
Self::default()
|
||||
|
@ -213,6 +228,17 @@ impl UiStyles {
|
|||
|
||||
"mp" => self.filekinds.mount_point = pair.to_style(),
|
||||
|
||||
"im" => self.file_type.image = pair.to_style(),
|
||||
"vi" => self.file_type.video = pair.to_style(),
|
||||
"mu" => self.file_type.music = pair.to_style(),
|
||||
"lo" => self.file_type.lossless = pair.to_style(),
|
||||
"cr" => self.file_type.crypto = pair.to_style(),
|
||||
"do" => self.file_type.document = pair.to_style(),
|
||||
"co" => self.file_type.compressed = pair.to_style(),
|
||||
"tm" => self.file_type.temp = pair.to_style(),
|
||||
"cm" => self.file_type.compiled = pair.to_style(),
|
||||
"ie" => self.file_type.immediate = pair.to_style(),
|
||||
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue