mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-22 20:15:11 +00:00
Implement file name colouring in {exa,ls}_colors
This commit adds to the parsing of the LS_COLORS and EXA_COLORS variables so that non-two-letter codes (keys other than things like ‘di’ or ‘ln’ or ‘ex’) will be treated as file name globs, and get used to colour files accordingly. Fixes #116 for good.
This commit is contained in:
parent
b86074d63b
commit
dc45332d7b
@ -1,9 +1,11 @@
|
|||||||
use style::Colours;
|
use ansi_term::Style;
|
||||||
use output::file_name::{FileStyle, Classify};
|
use glob;
|
||||||
|
|
||||||
|
use fs::File;
|
||||||
use options::{flags, Vars, Misfire};
|
use options::{flags, Vars, Misfire};
|
||||||
use options::parser::MatchedFlags;
|
use options::parser::MatchedFlags;
|
||||||
|
use output::file_name::{FileStyle, Classify};
|
||||||
|
use style::Colours;
|
||||||
|
|
||||||
|
|
||||||
/// Under what circumstances we should display coloured, rather than plain,
|
/// Under what circumstances we should display coloured, rather than plain,
|
||||||
@ -82,12 +84,12 @@ impl Styles {
|
|||||||
where TW: Fn() -> Option<usize>, V: Vars {
|
where TW: Fn() -> Option<usize>, V: Vars {
|
||||||
use self::TerminalColours::*;
|
use self::TerminalColours::*;
|
||||||
use info::filetype::FileExtensions;
|
use info::filetype::FileExtensions;
|
||||||
use style::LSColors;
|
|
||||||
use options::vars;
|
|
||||||
use output::file_name::NoFileColours;
|
use output::file_name::NoFileColours;
|
||||||
|
|
||||||
let classify = Classify::deduce(matches)?;
|
let classify = Classify::deduce(matches)?;
|
||||||
|
|
||||||
|
// Before we do anything else, figure out if we need to consider
|
||||||
|
// custom colours at all
|
||||||
let tc = TerminalColours::deduce(matches)?;
|
let tc = TerminalColours::deduce(matches)?;
|
||||||
if tc == Never || (tc == Automatic && widther().is_none()) {
|
if tc == Never || (tc == Automatic && widther().is_none()) {
|
||||||
return Ok(Styles {
|
return Ok(Styles {
|
||||||
@ -96,32 +98,103 @@ impl Styles {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the environment variables into colours and extension mappings
|
||||||
let scale = matches.has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?;
|
let scale = matches.has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?;
|
||||||
let mut colours = Colours::colourful(scale.is_some());
|
let mut colours = Colours::colourful(scale.is_some());
|
||||||
|
|
||||||
if let Some(lsc) = vars.get(vars::LS_COLORS) {
|
let (exts, use_default_filetypes) = parse_color_vars(vars, &mut colours);
|
||||||
let lsc = lsc.to_string_lossy();
|
|
||||||
LSColors(lsc.as_ref()).each_pair(|pair| {
|
// Use between 0 and 2 file name highlighters
|
||||||
colours.set_ls(&pair);
|
let exts = match (exts.is_non_empty(), use_default_filetypes) {
|
||||||
});
|
(false, false) => Box::new(NoFileColours) as Box<_>,
|
||||||
}
|
(false, true) => Box::new(FileExtensions) as Box<_>,
|
||||||
|
( true, false) => Box::new(exts) as Box<_>,
|
||||||
|
( true, true) => Box::new((exts, FileExtensions)) as Box<_>,
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(exa) = vars.get(vars::EXA_COLORS) {
|
|
||||||
let exa = exa.to_string_lossy();
|
|
||||||
LSColors(exa.as_ref()).each_pair(|pair| {
|
|
||||||
colours.set_exa(&pair);
|
|
||||||
});
|
|
||||||
let style = FileStyle { classify, exts };
|
let style = FileStyle { classify, exts };
|
||||||
Ok(Styles { colours, style })
|
Ok(Styles { colours, style })
|
||||||
}
|
|
||||||
|
|
||||||
let classify = Classify::deduce(matches)?;
|
|
||||||
let exts = if colours.colourful { Box::new(FileExtensions) as Box<_> }
|
|
||||||
else { Box::new(NoFileColours) as Box<_> };
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the environment variables into LS_COLORS pairs, putting file glob
|
||||||
|
/// colours into the `ExtensionMappings` that gets returned, and using the
|
||||||
|
/// two-character UI codes to modify the mutable `Colours`.
|
||||||
|
///
|
||||||
|
/// Also returns if the EXA_COLORS variable should reset the existing file
|
||||||
|
/// type mappings or not. The `reset` code needs to be the first one.
|
||||||
|
fn parse_color_vars<V: Vars>(vars: &V, colours: &mut Colours) -> (ExtensionMappings, bool) {
|
||||||
|
use options::vars;
|
||||||
|
use style::LSColors;
|
||||||
|
|
||||||
|
let mut exts = ExtensionMappings::default();
|
||||||
|
|
||||||
|
if let Some(lsc) = vars.get(vars::LS_COLORS) {
|
||||||
|
let lsc = lsc.to_string_lossy();
|
||||||
|
LSColors(lsc.as_ref()).each_pair(|pair| {
|
||||||
|
if !colours.set_ls(&pair) {
|
||||||
|
match glob::Pattern::new(pair.key) {
|
||||||
|
Ok(pat) => exts.add(pat, pair.to_style()),
|
||||||
|
Err(e) => warn!("Couldn't parse glob pattern {:?}: {}", pair.key, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut use_default_filetypes = true;
|
||||||
|
|
||||||
|
if let Some(exa) = vars.get(vars::EXA_COLORS) {
|
||||||
|
let exa = exa.to_string_lossy();
|
||||||
|
|
||||||
|
// Is this hacky? Yes.
|
||||||
|
if exa == "reset" || exa.starts_with("reset:") {
|
||||||
|
use_default_filetypes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSColors(exa.as_ref()).each_pair(|pair| {
|
||||||
|
if !colours.set_ls(&pair) && !colours.set_exa(&pair) {
|
||||||
|
match glob::Pattern::new(pair.key) {
|
||||||
|
Ok(pat) => exts.add(pat, pair.to_style()),
|
||||||
|
Err(e) => warn!("Couldn't parse glob pattern {:?}: {}", pair.key, e),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
(exts, use_default_filetypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Default)]
|
||||||
|
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
|
||||||
|
|
||||||
|
use output::file_name::FileColours;
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, pattern: glob::Pattern, style: Style) {
|
||||||
|
self.mappings.push((pattern, style))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl Classify {
|
impl Classify {
|
||||||
fn deduce(matches: &MatchedFlags) -> Result<Classify, Misfire> {
|
fn deduce(matches: &MatchedFlags) -> Result<Classify, Misfire> {
|
||||||
@ -219,7 +292,7 @@ mod colour_test {
|
|||||||
($name:ident: $inputs:expr, $widther:expr; $stricts:expr => $result:expr) => {
|
($name:ident: $inputs:expr, $widther:expr; $stricts:expr => $result:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Style::deduce(mf, &None, &$widther).map(|s| s.colours)) {
|
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Styles::deduce(mf, &None, &$widther).map(|s| s.colours)) {
|
||||||
assert_eq!(result, $result);
|
assert_eq!(result, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +301,7 @@ mod colour_test {
|
|||||||
($name:ident: $inputs:expr, $widther:expr; $stricts:expr => err $result:expr) => {
|
($name:ident: $inputs:expr, $widther:expr; $stricts:expr => err $result:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Style::deduce(mf, &None, &$widther).map(|s| s.colours)) {
|
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Styles::deduce(mf, &None, &$widther).map(|s| s.colours)) {
|
||||||
assert_eq!(result.unwrap_err(), $result);
|
assert_eq!(result.unwrap_err(), $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +310,7 @@ mod colour_test {
|
|||||||
($name:ident: $inputs:expr, $widther:expr; $stricts:expr => like $pat:pat) => {
|
($name:ident: $inputs:expr, $widther:expr; $stricts:expr => like $pat:pat) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Style::deduce(mf, &None, &$widther).map(|s| s.colours)) {
|
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Styles::deduce(mf, &None, &$widther).map(|s| s.colours)) {
|
||||||
println!("Testing {:?}", result);
|
println!("Testing {:?}", result);
|
||||||
match result {
|
match result {
|
||||||
$pat => assert!(true),
|
$pat => assert!(true),
|
||||||
@ -276,23 +349,57 @@ mod customs_test {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use options::Vars;
|
use options::Vars;
|
||||||
use options::test::parse_for_test;
|
|
||||||
use options::test::Strictnesses::Both;
|
|
||||||
|
|
||||||
use ansi_term::Colour::*;
|
use ansi_term::Colour::*;
|
||||||
|
|
||||||
macro_rules! test {
|
macro_rules! test {
|
||||||
($name:ident: ls $ls:expr, exa $exa:expr => $resulter:expr) => {
|
($name:ident: ls $ls:expr, exa $exa:expr => colours $expected:ident -> $process_expected:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(unused_mut)]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
let mut c = Colours::colourful(false);
|
let mut $expected = Colours::colourful(false);
|
||||||
$resulter(&mut c);
|
$process_expected();
|
||||||
|
|
||||||
let vars = MockVars { ls: $ls, exa: $exa };
|
let vars = MockVars { ls: $ls, exa: $exa };
|
||||||
|
|
||||||
for result in parse_for_test(&[], &[], Both, |mf| Style::deduce(mf, &vars, || Some(80)).map(|s| s.colours)) {
|
let mut result = Colours::colourful(false);
|
||||||
assert_eq!(result.as_ref(), Ok(&c));
|
let (_exts, _reset) = parse_color_vars(&vars, &mut result);
|
||||||
}
|
assert_eq!($expected, result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($name:ident: ls $ls:expr, exa $exa:expr => exts $mappings:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $name() {
|
||||||
|
let mappings: Vec<(glob::Pattern, Style)>
|
||||||
|
= $mappings.into_iter()
|
||||||
|
.map(|t| (glob::Pattern::new(t.0).unwrap(), t.1))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let vars = MockVars { ls: $ls, exa: $exa };
|
||||||
|
|
||||||
|
let mut meh = Colours::colourful(false);
|
||||||
|
let (result, _reset) = parse_color_vars(&vars, &mut meh);
|
||||||
|
assert_eq!(ExtensionMappings { mappings }, result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($name:ident: ls $ls:expr, exa $exa:expr => colours $expected:ident -> $process_expected:expr, exts $mappings:expr) => {
|
||||||
|
#[test]
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
fn $name() {
|
||||||
|
let mut $expected = Colours::colourful(false);
|
||||||
|
$process_expected();
|
||||||
|
|
||||||
|
let mappings: Vec<(glob::Pattern, Style)>
|
||||||
|
= $mappings.into_iter()
|
||||||
|
.map(|t| (glob::Pattern::new(t.0).unwrap(), t.1))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let vars = MockVars { ls: $ls, exa: $exa };
|
||||||
|
|
||||||
|
let mut meh = Colours::colourful(false);
|
||||||
|
let (result, _reset) = parse_color_vars(&vars, &mut meh);
|
||||||
|
assert_eq!(ExtensionMappings { mappings }, result);
|
||||||
|
assert_eq!($expected, meh);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -319,14 +426,103 @@ mod customs_test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test!(ls_di: ls "di=31", exa "" => |c: &mut Colours| { c.filekinds.directory = Red.normal(); }); // Directory
|
// LS_COLORS can affect all of these colours:
|
||||||
test!(ls_ex: ls "ex=32", exa "" => |c: &mut Colours| { c.filekinds.executable = Green.normal(); }); // Executable file
|
test!(ls_di: ls "di=31", exa "" => colours c -> { c.filekinds.directory = Red.normal(); });
|
||||||
test!(ls_fi: ls "fi=33", exa "" => |c: &mut Colours| { c.filekinds.normal = Yellow.normal(); }); // Regular file
|
test!(ls_ex: ls "ex=32", exa "" => colours c -> { c.filekinds.executable = Green.normal(); });
|
||||||
test!(ls_pi: ls "pi=34", exa "" => |c: &mut Colours| { c.filekinds.pipe = Blue.normal(); }); // FIFO
|
test!(ls_fi: ls "fi=33", exa "" => colours c -> { c.filekinds.normal = Yellow.normal(); });
|
||||||
test!(ls_so: ls "so=35", exa "" => |c: &mut Colours| { c.filekinds.socket = Purple.normal(); }); // Socket
|
test!(ls_pi: ls "pi=34", exa "" => colours c -> { c.filekinds.pipe = Blue.normal(); });
|
||||||
test!(ls_bd: ls "bd=36", exa "" => |c: &mut Colours| { c.filekinds.block_device = Cyan.normal(); }); // Block device
|
test!(ls_so: ls "so=35", exa "" => colours c -> { c.filekinds.socket = Purple.normal(); });
|
||||||
test!(ls_cd: ls "cd=35", exa "" => |c: &mut Colours| { c.filekinds.char_device = Purple.normal(); }); // Character device
|
test!(ls_bd: ls "bd=36", exa "" => colours c -> { c.filekinds.block_device = Cyan.normal(); });
|
||||||
test!(ls_ln: ls "ln=34", exa "" => |c: &mut Colours| { c.filekinds.symlink = Blue.normal(); }); // Symlink
|
test!(ls_cd: ls "cd=35", exa "" => colours c -> { c.filekinds.char_device = Purple.normal(); });
|
||||||
test!(ls_or: ls "or=33", exa "" => |c: &mut Colours| { c.broken_arrow = Yellow.normal(); }); // Broken link
|
test!(ls_ln: ls "ln=34", exa "" => colours c -> { c.filekinds.symlink = Blue.normal(); });
|
||||||
test!(ls_mi: ls "mi=32", exa "" => |c: &mut Colours| { c.broken_filename = Green.normal(); }); // Broken link target
|
test!(ls_or: ls "or=33", exa "" => colours c -> { c.broken_arrow = Yellow.normal(); });
|
||||||
|
test!(ls_mi: ls "mi=32", exa "" => colours c -> { c.broken_filename = Green.normal(); });
|
||||||
|
|
||||||
|
// EXA_COLORS can affect all those colours too:
|
||||||
|
test!(exa_di: ls "", exa "di=32" => colours c -> { c.filekinds.directory = Green.normal(); });
|
||||||
|
test!(exa_ex: ls "", exa "ex=33" => colours c -> { c.filekinds.executable = Yellow.normal(); });
|
||||||
|
test!(exa_fi: ls "", exa "fi=34" => colours c -> { c.filekinds.normal = Blue.normal(); });
|
||||||
|
test!(exa_pi: ls "", exa "pi=35" => colours c -> { c.filekinds.pipe = Purple.normal(); });
|
||||||
|
test!(exa_so: ls "", exa "so=36" => colours c -> { c.filekinds.socket = Cyan.normal(); });
|
||||||
|
test!(exa_bd: ls "", exa "bd=35" => colours c -> { c.filekinds.block_device = Purple.normal(); });
|
||||||
|
test!(exa_cd: ls "", exa "cd=34" => colours c -> { c.filekinds.char_device = Blue.normal(); });
|
||||||
|
test!(exa_ln: ls "", exa "ln=33" => colours c -> { c.filekinds.symlink = Yellow.normal(); });
|
||||||
|
test!(exa_or: ls "", exa "or=32" => colours c -> { c.broken_arrow = Green.normal(); });
|
||||||
|
test!(exa_mi: ls "", exa "mi=31" => colours c -> { c.broken_filename = Red.normal(); });
|
||||||
|
|
||||||
|
// EXA_COLORS will even override options from LS_COLORS:
|
||||||
|
test!(ls_exa_di: ls "di=31", exa "di=32" => colours c -> { c.filekinds.directory = Green.normal(); });
|
||||||
|
test!(ls_exa_ex: ls "ex=32", exa "ex=33" => colours c -> { c.filekinds.executable = Yellow.normal(); });
|
||||||
|
test!(ls_exa_fi: ls "fi=33", exa "fi=34" => colours c -> { c.filekinds.normal = Blue.normal(); });
|
||||||
|
|
||||||
|
// But more importantly, EXA_COLORS has its own, special list of colours:
|
||||||
|
test!(exa_ur: ls "", exa "ur=38;5;100" => colours c -> { c.perms.user_read = Fixed(100).normal(); });
|
||||||
|
test!(exa_uw: ls "", exa "uw=38;5;101" => colours c -> { c.perms.user_write = Fixed(101).normal(); });
|
||||||
|
test!(exa_ux: ls "", exa "ux=38;5;102" => colours c -> { c.perms.user_execute_file = Fixed(102).normal(); });
|
||||||
|
test!(exa_ue: ls "", exa "ue=38;5;103" => colours c -> { c.perms.user_execute_other = Fixed(103).normal(); });
|
||||||
|
test!(exa_gr: ls "", exa "gr=38;5;104" => colours c -> { c.perms.group_read = Fixed(104).normal(); });
|
||||||
|
test!(exa_gw: ls "", exa "gw=38;5;105" => colours c -> { c.perms.group_write = Fixed(105).normal(); });
|
||||||
|
test!(exa_gx: ls "", exa "gx=38;5;106" => colours c -> { c.perms.group_execute = Fixed(106).normal(); });
|
||||||
|
test!(exa_tr: ls "", exa "tr=38;5;107" => colours c -> { c.perms.other_read = Fixed(107).normal(); });
|
||||||
|
test!(exa_tw: ls "", exa "tw=38;5;108" => colours c -> { c.perms.other_write = Fixed(108).normal(); });
|
||||||
|
test!(exa_tx: ls "", exa "tx=38;5;109" => colours c -> { c.perms.other_execute = Fixed(109).normal(); });
|
||||||
|
test!(exa_su: ls "", exa "su=38;5;110" => colours c -> { c.perms.special_user_file = Fixed(110).normal(); });
|
||||||
|
test!(exa_sf: ls "", exa "sf=38;5;111" => colours c -> { c.perms.special_other = Fixed(111).normal(); });
|
||||||
|
test!(exa_xa: ls "", exa "xa=38;5;112" => colours c -> { c.perms.attribute = Fixed(112).normal(); });
|
||||||
|
|
||||||
|
test!(exa_sn: ls "", exa "sn=38;5;113" => colours c -> { c.size.numbers = Fixed(113).normal(); });
|
||||||
|
test!(exa_sb: ls "", exa "sb=38;5;114" => colours c -> { c.size.unit = Fixed(114).normal(); });
|
||||||
|
test!(exa_df: ls "", exa "df=38;5;115" => colours c -> { c.size.major = Fixed(115).normal(); });
|
||||||
|
test!(exa_ds: ls "", exa "ds=38;5;116" => colours c -> { c.size.minor = Fixed(116).normal(); });
|
||||||
|
|
||||||
|
test!(exa_uu: ls "", exa "uu=38;5;117" => colours c -> { c.users.user_you = Fixed(117).normal(); });
|
||||||
|
test!(exa_un: ls "", exa "un=38;5;118" => colours c -> { c.users.user_someone_else = Fixed(118).normal(); });
|
||||||
|
test!(exa_gu: ls "", exa "gu=38;5;119" => colours c -> { c.users.group_yours = Fixed(119).normal(); });
|
||||||
|
test!(exa_gn: ls "", exa "gn=38;5;120" => colours c -> { c.users.group_not_yours = Fixed(120).normal(); });
|
||||||
|
|
||||||
|
test!(exa_lc: ls "", exa "lc=38;5;121" => colours c -> { c.links.normal = Fixed(121).normal(); });
|
||||||
|
test!(exa_lm: ls "", exa "lm=38;5;122" => colours c -> { c.links.multi_link_file = Fixed(122).normal(); });
|
||||||
|
|
||||||
|
test!(exa_ga: ls "", exa "ga=38;5;123" => colours c -> { c.git.new = Fixed(123).normal(); });
|
||||||
|
test!(exa_gm: ls "", exa "gm=38;5;124" => colours c -> { c.git.modified = Fixed(124).normal(); });
|
||||||
|
test!(exa_gd: ls "", exa "gd=38;5;125" => colours c -> { c.git.deleted = Fixed(125).normal(); });
|
||||||
|
test!(exa_gv: ls "", exa "gv=38;5;126" => colours c -> { c.git.renamed = Fixed(126).normal(); });
|
||||||
|
test!(exa_gt: ls "", exa "gt=38;5;127" => colours c -> { c.git.typechange = Fixed(127).normal(); });
|
||||||
|
|
||||||
|
test!(exa_xx: ls "", exa "xx=38;5;128" => colours c -> { c.punctuation = Fixed(128).normal(); });
|
||||||
|
test!(exa_da: ls "", exa "da=38;5;129" => colours c -> { c.date = Fixed(129).normal(); });
|
||||||
|
test!(exa_in: ls "", exa "in=38;5;130" => colours c -> { c.inode = Fixed(130).normal(); });
|
||||||
|
test!(exa_bl: ls "", exa "bl=38;5;131" => colours c -> { c.blocks = Fixed(131).normal(); });
|
||||||
|
test!(exa_hd: ls "", exa "hd=38;5;132" => colours c -> { c.header = Fixed(132).normal(); });
|
||||||
|
test!(exa_lp: ls "", exa "lp=38;5;133" => colours c -> { c.symlink_path = Fixed(133).normal(); });
|
||||||
|
test!(exa_cc: ls "", exa "cc=38;5;134" => colours c -> { c.control_char = Fixed(134).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()) ]);
|
||||||
|
test!(ls_gu: ls "gu=38;5;119", exa "" => exts [ ("gu", Fixed(119).normal()) ]);
|
||||||
|
test!(ls_gn: ls "gn=38;5;120", exa "" => exts [ ("gn", Fixed(120).normal()) ]);
|
||||||
|
|
||||||
|
// Just like all other keys:
|
||||||
|
test!(ls_txt: ls "*.txt=31", exa "" => exts [ ("*.txt", Red.normal()) ]);
|
||||||
|
test!(ls_mp3: ls "*.mp3=38;5;135", exa "" => exts [ ("*.mp3", Fixed(135).normal()) ]);
|
||||||
|
test!(ls_mak: ls "Makefile=1;32;4", exa "" => exts [ ("Makefile", Green.bold().underline()) ]);
|
||||||
|
test!(exa_txt: ls "", exa "*.zip=31" => exts [ ("*.zip", Red.normal()) ]);
|
||||||
|
test!(exa_mp3: ls "", exa "lev.*=38;5;153" => exts [ ("lev.*", Fixed(153).normal()) ]);
|
||||||
|
test!(exa_mak: ls "", exa "Cargo.toml=4;32;1" => exts [ ("Cargo.toml", Green.bold().underline()) ]);
|
||||||
|
|
||||||
|
// Testing whether a glob from EXA_COLORS overrides a glob from LS_COLORS
|
||||||
|
// can’t be tested here, because they’ll both be added to the same vec
|
||||||
|
|
||||||
|
// Values get separated by colons:
|
||||||
|
test!(ls_multi: ls "*.txt=31:*.rtf=32", exa "" => exts [ ("*.txt", Red.normal()), ("*.rtf", Green.normal()) ]);
|
||||||
|
test!(exa_multi: ls "", exa "*.tmp=37:*.log=37" => exts [ ("*.tmp", White.normal()), ("*.log", White.normal()) ]);
|
||||||
|
|
||||||
|
test!(ls_five: ls "1*1=31:2*2=32:3*3=1;33:4*4=34;1:5*5=35;4", exa "" => exts [
|
||||||
|
("1*1", Red.normal()), ("2*2", Green.normal()), ("3*3", Yellow.bold()), ("4*4", Blue.bold()), ("5*5", Purple.underline())
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Finally, colours get applied right-to-left:
|
||||||
|
test!(ls_overwrite: ls "pi=31:pi=32:pi=33", exa "" => colours c -> { c.filekinds.pipe = Yellow.normal(); });
|
||||||
|
test!(exa_overwrite: ls "", exa "da=36:da=35:da=34" => colours c -> { c.date = Blue.normal(); });
|
||||||
}
|
}
|
||||||
|
@ -285,3 +285,13 @@ impl FileColours for NoFileColours {
|
|||||||
fn colour_file(&self, _file: &File) -> Option<Style> { None }
|
fn colour_file(&self, _file: &File) -> Option<Style> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When getting the colour of a file from a *pair* of colourisers, try the
|
||||||
|
// first one then try the second one. This lets the user provide their own
|
||||||
|
// file type associations, while falling back to the default set if not set
|
||||||
|
// explicitly.
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -158,17 +158,17 @@ env LANG=ja_JP.UTF-8 $exa $testcases/dates -l | diff -q - $results/dates_jp ||
|
|||||||
# These directories are created in the VM user’s home directory (the default
|
# These directories are created in the VM user’s home directory (the default
|
||||||
# location) when a Cargo build is done.
|
# location) when a Cargo build is done.
|
||||||
(cd; mkdir -p target/debug/build
|
(cd; mkdir -p target/debug/build
|
||||||
$exa -1d target target/debug target/debug/build | diff -q - $results/dir_paths) || exit 1
|
$exa -1d target target/debug target/debug/build | diff -q - $results/dir_paths) || exit 1
|
||||||
$exa -1d . .. / | diff -q - $results/dirs || exit 1
|
$exa -1d . .. / | diff -q - $results/dirs || exit 1
|
||||||
|
|
||||||
|
|
||||||
# Links
|
# Links
|
||||||
COLUMNS=80 $exa $testcases/links 2>&1 | diff -q - $results/links || exit 1
|
COLUMNS=80 $exa $testcases/links 2>&1 | diff -q - $results/links || exit 1
|
||||||
$exa $testcases/links -1 2>&1 | diff -q - $results/links_1 || exit 1
|
$exa $testcases/links -1 2>&1 | diff -q - $results/links_1 || exit 1
|
||||||
$exa $testcases/links -T 2>&1 | diff -q - $results/links_T || exit 1
|
$exa $testcases/links -T 2>&1 | diff -q - $results/links_T || exit 1
|
||||||
$exa $testcases/links -T@ 2>&1 | diff -q - $results/links_T@ || exit 1
|
$exa $testcases/links -T@ 2>&1 | diff -q - $results/links_T@ || exit 1
|
||||||
$exa /proc/1/root -T 2>&1 | diff -q - $results/proc_1_root || exit 1
|
$exa /proc/1/root -T 2>&1 | diff -q - $results/proc_1_root || exit 1
|
||||||
$exa /proc/1/root -T@ 2>&1 | diff -q - $results/proc_1_root_@ || exit 1
|
$exa /proc/1/root -T@ 2>&1 | diff -q - $results/proc_1_root_@ || exit 1
|
||||||
|
|
||||||
# There’ve been bugs where the target file wasn’t printed properly when the
|
# There’ve been bugs where the target file wasn’t printed properly when the
|
||||||
# symlink file was specified on the command-line directly.
|
# symlink file was specified on the command-line directly.
|
||||||
@ -230,14 +230,35 @@ $exa $testcases/hiddens -l -a 2>&1 | diff -q - $results/hiddens_la || exit 1
|
|||||||
$exa $testcases/hiddens -l -aa 2>&1 | diff -q - $results/hiddens_laa || exit 1
|
$exa $testcases/hiddens -l -aa 2>&1 | diff -q - $results/hiddens_laa || exit 1
|
||||||
|
|
||||||
|
|
||||||
|
# Themes
|
||||||
|
LS_COLORS="bd=31:cd=32:pi=34" $exa -1 $testcases/specials 2>&1 | diff -q - $results/themed_specials || exit 1
|
||||||
|
EXA_COLORS="bd=31:cd=32:pi=34" $exa -1 $testcases/specials 2>&1 | diff -q - $results/themed_specials || exit 1
|
||||||
|
|
||||||
|
LS_COLORS="*.deb=1;37:*.tar.*=1;37" $exa -1 $testcases/file-names-exts/compressed.* 2>&1 | diff -q - $results/themed_compresseds || exit 1
|
||||||
|
EXA_COLORS="*.deb=1;37:*.tar.*=1;37" $exa -1 $testcases/file-names-exts/compressed.* 2>&1 | diff -q - $results/themed_compresseds || exit 1
|
||||||
|
EXA_COLORS="*.deb=1;37" LS_COLORS="*.tar.*=1;37" $exa -1 $testcases/file-names-exts/compressed.* 2>&1 | diff -q - $results/themed_compresseds || exit 1
|
||||||
|
|
||||||
|
LS_COLORS="reset:*.deb=1;37:*.tar.*=1;37" $exa -1 $testcases/file-names-exts/compressed.* 2>&1 | diff -q - $results/themed_compresseds || exit 1
|
||||||
|
EXA_COLORS="reset:*.deb=1;37:*.tar.*=1;37" $exa -1 $testcases/file-names-exts/compressed.* 2>&1 | diff -q - $results/themed_compresseds_r || exit 1
|
||||||
|
|
||||||
|
EXA_COLORS="or=32:mi=32;1;4:cc=34;1:ln=34:lp=36;4:xx=32" $exa -1 $testcases/file-names/links 2>&1 | diff -q - $results/themed_links || exit 1
|
||||||
|
|
||||||
|
# EXA_COLORS overrides LS_COLORS
|
||||||
|
LS_COLORS="bd=32:cd=34:pi=31" EXA_COLORS="bd=31:cd=32:pi=34" $exa -1 $testcases/specials 2>&1 | diff -q - $results/themed_specials || exit 1
|
||||||
|
|
||||||
|
EXA_COLORS="di=38;5;195:fi=38;5;250:xx=38;5;237:ur=38;5;194:uw=38;5;193:ux=38;5;192:gr=38;5;191:gw=38;5;190:gx=38;5;118:tr=38;5;119:tw=38;5;120:tx=38;5;121:su=38;5;51:sf=38;5;50:sn=38;5;49:un=38;5;46:da=38;5;47:ex=38;5;48" \
|
||||||
|
$exa --long $testcases/permissions 2>&1 | diff -q - $results/themed_long || exit 1
|
||||||
|
|
||||||
|
EXA_COLORS="reset" $exa $testcases/file-names-exts -1 2>&1 | diff -q - $results/themed_un || exit 1
|
||||||
|
|
||||||
# Errors
|
# Errors
|
||||||
$exa --binary 2>&1 | diff -q - $results/error_useless || exit 1
|
$exa --binary 2>&1 | diff -q - $results/error_useless || exit 1
|
||||||
$exa --ternary 2>&1 | diff -q - $results/error_long || exit 1
|
$exa --ternary 2>&1 | diff -q - $results/error_long || exit 1
|
||||||
$exa -4 2>&1 | diff -q - $results/error_short || exit 1
|
$exa -4 2>&1 | diff -q - $results/error_short || exit 1
|
||||||
$exa --time 2>&1 | diff -q - $results/error_value || exit 1
|
$exa --time 2>&1 | diff -q - $results/error_value || exit 1
|
||||||
$exa --long=time 2>&1 | diff -q - $results/error_overvalued || exit 1
|
$exa --long=time 2>&1 | diff -q - $results/error_overvalued || exit 1
|
||||||
$exa -l --long 2>&1 | diff -q - $results/error_duplicate || exit 1
|
$exa -l --long 2>&1 | diff -q - $results/error_duplicate || exit 1
|
||||||
$exa -ll 2>&1 | diff -q - $results/error_twice || exit 1
|
$exa -ll 2>&1 | diff -q - $results/error_twice || exit 1
|
||||||
|
|
||||||
|
|
||||||
# Debug mode
|
# Debug mode
|
||||||
@ -246,8 +267,8 @@ EXA_DEBUG="1" $exa $testcases/attributes/dirs/no-xattrs_empty -lh 2>&1 | tail -n
|
|||||||
|
|
||||||
|
|
||||||
# And finally...
|
# And finally...
|
||||||
$exa --help | diff -q - $results/help || exit 1
|
$exa --help | diff -q - $results/help || exit 1
|
||||||
$exa --help --long | diff -q - $results/help_long || exit 1
|
$exa --help --long | diff -q - $results/help_long || exit 1
|
||||||
|
|
||||||
|
|
||||||
echo "All the tests passed!"
|
echo "All the tests passed!"
|
||||||
|
5
xtests/themed_compresseds
Normal file
5
xtests/themed_compresseds
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[36m/testcases/file-names-exts/[1;37mcompressed.deb[0m
|
||||||
|
[36m/testcases/file-names-exts/[1;37mcompressed.tar.gz[0m
|
||||||
|
[36m/testcases/file-names-exts/[1;37mcompressed.tar.xz[0m
|
||||||
|
[36m/testcases/file-names-exts/[31mcompressed.tgz[0m
|
||||||
|
[36m/testcases/file-names-exts/[31mcompressed.txz[0m
|
5
xtests/themed_compresseds_r
Normal file
5
xtests/themed_compresseds_r
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[36m/testcases/file-names-exts/[1;37mcompressed.deb[0m
|
||||||
|
[36m/testcases/file-names-exts/[1;37mcompressed.tar.gz[0m
|
||||||
|
[36m/testcases/file-names-exts/[1;37mcompressed.tar.xz[0m
|
||||||
|
[36m/testcases/file-names-exts/[0mcompressed.tgz
|
||||||
|
[36m/testcases/file-names-exts/[0mcompressed.txz
|
3
xtests/themed_links
Normal file
3
xtests/themed_links
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[34manother: [[1m\n[0m[34m][0m [32m->[0m [4;36m/testcases/file-names/new-line-dir: [[0m[1;34m\n[0m[4;36m]/[0manother: [[1;34m\n[0m]
|
||||||
|
[34mbroken[0m [32m->[0m [1;4;32m/testcases/file-names/new-line-dir: [[34m\n[32m]/broken[0m
|
||||||
|
[34msubfile[0m [32m->[0m [4;36m/testcases/file-names/new-line-dir: [[0m[1;34m\n[0m[4;36m]/[0msubfile
|
22
xtests/themed_long
Normal file
22
xtests/themed_long
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[38;5;250m.[38;5;237m---------[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m000[0m
|
||||||
|
[38;5;250m.[38;5;237m--------[38;5;121mx[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m001[0m
|
||||||
|
[38;5;250m.[38;5;237m-------[38;5;120mw[38;5;237m-[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m002[0m
|
||||||
|
[38;5;250m.[38;5;237m------[38;5;119mr[38;5;237m--[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m004[0m
|
||||||
|
[38;5;250m.[38;5;237m-----[38;5;118mx[38;5;237m---[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m010[0m
|
||||||
|
[38;5;250m.[38;5;237m----[38;5;190mw[38;5;237m----[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m020[0m
|
||||||
|
[38;5;250m.[38;5;237m---[38;5;191mr[38;5;237m-----[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m040[0m
|
||||||
|
[38;5;250m.[38;5;237m--[38;5;192mx[38;5;237m------[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;48m100[0m
|
||||||
|
[38;5;250m.[38;5;237m-[38;5;193mw[38;5;237m-------[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m200[0m
|
||||||
|
[38;5;250m.[38;5;194mr[38;5;237m--------[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m400[0m
|
||||||
|
[38;5;250m.[38;5;194mr[38;5;193mw[38;5;237m-[38;5;191mr[38;5;237m--[38;5;119mr[38;5;237m--[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m644[0m
|
||||||
|
[38;5;250m.[38;5;194mr[38;5;193mw[38;5;192mx[38;5;191mr[38;5;237m-[38;5;118mx[38;5;119mr[38;5;237m-[38;5;121mx[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;48m755[0m
|
||||||
|
[38;5;250m.[38;5;194mr[38;5;193mw[38;5;192mx[38;5;191mr[38;5;190mw[38;5;118mx[38;5;119mr[38;5;120mw[38;5;121mx[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;48m777[0m
|
||||||
|
[38;5;250m.[38;5;237m--------[38;5;50mT[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m1000[0m
|
||||||
|
[38;5;250m.[38;5;237m--------[38;5;50mt[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m1001[0m
|
||||||
|
[38;5;250m.[38;5;237m-----[38;5;50mS[38;5;237m---[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m2000[0m
|
||||||
|
[38;5;250m.[38;5;237m-----[38;5;50ms[38;5;237m---[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m2010[0m
|
||||||
|
[38;5;250m.[38;5;237m--[38;5;50mS[38;5;237m------[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m4000[0m
|
||||||
|
[38;5;250m.[38;5;237m--[38;5;51ms[38;5;237m------[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;48m4100[0m
|
||||||
|
[38;5;250m.[38;5;194mr[38;5;193mw[38;5;50mS[38;5;191mr[38;5;190mw[38;5;50mS[38;5;119mr[38;5;120mw[38;5;50mT[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;250m7666[0m
|
||||||
|
[38;5;250m.[38;5;194mr[38;5;193mw[38;5;51ms[38;5;191mr[38;5;190mw[38;5;50ms[38;5;119mr[38;5;120mw[38;5;50mt[0m [38;5;49m0[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;48m7777[0m
|
||||||
|
[38;5;195md[38;5;237m---------[0m [38;5;237m-[0m [38;5;46mcassowary[0m [38;5;47m 1 Jan 12:34[0m [38;5;195mforbidden-directory[0m
|
3
xtests/themed_specials
Normal file
3
xtests/themed_specials
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[31mblock-device[0m
|
||||||
|
[32mchar-device[0m
|
||||||
|
[34mnamed-pipe[0m
|
26
xtests/themed_un
Normal file
26
xtests/themed_un
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#SAVEFILE#
|
||||||
|
backup~
|
||||||
|
compiled.class
|
||||||
|
compiled.coffee
|
||||||
|
compiled.js
|
||||||
|
compiled.o
|
||||||
|
compressed.deb
|
||||||
|
compressed.tar.gz
|
||||||
|
compressed.tar.xz
|
||||||
|
compressed.tgz
|
||||||
|
compressed.txz
|
||||||
|
COMPRESSED.ZIP
|
||||||
|
crypto.asc
|
||||||
|
crypto.signature
|
||||||
|
document.pdf
|
||||||
|
DOCUMENT.XLSX
|
||||||
|
file.tmp
|
||||||
|
IMAGE.PNG
|
||||||
|
image.svg
|
||||||
|
lossless.flac
|
||||||
|
lossless.wav
|
||||||
|
Makefile
|
||||||
|
music.mp3
|
||||||
|
MUSIC.OGG
|
||||||
|
VIDEO.AVI
|
||||||
|
video.wmv
|
Loading…
Reference in New Issue
Block a user