Merge branch 'common-view-fields'

This commit is contained in:
Benjamin Sago 2017-06-26 23:03:29 +01:00
commit c7f18873fd
20 changed files with 437 additions and 348 deletions

77
Cargo.lock generated
View File

@ -7,10 +7,11 @@ dependencies = [
"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)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.23 (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.24 (registry+https://github.com/rust-lang/crates.io-index)",
"locale 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"natord 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"term_grid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -39,7 +40,7 @@ name = "cmake"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -48,7 +49,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.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (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.39 (registry+https://github.com/rust-lang/crates.io-index)",
"pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -56,7 +57,7 @@ dependencies = [
[[package]]
name = "gcc"
version = "0.3.50"
version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -70,9 +71,9 @@ version = "0.6.6"
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.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
"libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -87,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -98,9 +99,14 @@ dependencies = [
"nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.23"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -109,20 +115,21 @@ version = "0.6.12"
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.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (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.24 (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)",
]
[[package]]
name = "libz-sys"
version = "1.0.13"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.23 (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.24 (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)",
]
[[package]]
@ -130,7 +137,7 @@ name = "locale"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -216,10 +223,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "1.5.1"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -238,6 +245,11 @@ dependencies = [
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "percent-encoding"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pkg-config"
version = "0.3.9"
@ -248,7 +260,7 @@ name = "rand"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -279,7 +291,7 @@ dependencies = [
[[package]]
name = "unicode-normalization"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -289,11 +301,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "url"
version = "1.4.1"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -301,9 +314,14 @@ name = "users"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vcpkg"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "zoneinfo_compiled"
version = "0.2.1"
@ -319,15 +337,16 @@ dependencies = [
"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 datetime 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d425bf1f6bbd57cf833081c1e60ac294fd74e7edd66acc91c3fca2e496bcee9"
"checksum gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)" = "5f837c392f2ea61cb1576eac188653df828c861b7137d74ea4a5caa89621f9e6"
"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a"
"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 glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37"
"checksum iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11dc464f8c6f17595d191447c9c6559298b2d023d6f846a4a23ac7ea3c46c477"
"checksum libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e7eb6b826bfc1fdea7935d46556250d1799b7fe2d9f7951071f4291710665e3e"
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc"
"checksum libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "df18a822100352d9863b302faf6f8f25c0e77f0e60feb40e5dbe1238b7f13b1d"
"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c"
"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 matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum natord 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
@ -339,17 +358,19 @@ dependencies = [
"checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e"
"checksum num-rational 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "33c881e104a26e1accc09449374c095ff2312c8e0c27fab7bbefe16eac7c776d"
"checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6"
"checksum num_cpus 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e416ba127a4bb3ff398cb19546a8d0414f73352efe2857f4060d36f5fe5983a"
"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584"
"checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902"
"checksum pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d1bf3336e626b898e7263790d432a711d4277e22faea20dd9f70e0cab268fa58"
"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
"checksum term_grid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc202875496cf72a683a1ecd66f0742a830e73c202bdbd21867d73dfaac8343"
"checksum unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a"
"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2ba3456fbe5c0098cb877cf08b92b76c3e18e0be9e47c35b487220d377d24e"
"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
"checksum users 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7ae8fdf783cb9652109c99886459648feb92ecc749e6b8e7930f6decba74c7c"
"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
"checksum zoneinfo_compiled 0.2.1 (git+https://github.com/rust-datetime/zoneinfo-compiled.git)" = "<none>"

View File

@ -16,6 +16,7 @@ ansi_term = "0.8.0"
datetime = "0.4.3"
getopts = "0.2.14"
glob = "0.2"
lazy_static = "0.2"
libc = "0.2.9"
locale = "0.2.1"
natord = "1.0.7"

View File

@ -18,6 +18,10 @@ extern crate zoneinfo_compiled;
#[cfg(feature="git")] extern crate git2;
#[macro_use]
extern crate lazy_static;
use std::ffi::OsStr;
use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, Path};
@ -25,9 +29,9 @@ use std::path::{Component, Path};
use ansi_term::{ANSIStrings, Style};
use fs::{Dir, File};
use options::{Options, View};
use options::{Options, View, Mode};
pub use options::Misfire;
use output::escape;
use output::{escape, lines, grid, grid_details, details};
mod fs;
mod info;
@ -164,11 +168,13 @@ impl<'w, W: Write + 'w> Exa<'w, W> {
/// printing differently...
fn print_files(&mut self, dir: Option<&Dir>, files: Vec<File>) -> IOResult<()> {
if !files.is_empty() {
match self.options.view {
View::Grid(ref g) => g.view(&files, self.writer),
View::Details(ref d) => d.view(dir, files, self.writer),
View::GridDetails(ref gd) => gd.view(dir, files, self.writer),
View::Lines(ref l) => l.view(files, self.writer),
let View { ref mode, ref colours, classify } = self.options.view;
match *mode {
Mode::Lines => lines::Render { files, colours, classify }.render(self.writer),
Mode::Grid(ref opts) => grid::Render { files, colours, classify, opts }.render(self.writer),
Mode::Details(ref opts) => details::Render { dir, files, colours, classify, opts, filter: &self.options.filter, recurse: self.options.dir_action.recurse_options() }.render(self.writer),
Mode::GridDetails(ref grid, ref details) => grid_details::Render { dir, files, colours, classify, grid, details }.render(self.writer),
}
}
else {

View File

@ -3,7 +3,7 @@ use std::ffi::OsStr;
use getopts;
use fs::feature::xattr;
use output::{Details, GridDetails};
use output::details;
mod dir_action;
pub use self::dir_action::{DirAction, RecurseOptions};
@ -18,7 +18,7 @@ mod misfire;
pub use self::misfire::Misfire;
mod view;
pub use self::view::View;
pub use self::view::{View, Mode};
/// These **options** represent a parsed, error-checked versions of the
@ -123,9 +123,9 @@ impl Options {
/// status column. Its only worth trying to discover a repository if the
/// results will end up being displayed.
pub fn should_scan_for_git(&self) -> bool {
match self.view {
View::Details(Details { columns: Some(cols), .. }) |
View::GridDetails(GridDetails { details: Details { columns: Some(cols), .. }, .. }) => cols.should_scan_for_git(),
match self.view.mode {
Mode::Details(details::Options { columns: Some(cols), .. }) |
Mode::GridDetails(_, details::Options { columns: Some(cols), .. }) => cols.should_scan_for_git(),
_ => false,
}
}
@ -135,7 +135,7 @@ impl Options {
fn deduce(matches: &getopts::Matches) -> Result<Options, Misfire> {
let dir_action = DirAction::deduce(matches)?;
let filter = FileFilter::deduce(matches)?;
let view = View::deduce(matches, filter.clone(), dir_action)?;
let view = View::deduce(matches)?;
Ok(Options { dir_action, view, filter })
}

View File

@ -3,32 +3,47 @@ use std::env::var_os;
use getopts;
use output::Colours;
use output::{Grid, Details, GridDetails, Lines};
use output::{grid, details};
use output::column::{Columns, TimeTypes, SizeFormat};
use output::file_name::Classify;
use options::{FileFilter, DirAction, Misfire};
use term::dimensions;
use options::Misfire;
use fs::feature::xattr;
/// The **view** contains all information about how to format output.
#[derive(PartialEq, Debug, Clone)]
pub enum View {
Details(Details),
Grid(Grid),
GridDetails(GridDetails),
Lines(Lines),
pub struct View {
pub mode: Mode,
pub colours: Colours,
pub classify: Classify,
}
impl View {
/// Determine which view to use and all of that views arguments.
pub fn deduce(matches: &getopts::Matches, filter: FileFilter, dir_action: DirAction) -> Result<View, Misfire> {
use options::misfire::Misfire::*;
pub fn deduce(matches: &getopts::Matches) -> Result<View, Misfire> {
let mode = Mode::deduce(matches)?;
let colours = Colours::deduce(matches)?;
let classify = Classify::deduce(matches);
Ok(View { mode, colours, classify })
}
}
let colour_scale = || {
matches.opt_present("color-scale") || matches.opt_present("colour-scale")
};
/// The **mode** is the “type” of output.
#[derive(PartialEq, Debug, Clone)]
pub enum Mode {
Grid(grid::Options),
Details(details::Options),
GridDetails(grid::Options, details::Options),
Lines,
}
impl Mode {
/// Determine the mode from the command-line arguments.
pub fn deduce(matches: &getopts::Matches) -> Result<Mode, Misfire> {
use options::misfire::Misfire::*;
let long = || {
if matches.opt_present("across") && !matches.opt_present("grid") {
@ -38,31 +53,11 @@ impl View {
Err(Useless("oneline", true, "long"))
}
else {
let term_colours = TerminalColours::deduce(matches)?;
let colours = match term_colours {
TerminalColours::Always => Colours::colourful(colour_scale()),
TerminalColours::Never => Colours::plain(),
TerminalColours::Automatic => {
if dimensions().is_some() {
Colours::colourful(colour_scale())
}
else {
Colours::plain()
}
},
};
let details = Details {
Ok(details::Options {
columns: Some(Columns::deduce(matches)?),
header: matches.opt_present("header"),
recurse: dir_action.recurse_options(),
filter: filter.clone(),
xattr: xattr::ENABLED && matches.opt_present("extended"),
colours: colours,
classify: Classify::deduce(matches),
};
Ok(details)
})
}
};
@ -88,47 +83,31 @@ impl View {
};
let other_options_scan = || {
let classify = Classify::deduce(matches);
let term_colours = TerminalColours::deduce(matches)?;
let term_width = TerminalWidth::deduce()?;
if let Some(&width) = term_width.as_ref() {
let colours = match term_colours {
TerminalColours::Always |
TerminalColours::Automatic => Colours::colourful(colour_scale()),
TerminalColours::Never => Colours::plain(),
};
if let Some(width) = TerminalWidth::deduce()?.width() {
if matches.opt_present("oneline") {
if matches.opt_present("across") {
Err(Useless("across", true, "oneline"))
}
else {
Ok(View::Lines(Lines { colours, classify }))
Ok(Mode::Lines)
}
}
else if matches.opt_present("tree") {
let details = Details {
let details = details::Options {
columns: None,
header: false,
recurse: dir_action.recurse_options(),
filter: filter.clone(), // TODO: clone
xattr: false,
colours: colours,
classify: classify,
};
Ok(View::Details(details))
Ok(Mode::Details(details))
}
else {
let grid = Grid {
let grid = grid::Options {
across: matches.opt_present("across"),
console_width: width,
colours: colours,
classify: classify,
};
Ok(View::Grid(grid))
Ok(Mode::Grid(grid))
}
}
else {
@ -136,42 +115,31 @@ impl View {
// as the programs stdout being connected to a file, then
// fallback to the lines view.
let colours = match term_colours {
TerminalColours::Always => Colours::colourful(colour_scale()),
TerminalColours::Never | TerminalColours::Automatic => Colours::plain(),
};
if matches.opt_present("tree") {
let details = Details {
let details = details::Options {
columns: None,
header: false,
recurse: dir_action.recurse_options(),
filter: filter.clone(),
xattr: false,
colours: colours,
classify: classify,
};
Ok(View::Details(details))
Ok(Mode::Details(details))
}
else {
Ok(View::Lines(Lines { colours, classify }))
Ok(Mode::Lines)
}
}
};
if matches.opt_present("long") {
let details = long()?;
if matches.opt_present("grid") {
match other_options_scan() {
Ok(View::Grid(grid)) => return Ok(View::GridDetails(GridDetails { grid, details })),
Ok(lines) => return Ok(lines),
Err(e) => return Err(e),
match other_options_scan()? {
Mode::Grid(grid) => return Ok(Mode::GridDetails(grid, details)),
others => return Ok(others),
};
}
else {
return Ok(View::Details(details));
return Ok(Mode::Details(details));
}
}
@ -208,7 +176,7 @@ impl TerminalWidth {
Err(e) => Err(Misfire::FailedParse(e)),
}
}
else if let Some((width, _)) = dimensions() {
else if let Some(width) = *TERM_WIDTH {
Ok(TerminalWidth::Terminal(width))
}
else {
@ -216,11 +184,11 @@ impl TerminalWidth {
}
}
fn as_ref(&self) -> Option<&usize> {
fn width(&self) -> Option<usize> {
match *self {
TerminalWidth::Set(ref width)
| TerminalWidth::Terminal(ref width) => Some(width),
TerminalWidth::Unset => None,
TerminalWidth::Set(width) |
TerminalWidth::Terminal(width) => Some(width),
TerminalWidth::Unset => None,
}
}
}
@ -359,6 +327,22 @@ impl TerminalColours {
}
impl Colours {
fn deduce(matches: &getopts::Matches) -> Result<Colours, Misfire> {
use self::TerminalColours::*;
let tc = TerminalColours::deduce(matches)?;
if tc == Always || (tc == Automatic && TERM_WIDTH.is_some()) {
let scale = matches.opt_present("color-scale") || matches.opt_present("colour-scale");
Ok(Colours::colourful(scale))
}
else {
Ok(Colours::plain())
}
}
}
impl Classify {
fn deduce(matches: &getopts::Matches) -> Classify {
@ -366,3 +350,14 @@ impl Classify {
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 its easier to just cache it the first time it runs.
lazy_static! {
static ref TERM_WIDTH: Option<usize> = {
use term::dimensions;
dimensions().map(|t| t.0)
};
}

View File

@ -113,33 +113,18 @@ use output::file_name::{FileName, LinkStyle, Classify};
/// Almost all the heavy lifting is done in a Table object, which handles the
/// columns for each row.
#[derive(PartialEq, Debug, Clone, Default)]
pub struct Details {
pub struct Options {
/// A Columns object that says which columns should be included in the
/// output in the general case. Directories themselves can pick which
/// columns are *added* to this list, such as the Git column.
pub columns: Option<Columns>,
/// Whether to recurse through directories with a tree view, and if so,
/// which options to use. This field is only relevant here if the `tree`
/// field of the RecurseOptions is `true`.
pub recurse: Option<RecurseOptions>,
/// How to sort and filter the files after getting their details.
pub filter: FileFilter,
/// Whether to show a header line or not.
pub header: bool,
/// Whether to show each file's extended attributes.
pub xattr: bool,
/// The colours to use to display information in the table, including the
/// colour of the tree view symbols.
pub colours: Colours,
/// Whether to show a file type indiccator.
pub classify: Classify,
}
/// The **environment** struct contains any data that could change between
@ -224,16 +209,30 @@ fn determine_time_zone() -> TZResult<TimeZone> {
TimeZone::from_file("/etc/localtime")
}
impl Details {
/// Print the details of the given vector of files -- all of which will
/// have been read from the given directory, if present -- to stdout.
pub fn view<W: Write>(&self, dir: Option<&Dir>, files: Vec<File>, w: &mut W) -> IOResult<()> {
pub struct Render<'a> {
pub dir: Option<&'a Dir>,
pub files: Vec<File<'a>>,
pub colours: &'a Colours,
pub classify: Classify,
pub opts: &'a Options,
/// Whether to recurse through directories with a tree view, and if so,
/// which options to use. This field is only relevant here if the `tree`
/// field of the RecurseOptions is `true`.
pub recurse: Option<RecurseOptions>,
/// How to sort and filter the files after getting their details.
pub filter: &'a FileFilter,
}
impl<'a> Render<'a> {
pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
// First, transform the Columns object into a vector of columns for
// the current directory.
let columns_for_dir = match self.columns {
Some(cols) => cols.for_dir(dir),
let columns_for_dir = match self.opts.columns {
Some(cols) => cols.for_dir(self.dir),
None => Vec::new(),
};
@ -243,16 +242,18 @@ impl Details {
// Build the table to put rows in.
let mut table = Table {
columns: &*columns_for_dir,
opts: self,
colours: self.colours,
classify: self.classify,
xattr: self.opts.xattr,
env: env,
rows: Vec::new(),
};
// Next, add a header if the user requests it.
if self.header { table.add_header() }
if self.opts.header { table.add_header() }
// Then add files to the table and print it out.
self.add_files_to_table(&mut table, files, 0);
self.add_files_to_table(&mut table, &self.files, 0);
for cell in table.print_table() {
writeln!(w, "{}", cell.strings())?;
}
@ -262,7 +263,7 @@ impl Details {
/// Adds files to the table, possibly recursively. This is easily
/// parallelisable, and uses a pool of threads.
fn add_files_to_table<'dir, U: Users+Groups+Send>(&self, mut table: &mut Table<U>, src: Vec<File<'dir>>, depth: usize) {
fn add_files_to_table<'dir, U: Users+Groups+Send>(&self, mut table: &mut Table<U>, src: &Vec<File<'dir>>, depth: usize) {
use num_cpus;
use scoped_threadpool::Pool;
use std::sync::{Arc, Mutex};
@ -276,12 +277,12 @@ impl Details {
xattrs: Vec<Attribute>,
errors: Vec<(IOError, Option<PathBuf>)>,
dir: Option<Dir>,
file: File<'a>,
file: &'a File<'a>,
}
impl<'a> AsRef<File<'a>> for Egg<'a> {
fn as_ref(&self) -> &File<'a> {
&self.file
self.file
}
}
@ -306,7 +307,7 @@ impl Details {
let cells = table.cells_for_file(&file, !xattrs.is_empty());
if !table.opts.xattr {
if !table.xattr {
xattrs.clear();
}
@ -336,7 +337,7 @@ impl Details {
let row = Row {
depth: depth,
cells: Some(egg.cells),
name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, self.classify, &self.colours).paint().promote(),
name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, table.classify, table.colours).paint().promote(),
last: index == num_eggs - 1,
};
@ -361,7 +362,7 @@ impl Details {
table.add_error(&error, depth + 1, false, path);
}
self.add_files_to_table(table, files, depth + 1);
self.add_files_to_table(table, &files, depth + 1);
continue;
}
}
@ -420,9 +421,10 @@ impl Row {
/// directories.
pub struct Table<'a, U: 'a> { // where U: Users+Groups
pub rows: Vec<Row>,
pub columns: &'a [Column],
pub opts: &'a Details,
pub colours: &'a Colours,
pub xattr: bool,
pub classify: Classify,
pub env: Arc<Environment<U>>,
}
@ -434,8 +436,8 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
pub fn add_header(&mut self) {
let row = Row {
depth: 0,
cells: Some(self.columns.iter().map(|c| TextCell::paint_str(self.opts.colours.header, c.header())).collect()),
name: TextCell::paint_str(self.opts.colours.header, "Name"),
cells: Some(self.columns.iter().map(|c| TextCell::paint_str(self.colours.header, c.header())).collect()),
name: TextCell::paint_str(self.colours.header, "Name"),
last: false,
};
@ -451,7 +453,7 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
let row = Row {
depth: depth,
cells: None,
name: TextCell::paint(self.opts.colours.broken_arrow, error_message),
name: TextCell::paint(self.colours.broken_arrow, error_message),
last: last,
};
@ -462,15 +464,15 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
let row = Row {
depth: depth,
cells: None,
name: TextCell::paint(self.opts.colours.perms.attribute, format!("{} (len {})", xattr.name, xattr.size)),
name: TextCell::paint(self.colours.perms.attribute, format!("{} (len {})", xattr.name, xattr.size)),
last: last,
};
self.rows.push(row);
}
pub fn filename(&self, file: File, links: LinkStyle) -> TextCellContents {
FileName::new(&file, links, self.opts.classify, &self.opts.colours).paint()
pub fn filename(&self, file: &File, links: LinkStyle) -> TextCellContents {
FileName::new(file, links, self.classify, &self.colours).paint()
}
pub fn add_file_with_cells(&mut self, cells: Vec<TextCell>, name_cell: TextCell, depth: usize, last: bool) {
@ -504,17 +506,17 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
use output::column::TimeType::*;
match *column {
Column::Permissions => self.permissions_plus(file, xattrs).render(&self.opts.colours),
Column::FileSize(fmt) => file.size().render(&self.opts.colours, fmt, &self.env.numeric),
Column::Timestamp(Modified) => file.modified_time().render(&self.opts.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::Timestamp(Created) => file.created_time().render( &self.opts.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::Timestamp(Accessed) => file.accessed_time().render(&self.opts.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::HardLinks => file.links().render(&self.opts.colours, &self.env.numeric),
Column::Inode => file.inode().render(&self.opts.colours),
Column::Blocks => file.blocks().render(&self.opts.colours),
Column::User => file.user().render(&self.opts.colours, &*self.env.lock_users()),
Column::Group => file.group().render(&self.opts.colours, &*self.env.lock_users()),
Column::GitStatus => file.git_status().render(&self.opts.colours),
Column::Permissions => self.permissions_plus(file, xattrs).render(&self.colours),
Column::FileSize(fmt) => file.size().render(&self.colours, fmt, &self.env.numeric),
Column::Timestamp(Modified) => file.modified_time().render(&self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::Timestamp(Created) => file.created_time().render( &self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::Timestamp(Accessed) => file.accessed_time().render(&self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
Column::HardLinks => file.links().render(&self.colours, &self.env.numeric),
Column::Inode => file.inode().render(&self.colours),
Column::Blocks => file.blocks().render(&self.colours),
Column::User => file.user().render(&self.colours, &*self.env.lock_users()),
Column::Group => file.group().render(&self.colours, &*self.env.lock_users()),
Column::GitStatus => file.git_status().render(&self.colours),
}
}
@ -554,7 +556,7 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
let mut filename = TextCell::default();
for tree_part in tree_trunk.new_row(row.depth, row.last) {
filename.push(self.opts.colours.punctuation.paint(tree_part.ascii_art()), 4);
filename.push(self.colours.punctuation.paint(tree_part.ascii_art()), 4);
}
// If any tree characters have been printed, then add an extra

View File

@ -1,6 +1,6 @@
use std::io::{Write, Result as IOResult};
use term_grid as grid;
use term_grid as tg;
use fs::File;
use output::colours::Colours;
@ -8,42 +8,52 @@ use output::file_name::{FileName, LinkStyle, Classify};
#[derive(PartialEq, Debug, Copy, Clone)]
pub struct Grid {
pub struct Options {
pub across: bool,
pub console_width: usize,
pub colours: Colours,
pub classify: Classify,
}
impl Grid {
pub fn view<W: Write>(&self, files: &[File], w: &mut W) -> IOResult<()> {
let direction = if self.across { grid::Direction::LeftToRight }
else { grid::Direction::TopToBottom };
impl Options {
pub fn direction(&self) -> tg::Direction {
if self.across { tg::Direction::LeftToRight }
else { tg::Direction::TopToBottom }
}
}
let mut grid = grid::Grid::new(grid::GridOptions {
direction: direction,
filling: grid::Filling::Spaces(2),
pub struct Render<'a> {
pub files: Vec<File<'a>>,
pub colours: &'a Colours,
pub classify: Classify,
pub opts: &'a Options,
}
impl<'a> Render<'a> {
pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
let mut grid = tg::Grid::new(tg::GridOptions {
direction: self.opts.direction(),
filling: tg::Filling::Spaces(2),
});
grid.reserve(files.len());
grid.reserve(self.files.len());
for file in files.iter() {
let filename = FileName::new(file, LinkStyle::JustFilenames, self.classify, &self.colours).paint();
for file in self.files.iter() {
let filename = FileName::new(file, LinkStyle::JustFilenames, self.classify, self.colours).paint();
let width = filename.width();
grid.add(grid::Cell {
grid.add(tg::Cell {
contents: filename.strings().to_string(),
width: *width,
});
}
if let Some(display) = grid.fit_into_width(self.console_width) {
if let Some(display) = grid.fit_into_width(self.opts.console_width) {
write!(w, "{}", display)
}
else {
// File names too long for a grid - drop down to just listing them!
for file in files.iter() {
let name_cell = FileName::new(file, LinkStyle::JustFilenames, self.classify, &self.colours).paint();
for file in self.files.iter() {
let name_cell = FileName::new(file, LinkStyle::JustFilenames, self.classify, self.colours).paint();
writeln!(w, "{}", name_cell.strings())?;
}
Ok(())

View File

@ -10,29 +10,26 @@ use fs::feature::xattr::FileAttributes;
use output::cell::TextCell;
use output::column::Column;
use output::details::{Details, Table, Environment};
use output::grid::Grid;
use output::file_name::LinkStyle;
use output::colours::Colours;
use output::details::{Table, Environment, Options as DetailsOptions};
use output::grid::Options as GridOptions;
use output::file_name::{Classify, LinkStyle};
#[derive(PartialEq, Debug, Clone)]
pub struct GridDetails {
pub grid: Grid,
pub details: Details,
pub struct Render<'a> {
pub dir: Option<&'a Dir>,
pub files: Vec<File<'a>>,
pub colours: &'a Colours,
pub classify: Classify,
pub grid: &'a GridOptions,
pub details: &'a DetailsOptions,
}
fn file_has_xattrs(file: &File) -> bool {
match file.path.attributes() {
Ok(attrs) => !attrs.is_empty(),
Err(_) => false,
}
}
impl<'a> Render<'a> {
pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
impl GridDetails {
pub fn view<W>(&self, dir: Option<&Dir>, files: Vec<File>, w: &mut W) -> IOResult<()>
where W: Write {
let columns_for_dir = match self.details.columns {
Some(cols) => cols.for_dir(dir),
Some(cols) => cols.for_dir(self.dir),
None => Vec::new(),
};
@ -40,23 +37,23 @@ impl GridDetails {
let (cells, file_names) = {
let first_table = self.make_table(env.clone(), &*columns_for_dir);
let first_table = self.make_table(env.clone(), &*columns_for_dir, self.colours, self.classify);
let cells = files.iter()
let cells = self.files.iter()
.map(|file| first_table.cells_for_file(file, file_has_xattrs(file)))
.collect::<Vec<_>>();
let file_names = files.into_iter()
let file_names = self.files.iter()
.map(|file| first_table.filename(file, LinkStyle::JustFilenames).promote())
.collect::<Vec<_>>();
(cells, file_names)
};
let mut last_working_table = self.make_grid(env.clone(), 1, &columns_for_dir, &file_names, cells.clone());
let mut last_working_table = self.make_grid(env.clone(), 1, &columns_for_dir, &file_names, cells.clone(), self.colours, self.classify);
for column_count in 2.. {
let grid = self.make_grid(env.clone(), column_count, &columns_for_dir, &file_names, cells.clone());
let grid = self.make_grid(env.clone(), column_count, &columns_for_dir, &file_names, cells.clone(), self.colours, self.classify);
let the_grid_fits = {
let d = grid.fit_into_columns(column_count);
@ -74,12 +71,11 @@ impl GridDetails {
Ok(())
}
fn make_table<'a>(&'a self, env: Arc<Environment<UsersCache>>, columns_for_dir: &'a [Column]) -> Table<UsersCache> {
fn make_table<'g>(&'g self, env: Arc<Environment<UsersCache>>, columns_for_dir: &'g [Column], colours: &'g Colours, classify: Classify) -> Table<UsersCache> {
let mut table = Table {
columns: columns_for_dir,
opts: &self.details,
env: env,
colours, classify, env,
xattr: self.details.xattr,
rows: Vec::new(),
};
@ -87,10 +83,10 @@ impl GridDetails {
table
}
fn make_grid<'a>(&'a self, env: Arc<Environment<UsersCache>>, column_count: usize, columns_for_dir: &'a [Column], file_names: &[TextCell], cells: Vec<Vec<TextCell>>) -> grid::Grid {
fn make_grid<'g>(&'g self, env: Arc<Environment<UsersCache>>, column_count: usize, columns_for_dir: &'g [Column], file_names: &[TextCell], cells: Vec<Vec<TextCell>>, colours: &'g Colours, classify: Classify) -> grid::Grid {
let mut tables = Vec::new();
for _ in 0 .. column_count {
tables.push(self.make_table(env.clone(), columns_for_dir));
tables.push(self.make_table(env.clone(), columns_for_dir, colours, classify));
}
let mut num_cells = cells.len();
@ -159,3 +155,11 @@ fn divide_rounding_up(a: usize, b: usize) -> usize {
if a % b != 0 { result += 1; }
result
}
fn file_has_xattrs(file: &File) -> bool {
match file.path.attributes() {
Ok(attrs) => !attrs.is_empty(),
Err(_) => false,
}
}

View File

@ -8,19 +8,24 @@ use output::file_name::{FileName, LinkStyle, Classify};
use super::colours::Colours;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Lines {
pub colours: Colours,
/// The lines view literally just displays each file, line-by-line.
pub struct Render<'a> {
pub files: Vec<File<'a>>,
pub colours: &'a Colours,
pub classify: Classify,
}
/// The lines view literally just displays each file, line-by-line.
impl Lines {
pub fn view<W: Write>(&self, files: Vec<File>, w: &mut W) -> IOResult<()> {
for file in files {
let name_cell = FileName::new(&file, LinkStyle::FullLinkPaths, self.classify, &self.colours).paint();
impl<'a> Render<'a> {
pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
for file in &self.files {
let name_cell = self.render_file(file).paint();
writeln!(w, "{}", ANSIStrings(&name_cell))?;
}
Ok(())
}
fn render_file<'f>(&self, file: &'f File<'a>) -> FileName<'f, 'a> {
FileName::new(file, LinkStyle::FullLinkPaths, self.classify, self.colours)
}
}

View File

@ -1,19 +1,16 @@
pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
pub use self::colours::Colours;
pub use self::details::Details;
pub use self::grid_details::GridDetails;
pub use self::grid::Grid;
pub use self::lines::Lines;
pub use self::escape::escape;
mod grid;
pub mod details;
mod lines;
mod grid_details;
pub mod column;
pub mod details;
pub mod file_name;
pub mod grid_details;
pub mod grid;
pub mod lines;
mod cell;
mod colours;
mod tree;
pub mod file_name;
mod escape;
mod render;
mod tree;

View File

@ -15,7 +15,7 @@ impl f::Blocks {
#[cfg(test)]
pub mod test {
use output::details::Details;
use output::colours::Colours;
use output::cell::TextCell;
use fs::fields as f;
@ -24,21 +24,21 @@ pub mod test {
#[test]
fn blocklessness() {
let mut details = Details::default();
details.colours.punctuation = Green.italic();
let mut colours = Colours::default();
colours.punctuation = Green.italic();
let blox = f::Blocks::None;
let expected = TextCell::blank(Green.italic());
assert_eq!(expected, blox.render(&details.colours).into());
assert_eq!(expected, blox.render(&colours).into());
}
#[test]
fn blockfulity() {
let mut details = Details::default();
details.colours.blocks = Red.blink();
let mut colours = Colours::default();
colours.blocks = Red.blink();
let blox = f::Blocks::Some(3005);
let expected = TextCell::paint_str(Red.blink(), "3005");
assert_eq!(expected, blox.render(&details.colours).into());
assert_eq!(expected, blox.render(&colours).into());
}
}

View File

@ -33,7 +33,7 @@ impl f::GitStatus {
#[cfg(test)]
pub mod test {
use output::details::Details;
use output::colours::Colours;
use output::cell::{TextCell, DisplayWidth};
use fs::fields as f;
@ -42,8 +42,8 @@ pub mod test {
#[test]
fn git_blank() {
let mut details = Details::default();
details.colours.punctuation = Fixed(44).normal();
let mut colours = Colours::default();
colours.punctuation = Fixed(44).normal();
let stati = f::Git {
staged: f::GitStatus::NotModified,
@ -58,15 +58,15 @@ pub mod test {
].into(),
};
assert_eq!(expected, stati.render(&details.colours).into())
assert_eq!(expected, stati.render(&colours).into())
}
#[test]
fn git_new_changed() {
let mut details = Details::default();
details.colours.git.new = Red.normal();
details.colours.git.modified = Purple.normal();
let mut colours = Colours::default();
colours.git.new = Red.normal();
colours.git.modified = Purple.normal();
let stati = f::Git {
staged: f::GitStatus::New,
@ -81,6 +81,6 @@ pub mod test {
].into(),
};
assert_eq!(expected, stati.render(&details.colours).into())
assert_eq!(expected, stati.render(&colours).into())
}
}

View File

@ -32,10 +32,9 @@ impl f::Group {
#[cfg(test)]
#[allow(unused_results)]
pub mod test {
use output::details::Details;
use fs::fields as f;
use output::cell::TextCell;
use output::colours::Colours;
use users::{User, Group};
use users::mock::MockUsers;
@ -45,33 +44,33 @@ pub mod test {
#[test]
fn named() {
let mut details = Details::default();
details.colours.users.group_not_yours = Fixed(101).normal();
let mut colours = Colours::default();
colours.users.group_not_yours = Fixed(101).normal();
let mut users = MockUsers::with_current_uid(1000);
users.add_group(Group::new(100, "folk"));
let group = f::Group(100);
let expected = TextCell::paint_str(Fixed(101).normal(), "folk");
assert_eq!(expected, group.render(&details.colours, &users))
assert_eq!(expected, group.render(&colours, &users))
}
#[test]
fn unnamed() {
let mut details = Details::default();
details.colours.users.group_not_yours = Fixed(87).normal();
let mut colours = Colours::default();
colours.users.group_not_yours = Fixed(87).normal();
let users = MockUsers::with_current_uid(1000);
let group = f::Group(100);
let expected = TextCell::paint_str(Fixed(87).normal(), "100");
assert_eq!(expected, group.render(&details.colours, &users));
assert_eq!(expected, group.render(&colours, &users));
}
#[test]
fn primary() {
let mut details = Details::default();
details.colours.users.group_yours = Fixed(64).normal();
let mut colours = Colours::default();
colours.users.group_yours = Fixed(64).normal();
let mut users = MockUsers::with_current_uid(2);
users.add_user(User::new(2, "eve", 100));
@ -79,13 +78,13 @@ pub mod test {
let group = f::Group(100);
let expected = TextCell::paint_str(Fixed(64).normal(), "folk");
assert_eq!(expected, group.render(&details.colours, &users))
assert_eq!(expected, group.render(&colours, &users))
}
#[test]
fn secondary() {
let mut details = Details::default();
details.colours.users.group_yours = Fixed(31).normal();
let mut colours = Colours::default();
colours.users.group_yours = Fixed(31).normal();
let mut users = MockUsers::with_current_uid(2);
users.add_user(User::new(2, "eve", 666));
@ -95,16 +94,16 @@ pub mod test {
let group = f::Group(100);
let expected = TextCell::paint_str(Fixed(31).normal(), "folk");
assert_eq!(expected, group.render(&details.colours, &users))
assert_eq!(expected, group.render(&colours, &users))
}
#[test]
fn overflow() {
let mut details = Details::default();
details.colours.users.group_not_yours = Blue.underline();
let mut colours = Colours::default();
colours.users.group_not_yours = Blue.underline();
let group = f::Group(2_147_483_648);
let expected = TextCell::paint_str(Blue.underline(), "2147483648");
assert_eq!(expected, group.render(&details.colours, &MockUsers::with_current_uid(0)));
assert_eq!(expected, group.render(&colours, &MockUsers::with_current_uid(0)));
}
}

View File

@ -12,7 +12,7 @@ impl f::Inode {
#[cfg(test)]
pub mod test {
use output::details::Details;
use output::colours::Colours;
use output::cell::TextCell;
use fs::fields as f;
@ -21,11 +21,11 @@ pub mod test {
#[test]
fn blocklessness() {
let mut details = Details::default();
details.colours.inode = Cyan.underline();
let mut colours = Colours::default();
colours.inode = Cyan.underline();
let io = f::Inode(1414213);
let expected = TextCell::paint_str(Cyan.underline(), "1414213");
assert_eq!(expected, io.render(&details.colours).into());
assert_eq!(expected, io.render(&colours).into());
}
}

View File

@ -17,7 +17,7 @@ impl f::Links {
#[cfg(test)]
pub mod test {
use output::details::Details;
use output::colours::Colours;
use output::cell::{TextCell, DisplayWidth};
use fs::fields as f;
@ -27,8 +27,8 @@ pub mod test {
#[test]
fn regular_file() {
let mut details = Details::default();
details.colours.links.normal = Blue.normal();
let mut colours = Colours::default();
colours.links.normal = Blue.normal();
let stati = f::Links {
count: 1,
@ -40,13 +40,13 @@ pub mod test {
contents: vec![ Blue.paint("1") ].into(),
};
assert_eq!(expected, stati.render(&details.colours, &locale::Numeric::english()).into());
assert_eq!(expected, stati.render(&colours, &locale::Numeric::english()).into());
}
#[test]
fn regular_directory() {
let mut details = Details::default();
details.colours.links.normal = Blue.normal();
let mut colours = Colours::default();
colours.links.normal = Blue.normal();
let stati = f::Links {
count: 3005,
@ -58,13 +58,13 @@ pub mod test {
contents: vec![ Blue.paint("3,005") ].into(),
};
assert_eq!(expected, stati.render(&details.colours, &locale::Numeric::english()).into());
assert_eq!(expected, stati.render(&colours, &locale::Numeric::english()).into());
}
#[test]
fn popular_file() {
let mut details = Details::default();
details.colours.links.multi_link_file = Blue.on(Red);
let mut colours = Colours::default();
colours.links.multi_link_file = Blue.on(Red);
let stati = f::Links {
count: 3005,
@ -76,6 +76,6 @@ pub mod test {
contents: vec![ Blue.on(Red).paint("3,005") ].into(),
};
assert_eq!(expected, stati.render(&details.colours, &locale::Numeric::english()).into());
assert_eq!(expected, stati.render(&colours, &locale::Numeric::english()).into());
}
}

View File

@ -92,7 +92,7 @@ impl f::Type {
#[cfg(test)]
#[allow(unused_results)]
pub mod test {
use output::details::Details;
use output::colours::Colours;
use output::cell::TextCellContents;
use fs::fields as f;
@ -101,8 +101,8 @@ pub mod test {
#[test]
fn negate() {
let mut details = Details::default();
details.colours.punctuation = Fixed(11).normal();
let mut colours = Colours::default();
colours.punctuation = Fixed(11).normal();
let bits = f::Permissions {
user_read: false, user_write: false, user_execute: false, setuid: false,
@ -116,24 +116,24 @@ pub mod test {
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(11).paint("-"),
]);
assert_eq!(expected, bits.render(&details.colours, false).into())
assert_eq!(expected, bits.render(&colours, false).into())
}
#[test]
fn affirm() {
let mut details = Details::default();
details.colours.perms.user_read = Fixed(101).normal();
details.colours.perms.user_write = Fixed(102).normal();
details.colours.perms.user_execute_file = Fixed(103).normal();
let mut colours = Colours::default();
colours.perms.user_read = Fixed(101).normal();
colours.perms.user_write = Fixed(102).normal();
colours.perms.user_execute_file = Fixed(103).normal();
details.colours.perms.group_read = Fixed(104).normal();
details.colours.perms.group_write = Fixed(105).normal();
details.colours.perms.group_execute = Fixed(106).normal();
colours.perms.group_read = Fixed(104).normal();
colours.perms.group_write = Fixed(105).normal();
colours.perms.group_execute = Fixed(106).normal();
details.colours.perms.other_read = Fixed(107).normal();
details.colours.perms.other_write = Fixed(108).normal();
details.colours.perms.other_execute = Fixed(109).normal();
colours.perms.other_read = Fixed(107).normal();
colours.perms.other_write = Fixed(108).normal();
colours.perms.other_execute = Fixed(109).normal();
let bits = f::Permissions {
user_read: true, user_write: true, user_execute: true, setuid: false,
@ -147,16 +147,16 @@ pub mod test {
Fixed(107).paint("r"), Fixed(108).paint("w"), Fixed(109).paint("x"),
]);
assert_eq!(expected, bits.render(&details.colours, true).into())
assert_eq!(expected, bits.render(&colours, true).into())
}
#[test]
fn specials() {
let mut details = Details::default();
details.colours.punctuation = Fixed(11).normal();
details.colours.perms.special_user_file = Fixed(77).normal();
details.colours.perms.special_other = Fixed(88).normal();
let mut colours = Colours::default();
colours.punctuation = Fixed(11).normal();
colours.perms.special_user_file = Fixed(77).normal();
colours.perms.special_other = Fixed(88).normal();
let bits = f::Permissions {
user_read: false, user_write: false, user_execute: true, setuid: true,
@ -170,15 +170,15 @@ pub mod test {
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(88).paint("t"),
]);
assert_eq!(expected, bits.render(&details.colours, true).into())
assert_eq!(expected, bits.render(&colours, true).into())
}
#[test]
fn extra_specials() {
let mut details = Details::default();
details.colours.punctuation = Fixed(11).normal();
details.colours.perms.special_other = Fixed(88).normal();
let mut colours = Colours::default();
colours.punctuation = Fixed(11).normal();
colours.perms.special_other = Fixed(88).normal();
let bits = f::Permissions {
user_read: false, user_write: false, user_execute: false, setuid: true,
@ -192,6 +192,6 @@ pub mod test {
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(88).paint("T"),
]);
assert_eq!(expected, bits.render(&details.colours, true).into())
assert_eq!(expected, bits.render(&colours, true).into())
}
}

View File

@ -67,7 +67,7 @@ impl f::DeviceIDs {
#[cfg(test)]
pub mod test {
use output::details::Details;
use output::colours::Colours;
use output::column::SizeFormat;
use output::cell::{TextCell, DisplayWidth};
use fs::fields as f;
@ -78,20 +78,20 @@ pub mod test {
#[test]
fn directory() {
let mut details = Details::default();
details.colours.punctuation = Green.italic();
let mut colours = Colours::default();
colours.punctuation = Green.italic();
let directory = f::Size::None;
let expected = TextCell::blank(Green.italic());
assert_eq!(expected, directory.render(&details.colours, SizeFormat::JustBytes, &locale::Numeric::english()))
assert_eq!(expected, directory.render(&colours, SizeFormat::JustBytes, &locale::Numeric::english()))
}
#[test]
fn file_decimal() {
let mut details = Details::default();
details.colours.size.numbers = Blue.on(Red);
details.colours.size.unit = Yellow.bold();
let mut colours = Colours::default();
colours.size.numbers = Blue.on(Red);
colours.size.unit = Yellow.bold();
let directory = f::Size::Some(2_100_000);
let expected = TextCell {
@ -102,15 +102,15 @@ pub mod test {
].into(),
};
assert_eq!(expected, directory.render(&details.colours, SizeFormat::DecimalBytes, &locale::Numeric::english()))
assert_eq!(expected, directory.render(&colours, SizeFormat::DecimalBytes, &locale::Numeric::english()))
}
#[test]
fn file_binary() {
let mut details = Details::default();
details.colours.size.numbers = Blue.on(Red);
details.colours.size.unit = Yellow.bold();
let mut colours = Colours::default();
colours.size.numbers = Blue.on(Red);
colours.size.unit = Yellow.bold();
let directory = f::Size::Some(1_048_576);
let expected = TextCell {
@ -121,14 +121,14 @@ pub mod test {
].into(),
};
assert_eq!(expected, directory.render(&details.colours, SizeFormat::BinaryBytes, &locale::Numeric::english()))
assert_eq!(expected, directory.render(&colours, SizeFormat::BinaryBytes, &locale::Numeric::english()))
}
#[test]
fn file_bytes() {
let mut details = Details::default();
details.colours.size.numbers = Blue.on(Red);
let mut colours = Colours::default();
colours.size.numbers = Blue.on(Red);
let directory = f::Size::Some(1048576);
let expected = TextCell {
@ -138,16 +138,16 @@ pub mod test {
].into(),
};
assert_eq!(expected, directory.render(&details.colours, SizeFormat::JustBytes, &locale::Numeric::english()))
assert_eq!(expected, directory.render(&colours, SizeFormat::JustBytes, &locale::Numeric::english()))
}
#[test]
fn device_ids() {
let mut details = Details::default();
details.colours.size.major = Blue.on(Red);
details.colours.punctuation = Green.italic();
details.colours.size.minor = Cyan.on(Yellow);
let mut colours = Colours::default();
colours.size.major = Blue.on(Red);
colours.punctuation = Green.italic();
colours.size.minor = Cyan.on(Yellow);
let directory = f::Size::DeviceIDs(f::DeviceIDs { major: 10, minor: 80 });
let expected = TextCell {
@ -159,6 +159,6 @@ pub mod test {
].into(),
};
assert_eq!(expected, directory.render(&details.colours, SizeFormat::JustBytes, &locale::Numeric::english()))
assert_eq!(expected, directory.render(&colours, SizeFormat::JustBytes, &locale::Numeric::english()))
}
}

View File

@ -21,10 +21,9 @@ impl f::User {
#[cfg(test)]
#[allow(unused_results)]
pub mod test {
use output::details::Details;
use fs::fields as f;
use output::cell::TextCell;
use output::colours::Colours;
use users::User;
use users::mock::MockUsers;
@ -32,59 +31,59 @@ pub mod test {
#[test]
fn named() {
let mut details = Details::default();
details.colours.users.user_you = Red.bold();
let mut colours = Colours::default();
colours.users.user_you = Red.bold();
let mut users = MockUsers::with_current_uid(1000);
users.add_user(User::new(1000, "enoch", 100));
let user = f::User(1000);
let expected = TextCell::paint_str(Red.bold(), "enoch");
assert_eq!(expected, user.render(&details.colours, &users))
assert_eq!(expected, user.render(&colours, &users))
}
#[test]
fn unnamed() {
let mut details = Details::default();
details.colours.users.user_you = Cyan.bold();
let mut colours = Colours::default();
colours.users.user_you = Cyan.bold();
let users = MockUsers::with_current_uid(1000);
let user = f::User(1000);
let expected = TextCell::paint_str(Cyan.bold(), "1000");
assert_eq!(expected, user.render(&details.colours, &users));
assert_eq!(expected, user.render(&colours, &users));
}
#[test]
fn different_named() {
let mut details = Details::default();
details.colours.users.user_someone_else = Green.bold();
let mut colours = Colours::default();
colours.users.user_someone_else = Green.bold();
let mut users = MockUsers::with_current_uid(0);
users.add_user(User::new(1000, "enoch", 100));
let user = f::User(1000);
let expected = TextCell::paint_str(Green.bold(), "enoch");
assert_eq!(expected, user.render(&details.colours, &users));
assert_eq!(expected, user.render(&colours, &users));
}
#[test]
fn different_unnamed() {
let mut details = Details::default();
details.colours.users.user_someone_else = Red.normal();
let mut colours = Colours::default();
colours.users.user_someone_else = Red.normal();
let user = f::User(1000);
let expected = TextCell::paint_str(Red.normal(), "1000");
assert_eq!(expected, user.render(&details.colours, &MockUsers::with_current_uid(0)));
assert_eq!(expected, user.render(&colours, &MockUsers::with_current_uid(0)));
}
#[test]
fn overflow() {
let mut details = Details::default();
details.colours.users.user_someone_else = Blue.underline();
let mut colours = Colours::default();
colours.users.user_someone_else = Blue.underline();
let user = f::User(2_147_483_648);
let expected = TextCell::paint_str(Blue.underline(), "2147483648");
assert_eq!(expected, user.render(&details.colours, &MockUsers::with_current_uid(0)));
assert_eq!(expected, user.render(&colours, &MockUsers::with_current_uid(0)));
}
}

39
xtests/files_l_bw Normal file
View File

@ -0,0 +1,39 @@
.rw-r--r-- 1.0k cassowary 1 Jan 12:34 1_KiB
.rw-r--r-- 1.0M cassowary 1 Jan 12:34 1_MiB
.rw-r--r-- 1 cassowary 1 Jan 12:34 1_bytes
.rw-r--r-- 2.0k cassowary 1 Jan 12:34 2_KiB
.rw-r--r-- 2.1M cassowary 1 Jan 12:34 2_MiB
.rw-r--r-- 2 cassowary 1 Jan 12:34 2_bytes
.rw-r--r-- 3.1k cassowary 1 Jan 12:34 3_KiB
.rw-r--r-- 3.1M cassowary 1 Jan 12:34 3_MiB
.rw-r--r-- 3 cassowary 1 Jan 12:34 3_bytes
.rw-r--r-- 4.1k cassowary 1 Jan 12:34 4_KiB
.rw-r--r-- 4.2M cassowary 1 Jan 12:34 4_MiB
.rw-r--r-- 4 cassowary 1 Jan 12:34 4_bytes
.rw-r--r-- 5.1k cassowary 1 Jan 12:34 5_KiB
.rw-r--r-- 5.2M cassowary 1 Jan 12:34 5_MiB
.rw-r--r-- 5 cassowary 1 Jan 12:34 5_bytes
.rw-r--r-- 6.1k cassowary 1 Jan 12:34 6_KiB
.rw-r--r-- 6.3M cassowary 1 Jan 12:34 6_MiB
.rw-r--r-- 6 cassowary 1 Jan 12:34 6_bytes
.rw-r--r-- 7.2k cassowary 1 Jan 12:34 7_KiB
.rw-r--r-- 7.3M cassowary 1 Jan 12:34 7_MiB
.rw-r--r-- 7 cassowary 1 Jan 12:34 7_bytes
.rw-r--r-- 8.2k cassowary 1 Jan 12:34 8_KiB
.rw-r--r-- 8.4M cassowary 1 Jan 12:34 8_MiB
.rw-r--r-- 8 cassowary 1 Jan 12:34 8_bytes
.rw-r--r-- 9.2k cassowary 1 Jan 12:34 9_KiB
.rw-r--r-- 9.4M cassowary 1 Jan 12:34 9_MiB
.rw-r--r-- 9 cassowary 1 Jan 12:34 9_bytes
.rw-r--r-- 10k cassowary 1 Jan 12:34 10_KiB
.rw-r--r-- 10M cassowary 1 Jan 12:34 10_MiB
.rw-r--r-- 10 cassowary 1 Jan 12:34 10_bytes
.rw-r--r-- 11k cassowary 1 Jan 12:34 11_KiB
.rw-r--r-- 11M cassowary 1 Jan 12:34 11_MiB
.rw-r--r-- 11 cassowary 1 Jan 12:34 11_bytes
.rw-r--r-- 12k cassowary 1 Jan 12:34 12_KiB
.rw-r--r-- 12M cassowary 1 Jan 12:34 12_MiB
.rw-r--r-- 12 cassowary 1 Jan 12:34 12_bytes
.rw-r--r-- 13k cassowary 1 Jan 12:34 13_KiB
.rw-r--r-- 13M cassowary 1 Jan 12:34 13_MiB
.rw-r--r-- 13 cassowary 1 Jan 12:34 13_bytes

View File

@ -2,14 +2,17 @@
set +xe
# The exa binary we want to run
exa="$HOME/target/debug/exa --colour=always"
# The exa binary
exa_binary="$HOME/target/debug/exa"
# The exa command that ends up being run
exa="$exa_binary --colour=always"
# Directory containing our awkward testcase files
testcases=/testcases
testcases="/testcases"
# Directory containing existing test results to compare against
results=/vagrant/xtests
results="/vagrant/xtests"
# Check that no files were created more than a year ago.
@ -25,7 +28,7 @@ $exa $testcases/files -lhb | diff -q - $results/files_lhb || exit 1
$exa $testcases/files -lhB | diff -q - $results/files_lhb2 || exit 1
$exa $testcases/attributes/dirs/empty-with-attribute -lh | diff -q - $results/empty || exit 1
$exa $testcases/files -l --color-scale | diff -q - $results/files_l_scale || exit 1
$exa --color-scale $testcases/files -l | diff -q - $results/files_l_scale || exit 1
# Grid view tests
@ -105,6 +108,14 @@ COLUMNS=80 $exa $testcases/links 2>&1 | diff -q - $results/links || ex
$exa $testcases/links/* -1 | diff -q - $results/links_1_files || exit 1
# Colours and terminals
# Just because COLUMNS is present, doesnt mean output is to a terminal
COLUMNS=80 $exa_binary $testcases/files -l | diff -q - $results/files_l_bw || exit 1
COLUMNS=80 $exa_binary --colour=always $testcases/files -l | diff -q - $results/files_l || exit 1
COLUMNS=80 $exa_binary --colour=never $testcases/files -l | diff -q - $results/files_l_bw || exit 1
COLUMNS=80 $exa_binary --colour=automatic $testcases/files -l | diff -q - $results/files_l_bw || exit 1
# Git
$exa $testcases/git/additions -l --git 2>&1 | diff -q - $results/git_additions || exit 1
$exa $testcases/git/edits -l --git 2>&1 | diff -q - $results/git_edits || exit 1