From bad794ab9d441e2ac60e2475ceb69d8490f6565c Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Sun, 3 Sep 2017 17:03:30 +0100 Subject: [PATCH 1/5] Versions bump --- Cargo.lock | 56 +++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 101a285..cbc3e01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,10 +6,10 @@ dependencies = [ "datetime 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "locale 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "natord 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -53,10 +53,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cmake" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -78,7 +78,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "locale 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "gcc" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -105,12 +105,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "git2" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -153,17 +153,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.29" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -173,8 +173,8 @@ name = "libz-sys" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -184,7 +184,7 @@ name = "locale" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -219,7 +219,7 @@ name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -303,7 +303,7 @@ name = "num_cpus" version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -337,7 +337,7 @@ name = "rand" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -382,7 +382,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -392,7 +392,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -436,7 +436,7 @@ name = "users" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -474,21 +474,21 @@ dependencies = [ "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" -"checksum cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ebbb35d3dc9cd09497168f33de1acb79b265d350ab0ac34133b98f8509af1f" +"checksum cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8a6541a55bcd72d3de4faee2d101a5a66df29790282c7f797082a7228a9b3d" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum datetime 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d425bf1f6bbd57cf833081c1e60ac294fd74e7edd66acc91c3fca2e496bcee9" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" -"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" +"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa01936ac96555c083c0e8553f672616274408d9d3fc5b8696603fbf63ff43ee" +"checksum git2 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1c0203d653f4140241da0c1375a404f0a397249ec818cd2076c6280c50f6fa" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11dc464f8c6f17595d191447c9c6559298b2d023d6f846a4a23ac7ea3c46c477" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" -"checksum libgit2-sys 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "0f1641ccb55181967a3e5ee4ae2911c0563492f016383ea67a27886181de088c" +"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" +"checksum libgit2-sys 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c00f6e5bc3fb2b5f87e75e8d0fd4ae6720d55f3ee23d389b7c6cae30f8db8db1" "checksum libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd64ef8ee652185674455c1d450b83cbc8ad895625d543b5324d923f82e4d8" "checksum locale 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fdbe492a9c0238da900a1165c42fc5067161ce292678a6fe80921f30fe307fd" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" From 4507edd734df5d6906001b4cfbf0f05896b70c32 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Sun, 3 Sep 2017 17:05:38 +0100 Subject: [PATCH 2/5] 256 colour support in ls_colors This is more annoying than it should be because it has to work with Styles rather than with strings, which means parsing them, and parsing is always tricky business. --- src/style/lsc.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/style/lsc.rs b/src/style/lsc.rs index 092134f..823be47 100644 --- a/src/style/lsc.rs +++ b/src/style/lsc.rs @@ -1,6 +1,6 @@ use std::ops::FnMut; -use ansi_term::Style; +use ansi_term::{Colour, Style}; use ansi_term::Colour::*; @@ -25,11 +25,30 @@ pub struct Pair<'var> { pub value: &'var str, } +use std::iter::Peekable; +fn parse_into_high_colour<'a, I>(iter: &mut Peekable) -> Option +where I: Iterator { + match iter.peek() { + Some(&"5") => { + let _5 = iter.next(); + if let Some(byte) = iter.next() { + if let Ok(num) = byte.parse() { + return Some(Fixed(num)); + } + } + } + _ => {}, + } + + None +} + impl<'var> Pair<'var> { pub fn to_style(&self) -> Style { let mut style = Style::default(); + let mut iter = self.value.split(";").peekable(); - for num in self.value.split(";") { + while let Some(num) = iter.next() { match num { // Bold and italic @@ -45,6 +64,7 @@ impl<'var> Pair<'var> { "35" => style = style.fg(Purple), "36" => style = style.fg(Cyan), "37" => style = style.fg(White), + "38" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.fg(c) }, // Background colours "40" => style = style.on(Black), @@ -55,6 +75,8 @@ impl<'var> Pair<'var> { "45" => style = style.on(Purple), "46" => style = style.on(Cyan), "47" => style = style.on(White), + "48" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.on(c) }, + _ => {/* ignore the error and do nothing */}, } } @@ -93,6 +115,16 @@ mod ansi_test { test!(semis: ";;;;;;" => Style::default()); test!(nines: "99999999" => Style::default()); test!(word: "GREEN" => Style::default()); + + // Higher colours + test!(hifg: "38;5;149" => Fixed(149).normal()); + test!(hibg: "48;5;1" => Style::default().on(Fixed(1))); + test!(hibo: "48;5;1;1" => Style::default().on(Fixed(1)).bold()); + test!(hiund: "4;48;5;1" => Style::default().on(Fixed(1)).underline()); + + test!(fgbg: "38;5;121;48;5;212" => Fixed(121).on(Fixed(212))); + test!(bgfg: "48;5;121;38;5;212" => Fixed(212).on(Fixed(121))); + test!(toohi: "48;5;999" => Style::default()); } From 28b4b672d48a0714608d50777f469055b4bedb4a Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Sun, 3 Sep 2017 19:50:40 +0100 Subject: [PATCH 3/5] Move FileStyle to the same options file as Colours They are going to be deduced together (from the same environment variable) so it makes sense to put them in the same file first. --- src/options/mod.rs | 4 +- src/options/{colours.rs => style.rs} | 55 +++++++++++++++++++++++----- src/options/view.rs | 32 ++-------------- src/style/colours.rs | 21 +++-------- 4 files changed, 56 insertions(+), 56 deletions(-) rename src/options/{colours.rs => style.rs} (87%) diff --git a/src/options/mod.rs b/src/options/mod.rs index 074416d..97366d7 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -64,7 +64,7 @@ //! if no aliases are being used! //! //! Finally, this isn’t just useful when options could override each other. -//! Creating an alias `exal=”exa --long --inode --header”` then invoking `exal +//! Creating an alias `exal="exa --long --inode --header"` then invoking `exal //! --grid --long` shouldn’t complain about `--long` being given twice when //! it’s clear what the user wants. @@ -75,7 +75,7 @@ use fs::dir_action::DirAction; use fs::filter::FileFilter; use output::{View, Mode, details, grid_details}; -mod colours; +mod style; mod dir_action; mod filter; mod view; diff --git a/src/options/colours.rs b/src/options/style.rs similarity index 87% rename from src/options/colours.rs rename to src/options/style.rs index cbea537..2aede03 100644 --- a/src/options/colours.rs +++ b/src/options/style.rs @@ -1,4 +1,5 @@ use style::Colours; +use output::file_name::{FileStyle, Classify}; use options::{flags, Vars, Misfire}; use options::parser::MatchedFlags; @@ -59,16 +60,30 @@ impl TerminalColours { } -impl Colours { - pub fn deduce(matches: &MatchedFlags, vars: &V, widther: TW) -> Result +pub struct Style { + pub colours: Colours, + pub style: FileStyle, +} + +impl Style { + + #[allow(trivial_casts)] // the "as Box<_>" stuff below warns about this for some reason + pub fn deduce(matches: &MatchedFlags, vars: &V, widther: TW) -> Result where TW: Fn() -> Option, V: Vars { use self::TerminalColours::*; + use info::filetype::FileExtensions; use style::LSColors; use options::vars; + use output::file_name::NoFileColours; + + let classify = Classify::deduce(matches)?; let tc = TerminalColours::deduce(matches)?; if tc == Never || (tc == Automatic && widther().is_none()) { - return Ok(Colours::plain()); + return Ok(Style { + colours: Colours::plain(), + style: FileStyle { classify, exts: Box::new(NoFileColours) }, + }); } let scale = matches.has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?; @@ -76,19 +91,39 @@ impl Colours { if let Some(lsc) = vars.get(vars::LS_COLORS) { let lsc = lsc.to_string_lossy(); - LSColors(lsc.as_ref()).each_pair(|pair| colours.set_ls(&pair)); + LSColors(lsc.as_ref()).each_pair(|pair| { + colours.set_ls(&pair); + }); } 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)); + LSColors(exa.as_ref()).each_pair(|pair| { + colours.set_exa(&pair); + }); } - Ok(colours) + let classify = Classify::deduce(matches)?; + let exts = if colours.colourful { Box::new(FileExtensions) as Box<_> } + else { Box::new(NoFileColours) as Box<_> }; + + let style = FileStyle { classify, exts }; + Ok(Style { colours, style }) } } +impl Classify { + fn deduce(matches: &MatchedFlags) -> Result { + let flagged = matches.has(&flags::CLASSIFY)?; + + Ok(if flagged { Classify::AddFileIndicators } + else { Classify::JustFilenames }) + } +} + + + #[cfg(test)] mod terminal_test { use super::*; @@ -174,7 +209,7 @@ mod colour_test { ($name:ident: $inputs:expr, $widther:expr; $stricts:expr => $result:expr) => { #[test] fn $name() { - for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Colours::deduce(mf, &None, &$widther)) { + for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Style::deduce(mf, &None, &$widther).map(|s| s.colours)) { assert_eq!(result, $result); } } @@ -183,7 +218,7 @@ mod colour_test { ($name:ident: $inputs:expr, $widther:expr; $stricts:expr => err $result:expr) => { #[test] fn $name() { - for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Colours::deduce(mf, &None, &$widther)) { + for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Style::deduce(mf, &None, &$widther).map(|s| s.colours)) { assert_eq!(result.unwrap_err(), $result); } } @@ -192,7 +227,7 @@ mod colour_test { ($name:ident: $inputs:expr, $widther:expr; $stricts:expr => like $pat:pat) => { #[test] fn $name() { - for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Colours::deduce(mf, &None, &$widther)) { + for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| Style::deduce(mf, &None, &$widther).map(|s| s.colours)) { println!("Testing {:?}", result); match result { $pat => assert!(true), @@ -245,7 +280,7 @@ mod customs_test { let vars = MockVars { ls: $ls, exa: $exa }; - for result in parse_for_test(&[], &[], Both, |mf| Colours::deduce(mf, &vars, || Some(80))) { + for result in parse_for_test(&[], &[], Both, |mf| Style::deduce(mf, &vars, || Some(80)).map(|s| s.colours)) { assert_eq!(result.as_ref(), Ok(&c)); } } diff --git a/src/options/view.rs b/src/options/view.rs index 6aa3a6d..8d4520d 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -1,9 +1,6 @@ -use style::Colours; - use output::{View, Mode, grid, details}; use output::grid_details::{self, RowThreshold}; use output::table::{TimeTypes, Environment, SizeFormat, Columns, Options as TableOptions}; -use output::file_name::{Classify, FileStyle, NoFileColours}; use output::time::TimeFormat; use options::{flags, Misfire, Vars}; @@ -16,9 +13,10 @@ impl View { /// Determine which view to use and all of that view’s arguments. pub fn deduce(matches: &MatchedFlags, vars: &V) -> Result { + use options::style::Style; + let mode = Mode::deduce(matches, vars)?; - let colours = Colours::deduce(matches, vars, || *TERM_WIDTH)?; - let style = FileStyle::deduce(matches, &colours)?; + let Style { colours, style } = Style::deduce(matches, vars, || *TERM_WIDTH)?; Ok(View { mode, colours, style }) } } @@ -335,30 +333,6 @@ impl TimeTypes { } -impl FileStyle { - - #[allow(trivial_casts)] - fn deduce(matches: &MatchedFlags, colours: &Colours) -> Result { - use info::filetype::FileExtensions; - - let classify = Classify::deduce(matches)?; - let exts = if colours.colourful { Box::new(FileExtensions) as Box<_> } - else { Box::new(NoFileColours) as Box<_> }; - - Ok(FileStyle { classify, exts }) - } -} - -impl Classify { - fn deduce(matches: &MatchedFlags) -> Result { - let flagged = matches.has(&flags::CLASSIFY)?; - - Ok(if flagged { Classify::AddFileIndicators } - else { Classify::JustFilenames }) - } -} - - // Gets, then caches, the width of the terminal that exa is running in. // This gets used multiple times above, with no real guarantee of order, // so it’s easier to just cache it the first time it runs. diff --git a/src/style/colours.rs b/src/style/colours.rs index 25fc15a..fefd692 100644 --- a/src/style/colours.rs +++ b/src/style/colours.rs @@ -195,7 +195,7 @@ impl Colours { impl Colours { - pub fn set_ls(&mut self, pair: &Pair) { + pub fn set_ls(&mut self, pair: &Pair) -> bool { match pair.key { "di" => self.filekinds.directory = pair.to_style(), "ex" => self.filekinds.executable = pair.to_style(), @@ -207,23 +207,13 @@ impl Colours { "ln" => self.filekinds.symlink = pair.to_style(), "or" => self.broken_arrow = pair.to_style(), "mi" => self.broken_filename = pair.to_style(), - _ => {/* don’t change anything */}, + _ => return false, } + true } - pub fn set_exa(&mut self, pair: &Pair) { + pub fn set_exa(&mut self, pair: &Pair) -> bool { match pair.key { - "di" => self.filekinds.directory = pair.to_style(), - "ex" => self.filekinds.executable = pair.to_style(), - "fi" => self.filekinds.normal = pair.to_style(), - "pi" => self.filekinds.pipe = pair.to_style(), - "so" => self.filekinds.socket = pair.to_style(), - "bd" => self.filekinds.block_device = pair.to_style(), - "cd" => self.filekinds.char_device = pair.to_style(), - "ln" => self.filekinds.symlink = pair.to_style(), - "or" => self.broken_arrow = pair.to_style(), - "mi" => self.broken_filename = pair.to_style(), - "ur" => self.perms.user_read = pair.to_style(), "uw" => self.perms.user_write = pair.to_style(), "ux" => self.perms.user_execute_file = pair.to_style(), @@ -265,8 +255,9 @@ impl Colours { "lp" => self.symlink_path = pair.to_style(), "cc" => self.control_char = pair.to_style(), - _ => {/* still don’t change anything */}, + _ => return false, } + true } } From b86074d63b183eda8f5cd26d339864bac4328084 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Wed, 13 Sep 2017 08:44:59 +0100 Subject: [PATCH 4/5] Rename Style to Styles to avoid a name clash --- src/options/style.rs | 20 +++++++++++++++----- src/options/view.rs | 4 ++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/options/style.rs b/src/options/style.rs index 2aede03..061fef2 100644 --- a/src/options/style.rs +++ b/src/options/style.rs @@ -60,12 +60,22 @@ impl TerminalColours { } -pub struct Style { +/// **Styles**, which is already an overloaded term, is a pair of view option +/// sets that happen to both be affected by `LS_COLORS` and `EXA_COLORS`. +/// Because it’s better to only iterate through that once, the two are deduced +/// together. +pub struct Styles { + + /// The colours to paint user interface elements, like the date column, + /// and file kinds, such as directories. pub colours: Colours, + + /// The colours to paint the names of files that match glob patterns + /// (and the classify option). pub style: FileStyle, } -impl Style { +impl Styles { #[allow(trivial_casts)] // the "as Box<_>" stuff below warns about this for some reason pub fn deduce(matches: &MatchedFlags, vars: &V, widther: TW) -> Result @@ -80,7 +90,7 @@ impl Style { let tc = TerminalColours::deduce(matches)?; if tc == Never || (tc == Automatic && widther().is_none()) { - return Ok(Style { + return Ok(Styles { colours: Colours::plain(), style: FileStyle { classify, exts: Box::new(NoFileColours) }, }); @@ -101,14 +111,14 @@ impl Style { LSColors(exa.as_ref()).each_pair(|pair| { colours.set_exa(&pair); }); + let style = FileStyle { classify, exts }; + 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<_> }; - let style = FileStyle { classify, exts }; - Ok(Style { colours, style }) } } diff --git a/src/options/view.rs b/src/options/view.rs index 8d4520d..deff114 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -13,10 +13,10 @@ impl View { /// Determine which view to use and all of that view’s arguments. pub fn deduce(matches: &MatchedFlags, vars: &V) -> Result { - use options::style::Style; + use options::style::Styles; let mode = Mode::deduce(matches, vars)?; - let Style { colours, style } = Style::deduce(matches, vars, || *TERM_WIDTH)?; + let Styles { colours, style } = Styles::deduce(matches, vars, || *TERM_WIDTH)?; Ok(View { mode, colours, style }) } } From dc45332d7b2ed839f11da00c244dbed198e547c1 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Wed, 13 Sep 2017 08:51:57 +0100 Subject: [PATCH 5/5] Implement file name colouring in {exa,ls}_colors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/options/style.rs | 282 ++++++++++++++++++++++++++++++------ src/output/file_name.rs | 10 ++ xtests/run.sh | 55 ++++--- xtests/themed_compresseds | 5 + xtests/themed_compresseds_r | 5 + xtests/themed_links | 3 + xtests/themed_long | 22 +++ xtests/themed_specials | 3 + xtests/themed_un | 26 ++++ 9 files changed, 351 insertions(+), 60 deletions(-) create mode 100644 xtests/themed_compresseds create mode 100644 xtests/themed_compresseds_r create mode 100644 xtests/themed_links create mode 100644 xtests/themed_long create mode 100644 xtests/themed_specials create mode 100644 xtests/themed_un diff --git a/src/options/style.rs b/src/options/style.rs index 061fef2..78970f0 100644 --- a/src/options/style.rs +++ b/src/options/style.rs @@ -1,9 +1,11 @@ -use style::Colours; -use output::file_name::{FileStyle, Classify}; +use ansi_term::Style; +use glob; +use fs::File; use options::{flags, Vars, Misfire}; use options::parser::MatchedFlags; - +use output::file_name::{FileStyle, Classify}; +use style::Colours; /// Under what circumstances we should display coloured, rather than plain, @@ -82,12 +84,12 @@ impl Styles { where TW: Fn() -> Option, V: Vars { use self::TerminalColours::*; use info::filetype::FileExtensions; - use style::LSColors; - use options::vars; use output::file_name::NoFileColours; 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)?; if tc == Never || (tc == Automatic && widther().is_none()) { 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 mut colours = Colours::colourful(scale.is_some()); - if let Some(lsc) = vars.get(vars::LS_COLORS) { - let lsc = lsc.to_string_lossy(); - LSColors(lsc.as_ref()).each_pair(|pair| { - colours.set_ls(&pair); - }); - } + let (exts, use_default_filetypes) = parse_color_vars(vars, &mut colours); + + // 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(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 }; 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(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