diff --git a/Cargo.lock b/Cargo.lock index acac459..df94188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,24 +23,24 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.61" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" dependencies = [ "jobserver", ] [[package]] name = "cfg-if" -version = "0.1.10" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "datetime" @@ -79,10 +79,20 @@ dependencies = [ ] [[package]] -name = "git2" -version = "0.13.11" +name = "form_urlencoded" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e094214efbc7fdbbdee952147e493b00e99a4e52817492277e98967ae918165" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "git2" +version = "0.13.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" dependencies = [ "bitflags", "libc", @@ -100,18 +110,18 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "idna" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" dependencies = [ "matches", "unicode-bidi", @@ -135,15 +145,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.79" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" [[package]] name = "libgit2-sys" -version = "0.12.14+1.1.0" +version = "0.12.18+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" +checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" dependencies = [ "cc", "libc", @@ -174,9 +184,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] @@ -211,18 +221,18 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "openssl-src" -version = "111.12.0+1.1.1h" +version = "111.15.0+1.1.1k" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61" +checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.58" +version = "0.9.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" +checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" dependencies = [ "autocfg", "cc", @@ -286,24 +296,33 @@ dependencies = [ [[package]] name = "tinyvec" -version = "0.3.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" dependencies = [ "matches", ] [[package]] name = "unicode-normalization" -version = "0.1.13" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" dependencies = [ "tinyvec", ] @@ -316,10 +335,11 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "url" -version = "2.1.1" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ + "form_urlencoded", "idna", "matches", "percent-encoding", @@ -337,9 +357,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index d05e289..5944a68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ exclude = ["/devtools/*", "/Justfile", "/Vagrantfile", "/screenshots.png"] homepage = "https://the.exa.website/" license = "MIT" repository = "https://github.com/ogham/exa" -version = "0.11.0-pre" +version = "0.10.1" [[bin]] diff --git a/devtools/dev-create-test-filesystem.sh b/devtools/dev-create-test-filesystem.sh index afc19c0..112b569 100755 --- a/devtools/dev-create-test-filesystem.sh +++ b/devtools/dev-create-test-filesystem.sh @@ -300,6 +300,8 @@ touch "ignoreds/music.m4a" mkdir "ignoreds/nested" touch "ignoreds/nested/70s grove.mp3" touch "ignoreds/nested/funky chicken.m4a" +mkdir "ignoreds/nested2" +touch "ignoreds/nested2/ievan polkka.mp3" mkdir "target" touch "target/another ignored file" diff --git a/man/exa.1.md b/man/exa.1.md index 6e00a47..bd91a7c 100644 --- a/man/exa.1.md +++ b/man/exa.1.md @@ -84,7 +84,7 @@ FILTERING AND SORTING OPTIONS Use this twice to also show the ‘`.`’ and ‘`..`’ directories. `-d`, `--list-dirs` -: List directories like regular files. +: List directories as regular files, rather than recursing and listing their contents. `-L`, `--level=DEPTH` : Limit the depth of recursion. @@ -183,6 +183,10 @@ These options are available when running with `--long` (`-l`): `--git` [if exa was built with git support] : List each file’s Git status, if tracked. +This adds a two-character column indicating the staged and unstaged statuses respectively. The status character can be ‘`-`’ for not modified, ‘`M`’ for a modified file, ‘`N`’ for a new file, ‘`D`’ for deleted, ‘`R`’ for renamed, ‘`T`’ for type-change, ‘`I`’ for ignored, and ‘`U`’ for conflicted. + +Directories will be shown to have the status of their contents, which is how ‘deleted’ is possible: if a directory contains a file that has a certain status, it will be shown to have that status. + ENVIRONMENT VARIABLES ===================== diff --git a/src/fs/feature/git.rs b/src/fs/feature/git.rs index 1cba373..f6e37ab 100644 --- a/src/fs/feature/git.rs +++ b/src/fs/feature/git.rs @@ -242,25 +242,40 @@ impl Git { else { self.file_status(index) } } - /// Get the status for the file at the given path. + /// Get the user-facing status of a file. + /// We check the statuses directly applying to a file, and for the ignored + /// status we check if any of its parents directories is ignored by git. fn file_status(&self, file: &Path) -> f::Git { let path = reorient(file); - self.statuses.iter() - .find(|p| p.0.as_path() == path) - .map(|&(_, s)| f::Git { staged: index_status(s), unstaged: working_tree_status(s) }) - .unwrap_or_default() + let s = self.statuses.iter() + .filter(|p| if p.1 == git2::Status::IGNORED { + path.starts_with(&p.0) + } else { + p.0 == path + }) + .fold(git2::Status::empty(), |a, b| a | b.1); + + let staged = index_status(s); + let unstaged = working_tree_status(s); + f::Git { staged, unstaged } } - /// Get the combined status for all the files whose paths begin with the - /// path that gets passed in. This is used for getting the status of - /// directories, which don’t really have an ‘official’ status. + /// Get the combined, user-facing status of a directory. + /// Statuses are aggregating (for example, a directory is considered + /// modified if any file under it has the status modified), except for + /// ignored status which applies to files under (for example, a directory + /// is considered ignored if one of its parent directories is ignored). fn dir_status(&self, dir: &Path) -> f::Git { let path = reorient(dir); let s = self.statuses.iter() - .filter(|p| p.0.starts_with(&path)) - .fold(git2::Status::empty(), |a, b| a | b.1); + .filter(|p| if p.1 == git2::Status::IGNORED { + path.starts_with(&p.0) + } else { + p.0.starts_with(&path) + }) + .fold(git2::Status::empty(), |a, b| a | b.1); let staged = index_status(s); let unstaged = working_tree_status(s); diff --git a/src/fs/file.rs b/src/fs/file.rs index 3e6222b..2f509da 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -333,10 +333,15 @@ impl<'dir> File<'dir> { f::Size::None } else if self.is_char_device() || self.is_block_device() { - let dev = self.metadata.rdev(); + let device_ids = self.metadata.rdev().to_be_bytes(); + + // In C-land, getting the major and minor device IDs is done with + // preprocessor macros called `major` and `minor` that depend on + // the size of `dev_t`, but we just take the second-to-last and + // last bytes. f::Size::DeviceIDs(f::DeviceIDs { - major: (dev / 256) as u8, - minor: (dev % 256) as u8, + major: device_ids[6], + minor: device_ids[7], }) } else { diff --git a/src/options/dir_action.rs b/src/options/dir_action.rs index 0cc31fa..e729b86 100644 --- a/src/options/dir_action.rs +++ b/src/options/dir_action.rs @@ -1,7 +1,7 @@ //! Parsing the options for `DirAction`. use crate::options::parser::MatchedFlags; -use crate::options::{flags, OptionsError}; +use crate::options::{flags, OptionsError, NumberSource}; use crate::fs::dir_action::{DirAction, RecurseOptions}; @@ -55,17 +55,21 @@ impl RecurseOptions { /// determined earlier. The maximum level should be a number, and this /// will fail with an `Err` if it isn’t. pub fn deduce(matches: &MatchedFlags<'_>, tree: bool) -> Result { - let max_depth = if let Some(level) = matches.get(&flags::LEVEL)? { - match level.to_string_lossy().parse() { - Ok(l) => Some(l), - Err(e) => return Err(OptionsError::FailedParse(e)), + if let Some(level) = matches.get(&flags::LEVEL)? { + let arg_str = level.to_string_lossy(); + match arg_str.parse() { + Ok(l) => { + Ok(Self { tree, max_depth: Some(l) }) + } + Err(e) => { + let source = NumberSource::Arg(&flags::LEVEL); + Err(OptionsError::FailedParse(arg_str.to_string(), source, e)) + } } } else { - None - }; - - Ok(Self { tree, max_depth }) + Ok(Self { tree, max_depth: None }) + } } } diff --git a/src/options/error.rs b/src/options/error.rs index 2b724e1..1b1aa87 100644 --- a/src/options/error.rs +++ b/src/options/error.rs @@ -37,18 +37,38 @@ pub enum OptionsError { TreeAllAll, /// A numeric option was given that failed to be parsed as a number. - FailedParse(ParseIntError), + FailedParse(String, NumberSource, ParseIntError), /// A glob ignore was given that failed to be parsed as a pattern. FailedGlobPattern(String), } +/// The source of a string that failed to be parsed as a number. +#[derive(PartialEq, Debug)] +pub enum NumberSource { + + /// It came... from a command-line argument! + Arg(&'static Arg), + + /// It came... from the enviroment! + Env(&'static str), +} + impl From for OptionsError { fn from(error: glob::PatternError) -> Self { Self::FailedGlobPattern(error.to_string()) } } +impl fmt::Display for NumberSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Arg(arg) => write!(f, "option {}", arg), + Self::Env(env) => write!(f, "environment variable {}", env), + } + } +} + impl fmt::Display for OptionsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::options::parser::TakesValue; @@ -71,7 +91,7 @@ impl fmt::Display for OptionsError { Self::Useless(a, true, b) => write!(f, "Option {} is useless given option {}", a, b), Self::Useless2(a, b1, b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2), Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"), - Self::FailedParse(ref e) => write!(f, "Failed to parse number: {}", e), + Self::FailedParse(s, n, e) => write!(f, "Value {:?} not valid for {}: {}", s, n, e), Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e), } } diff --git a/src/options/file_name.rs b/src/options/file_name.rs index 96131bb..2c1db1a 100644 --- a/src/options/file_name.rs +++ b/src/options/file_name.rs @@ -1,4 +1,4 @@ -use crate::options::{flags, OptionsError}; +use crate::options::{flags, OptionsError, NumberSource}; use crate::options::parser::MatchedFlags; use crate::options::vars::{self, Vars}; @@ -30,8 +30,13 @@ impl ShowIcons { } else if let Some(columns) = vars.get(vars::EXA_ICON_SPACING).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(width) => Ok(Self::On(width)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(width) => { + Ok(Self::On(width)) + } + Err(e) => { + let source = NumberSource::Env(vars::EXA_ICON_SPACING); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { diff --git a/src/options/help.rs b/src/options/help.rs index 8f47a73..f3f4009 100644 --- a/src/options/help.rs +++ b/src/options/help.rs @@ -27,7 +27,7 @@ DISPLAY OPTIONS FILTERING AND SORTING OPTIONS -a, --all show hidden and 'dot' files - -d, --list-dirs list directories like regular files + -d, --list-dirs list directories as files; don't list their contents -L, --level DEPTH limit the depth of recursion -r, --reverse reverse the sort order -s, --sort SORT_FIELD which field to sort by diff --git a/src/options/mod.rs b/src/options/mod.rs index 26e9c81..747213b 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -84,7 +84,7 @@ mod theme; mod view; mod error; -pub use self::error::OptionsError; +pub use self::error::{OptionsError, NumberSource}; mod help; use self::help::HelpString; diff --git a/src/options/view.rs b/src/options/view.rs index 6f13c87..6d7abac 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -1,5 +1,5 @@ use crate::fs::feature::xattr; -use crate::options::{flags, OptionsError, Vars}; +use crate::options::{flags, OptionsError, NumberSource, Vars}; use crate::options::parser::MatchedFlags; use crate::output::{View, Mode, TerminalWidth, grid, details}; use crate::output::grid_details::{self, RowThreshold}; @@ -151,8 +151,13 @@ impl TerminalWidth { if let Some(columns) = vars.get(vars::COLUMNS).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(width) => Ok(Self::Set(width)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(width) => { + Ok(Self::Set(width)) + } + Err(e) => { + let source = NumberSource::Env(vars::COLUMNS); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { @@ -168,8 +173,13 @@ impl RowThreshold { if let Some(columns) = vars.get(vars::EXA_GRID_ROWS).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(rows) => Ok(Self::MinimumRows(rows)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(rows) => { + Ok(Self::MinimumRows(rows)) + } + Err(e) => { + let source = NumberSource::Env(vars::EXA_GRID_ROWS); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { diff --git a/src/output/file_name.rs b/src/output/file_name.rs index fcf02f2..bc172f1 100644 --- a/src/output/file_name.rs +++ b/src/output/file_name.rs @@ -173,7 +173,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { show_icons: ShowIcons::Off, }; - let target = FileName { + let target_name = FileName { file: target, colours: self.colours, target: None, @@ -181,9 +181,15 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { options: target_options, }; - for bit in target.coloured_file_name() { + for bit in target_name.coloured_file_name() { bits.push(bit); } + + if let Classify::AddFileIndicators = self.options.classify { + if let Some(class) = self.classify_char(target) { + bits.push(Style::default().paint(class)); + } + } } } @@ -206,7 +212,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { } } else if let Classify::AddFileIndicators = self.options.classify { - if let Some(class) = self.classify_char() { + if let Some(class) = self.classify_char(self.file) { bits.push(Style::default().paint(class)); } } @@ -236,20 +242,20 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { /// The character to be displayed after a file when classifying is on, if /// the file’s type has one associated with it. #[cfg(unix)] - fn classify_char(&self) -> Option<&'static str> { - if self.file.is_executable_file() { + fn classify_char(&self, file: &File<'_>) -> Option<&'static str> { + if file.is_executable_file() { Some("*") } - else if self.file.is_directory() { + else if file.is_directory() { Some("/") } - else if self.file.is_pipe() { + else if file.is_pipe() { Some("|") } - else if self.file.is_link() { + else if file.is_link() { Some("@") } - else if self.file.is_socket() { + else if file.is_socket() { Some("=") } else { @@ -258,11 +264,11 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { } #[cfg(windows)] - fn classify_char(&self) -> Option<&'static str> { - if self.file.is_directory() { + fn classify_char(&self, file: &File<'_>) -> Option<&'static str> { + if file.is_directory() { Some("/") } - else if self.file.is_link() { + else if file.is_link() { Some("@") } else { diff --git a/src/output/grid_details.rs b/src/output/grid_details.rs index df8e53c..35ff023 100644 --- a/src/output/grid_details.rs +++ b/src/output/grid_details.rs @@ -174,22 +174,21 @@ impl<'a> Render<'a> { }; if the_grid_fits { - if column_count == file_names.len() { - return Some((grid, column_count)); - } else { - last_working_grid = grid; - } - } else { - // If we’ve figured out how many columns can fit in the user’s - // terminal, and it turns out there aren’t enough rows to - // make it worthwhile, then just resort to the lines view. + last_working_grid = grid; + } + + if !the_grid_fits || column_count == file_names.len() { + let last_column_count = if the_grid_fits { column_count } else { column_count - 1 }; + // If we’ve figured out how many columns can fit in the user’s terminal, + // and it turns out there aren’t enough rows to make it worthwhile + // (according to EXA_GRID_ROWS), then just resort to the lines view. if let RowThreshold::MinimumRows(thresh) = self.row_threshold { - if last_working_grid.fit_into_columns(column_count - 1).row_count() < thresh { + if last_working_grid.fit_into_columns(last_column_count).row_count() < thresh { return None; } } - return Some((last_working_grid, column_count - 1)); + return Some((last_working_grid, last_column_count)); } } diff --git a/src/output/icons.rs b/src/output/icons.rs index 2a9373d..5f6680b 100644 --- a/src/output/icons.rs +++ b/src/output/icons.rs @@ -128,7 +128,7 @@ pub fn icon_for_file(file: &File<'_>) -> char { "class" => '\u{e256}', //  "clj" => '\u{e768}', //  "cljs" => '\u{e76a}', //  - "cls" => '\u{e600}', //  + "cls" => '\u{f034}', //  "cmd" => '\u{e70f}', //  "coffee" => '\u{f0f4}', //  "conf" => '\u{e615}', //  @@ -209,7 +209,7 @@ pub fn icon_for_file(file: &File<'_>) -> char { "json" => '\u{e60b}', //  "jsx" => '\u{e7ba}', //  "ksh" => '\u{f489}', //  - "latex" => '\u{e600}', //  + "latex" => '\u{f034}', //  "less" => '\u{e758}', //  "lhs" => '\u{e777}', //  "license" => '\u{f718}', //  @@ -297,7 +297,7 @@ pub fn icon_for_file(file: &File<'_>) -> char { "taz" => '\u{f410}', //  "tbz" => '\u{f410}', //  "tbz2" => '\u{f410}', //  - "tex" => '\u{e600}', //  + "tex" => '\u{f034}', //  "tiff" => '\u{f1c5}', //  "toml" => '\u{e615}', //  "ts" => '\u{e628}', //  diff --git a/src/output/render/size.rs b/src/output/render/size.rs index 7f1acb7..94f751b 100644 --- a/src/output/render/size.rs +++ b/src/output/render/size.rs @@ -36,20 +36,20 @@ impl f::Size { }; let (prefix, n) = match result { - NumberPrefix::Standalone(b) => return TextCell::paint(colours.size(None), b.to_string()), + NumberPrefix::Standalone(b) => return TextCell::paint(colours.size(None), numerics.format_int(b)), NumberPrefix::Prefixed(p, n) => (p, n), }; let symbol = prefix.symbol(); - let decimal_to_diplay = if n < 10_f64 { 1 } else { 0 }; - let number = numerics.format_float(n, decimal_to_diplay); + let number = if n < 10_f64 { + numerics.format_float(n, 1) + } else { + numerics.format_int(n.round() as isize) + }; - // The numbers and symbols are guaranteed to be written in ASCII, so - // we can skip the display width calculation. - let width = DisplayWidth::from(number.len() + symbol.len()); - TextCell { - width, + // symbol is guaranteed to be ASCII since unit prefixes are hardcoded. + width: DisplayWidth::from(&*number) + symbol.len(), contents: vec![ colours.size(Some(prefix)).paint(number), colours.unit(Some(prefix)).paint(symbol), diff --git a/src/output/time.rs b/src/output/time.rs index 79b3554..cb18c54 100644 --- a/src/output/time.rs +++ b/src/output/time.rs @@ -2,7 +2,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; -use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece, Month}; +use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece}; use datetime::fmt::DateFormat; use lazy_static::lazy_static; @@ -75,40 +75,25 @@ impl TimeFormat { #[allow(trivial_numeric_casts)] fn default_local(time: SystemTime) -> String { let date = LocalDateTime::at(systemtime_epoch(time)); - - if date.year() == *CURRENT_YEAR { - format!("{:2} {} {:02}:{:02}", - date.day(), month_to_abbrev(date.month()), - date.hour(), date.minute()) - } - else { - let date_format = match *MAXIMUM_MONTH_WIDTH { - 4 => &*FOUR_WIDE_DATE_TIME, - 5 => &*FIVE_WIDE_DATE_TIME, - _ => &*OTHER_WIDE_DATE_TIME, - }; - - date_format.format(&date, &*LOCALE) - } + let date_format = get_dateformat(&date); + date_format.format(&date, &*LOCALE) } #[allow(trivial_numeric_casts)] fn default_zoned(time: SystemTime, zone: &TimeZone) -> String { let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time))); + let date_format = get_dateformat(&date); + date_format.format(&date, &*LOCALE) +} - if date.year() == *CURRENT_YEAR { - format!("{:2} {} {:02}:{:02}", - date.day(), month_to_abbrev(date.month()), - date.hour(), date.minute()) - } - else { - let date_format = match *MAXIMUM_MONTH_WIDTH { - 4 => &*FOUR_WIDE_DATE_YEAR, - 5 => &*FIVE_WIDE_DATE_YEAR, - _ => &*OTHER_WIDE_DATE_YEAR, - }; - - date_format.format(&date, &*LOCALE) +fn get_dateformat(date: &LocalDateTime) -> &'static DateFormat<'static> { + match (is_recent(&date), *MAXIMUM_MONTH_WIDTH) { + (true, 4) => &FOUR_WIDE_DATE_TIME, + (true, 5) => &FIVE_WIDE_DATE_TIME, + (true, _) => &OTHER_WIDE_DATE_TIME, + (false, 4) => &FOUR_WIDE_DATE_YEAR, + (false, 5) => &FIVE_WIDE_DATE_YEAR, + (false, _) => &OTHER_WIDE_DATE_YEAR, } } @@ -153,7 +138,7 @@ fn full_zoned(time: SystemTime, zone: &TimeZone) -> String { fn iso_local(time: SystemTime) -> String { let date = LocalDateTime::at(systemtime_epoch(time)); - if is_recent(date) { + if is_recent(&date) { format!("{:02}-{:02} {:02}:{:02}", date.month() as usize, date.day(), date.hour(), date.minute()) @@ -168,7 +153,7 @@ fn iso_local(time: SystemTime) -> String { fn iso_zoned(time: SystemTime, zone: &TimeZone) -> String { let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time))); - if is_recent(date) { + if is_recent(&date) { format!("{:02}-{:02} {:02}:{:02}", date.month() as usize, date.day(), date.hour(), date.minute()) @@ -206,27 +191,10 @@ fn systemtime_nanos(time: SystemTime) -> u32 { }) } -fn is_recent(date: LocalDateTime) -> bool { +fn is_recent(date: &LocalDateTime) -> bool { date.year() == *CURRENT_YEAR } -fn month_to_abbrev(month: Month) -> &'static str { - match month { - Month::January => "Jan", - Month::February => "Feb", - Month::March => "Mar", - Month::April => "Apr", - Month::May => "May", - Month::June => "Jun", - Month::July => "Jul", - Month::August => "Aug", - Month::September => "Sep", - Month::October => "Oct", - Month::November => "Nov", - Month::December => "Dec", - } -} - lazy_static! { @@ -250,15 +218,15 @@ lazy_static! { }; static ref FOUR_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse( - "{2>:D} {4<:M} {2>:h}:{02>:m}" + "{2>:D} {4<:M} {02>:h}:{02>:m}" ).unwrap(); static ref FIVE_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse( - "{2>:D} {5<:M} {2>:h}:{02>:m}" + "{2>:D} {5<:M} {02>:h}:{02>:m}" ).unwrap(); static ref OTHER_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse( - "{2>:D} {:M} {2>:h}:{02>:m}" + "{2>:D} {:M} {02>:h}:{02>:m}" ).unwrap(); static ref FOUR_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse( diff --git a/xtests/details-view-dates.toml b/xtests/details-view-dates.toml index 50c2646..30cefeb 100644 --- a/xtests/details-view-dates.toml +++ b/xtests/details-view-dates.toml @@ -68,7 +68,7 @@ tags = [ 'long', 'time-style' ] [[cmd]] name = "‘exa -l’ using a locale with 4-character-long month abbreviations (‘ja_JP’) sizes the date column correctly" shell = "exa -l /testcases/dates" -environment = { LC_ALL = "ja_JP.UTF-8", LANG = "ja_JP.UTF-8" } +environment = { LC_TIME = "ja_JP.UTF-8", LANG = "ja_JP.UTF-8" } stdout = { file = "outputs/dates_long_localejp.ansitxt" } stderr = { empty = true } status = 0 @@ -77,8 +77,17 @@ tags = [ 'long', 'locales' ] [[cmd]] name = "‘exa -l’ using a locale with 5-character-long month abbreviations (‘fr_FR’) sizes the date column correctly" shell = "exa -l /testcases/dates" -environment = { LC_ALL = "fr_FR.UTF-8", LANG = "fr_FR.UTF-8" } +environment = { LC_TIME = "fr_FR.UTF-8", LANG = "fr_FR.UTF-8" } stdout = { file = "outputs/dates_long_localefr.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'locales' ] + +[[cmd]] +name = "‘exa -l’ using a locale (‘fr_FR’) display dates of the current year with localized month name" +shell = "exa -l /testcases/files" +environment = { LC_TIME = "fr_FR.UTF-8", LANG = "fr_FR.UTF-8" } +stdout = { file = "outputs/dates_long_currentyear_localefr.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'locales' ] diff --git a/xtests/details-view-filesizes.toml b/xtests/details-view-filesizes.toml index 6682d25..271db54 100644 --- a/xtests/details-view-filesizes.toml +++ b/xtests/details-view-filesizes.toml @@ -61,3 +61,14 @@ stdout = { file = "outputs/files_long_colourscale_bytes.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'colour-scale', 'bytes' ] + +[[cmd]] +name = "‘exa -l’ produces a details table with major and minor device IDs" +shell = "cd /dev; exa -l mem null port zero full random urandom --sort=none --no-time" +stdout = { file = "outputs/dev_long.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'dev' ] + +# these particular device IDs should be fixed: +# https://raw.githubusercontent.com/torvalds/linux/master/Documentation/admin-guide/devices.txt diff --git a/xtests/details-view.toml b/xtests/details-view.toml index 331fa58..73874df 100644 --- a/xtests/details-view.toml +++ b/xtests/details-view.toml @@ -43,3 +43,11 @@ stdout = { file = "outputs/specials_long_classify.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'classify' ] + +[[cmd]] +name = "‘exa -lF’ handles and classifies symlink kinds" +shell = "exa -lF --no-time /testcases/links" +stdout = { file = "outputs/links_long_classify.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'classify' ] diff --git a/xtests/errors.toml b/xtests/errors.toml index 150e73e..7ca0a08 100644 --- a/xtests/errors.toml +++ b/xtests/errors.toml @@ -1,3 +1,22 @@ +# Command-line errors + +[[cmd]] +name = "‘exa --aoeu’ displays an error" +shell = "exa --aoeu" +stdout = { empty = true } +stderr = { file = "outputs/error_invalid_option.ansitxt" } +status = 3 +tags = [ 'error' ] + +[[cmd]] +name = "‘exa -Taa’ displays an error" +shell = "exa -Taa" +stdout = { empty = true } +stderr = { file = "outputs/error_tree_all_all.ansitxt" } +status = 3 +tags = [ 'error' ] + + # Error suggestions [[cmd]] @@ -15,3 +34,85 @@ stdout = { empty = true } stderr = { string = "To sort newest files last, try \"--sort newest\", or just \"-snew\""} status = 3 tags = [ 'error', 'long', 'sort' ] + + +# Invalid values for $COLUMNS + +[[cmd]] +name = "‘COLUMNS=999... exa’ shows an error about the number size" +shell = "exa" +environment = { "COLUMNS" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_columns_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + +[[cmd]] +name = "‘COLUMNS=abcdef exa’ shows an error about invalid digits" +shell = "exa" +environment = { "COLUMNS" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_columns_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + + +# Invalid values for $EXA_GRID_ROWS + +[[cmd]] +name = "‘EXA_GRID_ROWS=999... exa -lG’ shows an error about the number size" +shell = "exa -lG" +environment = { "EXA_GRID_ROWS" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_grid_rows_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + +[[cmd]] +name = "‘EXA_GRID_ROWS=abcdef exa -lG’ shows an error about invalid digits" +shell = "exa -lG" +environment = { "EXA_GRID_ROWS" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_grid_rows_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + + +# Invalid values for $EXA_ICON_SPACING + +[[cmd]] +name = "‘EXA_ICON_SPACING=999... exa --icons’ shows an error about the number size" +shell = "exa --icons" +environment = { "EXA_ICON_SPACING" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_icon_spacing_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env', 'icons' ] + +[[cmd]] +name = "‘EXA_ICON_SPACING=abcdef exa --icons’ shows an error about invalid digits" +shell = "exa --icons" +environment = { "EXA_ICON_SPACING" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_icon_spacing_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env', 'icons' ] + + +# Invalid values for --level (-L) + +[[cmd]] +name = "‘exa -TL999...’ shows an error about the number size" +shell = "exa -TL99999999999999999999999" +stdout = { empty = true } +stderr = { file = "outputs/error_level_nines.ansitxt" } +status = 3 +tags = [ 'error', 'tree', 'level' ] + +[[cmd]] +name = "‘exa -TLabcdef’ shows an error about invalid digits" +shell = "exa -TLabcdef" +stdout = { empty = true } +stderr = { file = "outputs/error_level_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'tree', 'level' ] diff --git a/xtests/git.toml b/xtests/git.toml index d6c0b71..c262e9e 100644 --- a/xtests/git.toml +++ b/xtests/git.toml @@ -101,13 +101,21 @@ status = 0 tags = [ 'long', 'git' ] [[cmd]] -name = "‘exa --git -l’ with an ignored directory argument does not flag the contents as ignored" +name = "‘exa --git -l’ with an ignored directory argument flags the contents as ignored" shell = "exa --git -l /testcases/git2/target" stdout = { file = "outputs/git2_long_ignoreddir.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'git' ] +[[cmd]] +name = "‘exa --git -l --list-dirs’ with a directory argument doesn’t flag it as ignored if only the content is" +shell = "exa --git -l --list-dirs /testcases/git2/ignoreds/nested2" +stdout = { file = "outputs/git2_long_ignoredcontent.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'git' ] + [[cmd]] name = "‘exa --git -l’ with a nested repository argument uses the sub-repository rules" shell = "exa --git -l /testcases/git2/deeply/nested/repository" @@ -155,7 +163,7 @@ status = 0 tags = [ 'long', 'git' ] [[cmd]] -name = "‘exa --git -l’ shows a Git status column for multiple repositories across multiple directories" +name = "‘exa --git -l’ shows a Git status column for multiple repositories across multiple directories 2" shell = "exa --git -l /testcases/{git2/deeply/nested/directory,git/edits,git2/target,git2/deeply,git}" stdout = { file = "outputs/git1+2_long_nested.ansitxt" } stderr = { empty = true } diff --git a/xtests/grid-details-view.toml b/xtests/grid-details-view.toml index a76ba15..3488acf 100644 --- a/xtests/grid-details-view.toml +++ b/xtests/grid-details-view.toml @@ -81,19 +81,49 @@ tags = [ 'env', 'long', 'grid' ] # check if exa is using the minimum number of columns with headers [[cmd]] -name = "‘COLUMN=200 exa -lGh’ with one file don’t produce extra columns even if there place for more" +name = "‘COLUMNS=200 exa -lGh’ with one file don’t produce extra columns even if there place for more" shell = "exa -lGh /testcases/files/10_bytes" environment = { COLUMNS = "200" } -stdout = { file = "outputs/files_paths_long_grid_header_1file.ansitxt" } +stdout = { file = "outputs/files_long_grid_header_1file.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'env', 'long', 'grid' ] [[cmd]] -name = "‘COLUMN=200 exa -lGh’ with several files don’t produce extra columns even if there place for more" +name = "‘COLUMNS=200 exa -lGh’ with several files don’t produce extra columns even if there place for more" shell = "exa -lGh /testcases/files/10_{bytes,KiB}" environment = { COLUMNS = "200" } -stdout = { file = "outputs/files_paths_long_grid_header_2files.ansitxt" } +stdout = { file = "outputs/files_long_grid_header_2files.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'env', 'long', 'grid' ] + + +# check if EXA_GRID_ROWS is working + +[[cmd]] +name = "‘COLUMNS=200 EXA_GRID_ROWS=2 exa -lG’ with three files produces a grid details of 1 column" +shell = "exa -lG /testcases/files/1_*" +environment = { COLUMNS = "200", EXA_GRID_ROWS = "2" } +stdout = { file = "outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'env', 'long', 'grid' ] + +[[cmd]] +name = "‘COLUMNS=200 EXA_GRID_ROWS=5 exa -lG’ with 15 files produces a grid details of 3 columns" +shell = "exa -lG /testcases/files/1*" +environment = { COLUMNS = "200", EXA_GRID_ROWS = "5" } +stdout = { file = "outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'env', 'long', 'grid' ] + +[[cmd]] +name = "‘COLUMNS=200 EXA_GRID_ROWS=6 exa -lG’ with 15 files produces a grid details of 1 column" +shell = "exa -lG /testcases/files/1*" +environment = { COLUMNS = "200", EXA_GRID_ROWS = "6" } +stdout = { file = "outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'env', 'long', 'grid' ] diff --git a/xtests/outputs/dates_long_currentyear_localefr.ansitxt b/xtests/outputs/dates_long_currentyear_localefr.ansitxt new file mode 100644 index 0000000..728df17 --- /dev/null +++ b/xtests/outputs/dates_long_currentyear_localefr.ansitxt @@ -0,0 +1,39 @@ +.rw-r--r-- 1 cassowary  1 janv. 12:34 1_bytes +.rw-r--r-- 1,0k cassowary  1 janv. 12:34 1_KiB +.rw-r--r-- 1,0M cassowary  1 janv. 12:34 1_MiB +.rw-r--r-- 2 cassowary  1 janv. 12:34 2_bytes +.rw-r--r-- 2,0k cassowary  1 janv. 12:34 2_KiB +.rw-r--r-- 2,1M cassowary  1 janv. 12:34 2_MiB +.rw-r--r-- 3 cassowary  1 janv. 12:34 3_bytes +.rw-r--r-- 3,1k cassowary  1 janv. 12:34 3_KiB +.rw-r--r-- 3,1M cassowary  1 janv. 12:34 3_MiB +.rw-r--r-- 4 cassowary  1 janv. 12:34 4_bytes +.rw-r--r-- 4,1k cassowary  1 janv. 12:34 4_KiB +.rw-r--r-- 4,2M cassowary  1 janv. 12:34 4_MiB +.rw-r--r-- 5 cassowary  1 janv. 12:34 5_bytes +.rw-r--r-- 5,1k cassowary  1 janv. 12:34 5_KiB +.rw-r--r-- 5,2M cassowary  1 janv. 12:34 5_MiB +.rw-r--r-- 6 cassowary  1 janv. 12:34 6_bytes +.rw-r--r-- 6,1k cassowary  1 janv. 12:34 6_KiB +.rw-r--r-- 6,3M cassowary  1 janv. 12:34 6_MiB +.rw-r--r-- 7 cassowary  1 janv. 12:34 7_bytes +.rw-r--r-- 7,2k cassowary  1 janv. 12:34 7_KiB +.rw-r--r-- 7,3M cassowary  1 janv. 12:34 7_MiB +.rw-r--r-- 8 cassowary  1 janv. 12:34 8_bytes +.rw-r--r-- 8,2k cassowary  1 janv. 12:34 8_KiB +.rw-r--r-- 8,4M cassowary  1 janv. 12:34 8_MiB +.rw-r--r-- 9 cassowary  1 janv. 12:34 9_bytes +.rw-r--r-- 9,2k cassowary  1 janv. 12:34 9_KiB +.rw-r--r-- 9,4M cassowary  1 janv. 12:34 9_MiB +.rw-r--r-- 10 cassowary  1 janv. 12:34 10_bytes +.rw-r--r-- 10k cassowary  1 janv. 12:34 10_KiB +.rw-r--r-- 10M cassowary  1 janv. 12:34 10_MiB +.rw-r--r-- 11 cassowary  1 janv. 12:34 11_bytes +.rw-r--r-- 11k cassowary  1 janv. 12:34 11_KiB +.rw-r--r-- 12M cassowary  1 janv. 12:34 11_MiB +.rw-r--r-- 12 cassowary  1 janv. 12:34 12_bytes +.rw-r--r-- 12k cassowary  1 janv. 12:34 12_KiB +.rw-r--r-- 13M cassowary  1 janv. 12:34 12_MiB +.rw-r--r-- 13 cassowary  1 janv. 12:34 13_bytes +.rw-r--r-- 13k cassowary  1 janv. 12:34 13_KiB +.rw-r--r-- 14M cassowary  1 janv. 12:34 13_MiB diff --git a/xtests/outputs/dev_long.ansitxt b/xtests/outputs/dev_long.ansitxt new file mode 100644 index 0000000..40128c6 --- /dev/null +++ b/xtests/outputs/dev_long.ansitxt @@ -0,0 +1,7 @@ +crw-r----- 1,1 root mem +crw-rw-rw- 1,3 root null +crw-r----- 1,4 root port +crw-rw-rw- 1,5 root zero +crw-rw-rw- 1,7 root full +crw-rw-rw- 1,8 root random +crw-rw-rw- 1,9 root urandom diff --git a/xtests/outputs/error_columns_invalid.ansitxt b/xtests/outputs/error_columns_invalid.ansitxt new file mode 100644 index 0000000..1455322 --- /dev/null +++ b/xtests/outputs/error_columns_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable COLUMNS: invalid digit found in string diff --git a/xtests/outputs/error_columns_nines.ansitxt b/xtests/outputs/error_columns_nines.ansitxt new file mode 100644 index 0000000..f1ecc7f --- /dev/null +++ b/xtests/outputs/error_columns_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable COLUMNS: number too large to fit in target type diff --git a/xtests/outputs/error_grid_rows_invalid.ansitxt b/xtests/outputs/error_grid_rows_invalid.ansitxt new file mode 100644 index 0000000..c1474d9 --- /dev/null +++ b/xtests/outputs/error_grid_rows_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable EXA_GRID_ROWS: invalid digit found in string diff --git a/xtests/outputs/error_grid_rows_nines.ansitxt b/xtests/outputs/error_grid_rows_nines.ansitxt new file mode 100644 index 0000000..35750bb --- /dev/null +++ b/xtests/outputs/error_grid_rows_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable EXA_GRID_ROWS: number too large to fit in target type diff --git a/xtests/outputs/error_icon_spacing_invalid.ansitxt b/xtests/outputs/error_icon_spacing_invalid.ansitxt new file mode 100644 index 0000000..aaec7f3 --- /dev/null +++ b/xtests/outputs/error_icon_spacing_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable EXA_ICON_SPACING: invalid digit found in string diff --git a/xtests/outputs/error_icon_spacing_nines.ansitxt b/xtests/outputs/error_icon_spacing_nines.ansitxt new file mode 100644 index 0000000..44f3ad1 --- /dev/null +++ b/xtests/outputs/error_icon_spacing_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable EXA_ICON_SPACING: number too large to fit in target type diff --git a/xtests/outputs/error_invalid_option.ansitxt b/xtests/outputs/error_invalid_option.ansitxt new file mode 100644 index 0000000..39825d4 --- /dev/null +++ b/xtests/outputs/error_invalid_option.ansitxt @@ -0,0 +1 @@ +exa: Unknown argument --aoeu diff --git a/xtests/outputs/error_level_invalid.ansitxt b/xtests/outputs/error_level_invalid.ansitxt new file mode 100644 index 0000000..d7f4a03 --- /dev/null +++ b/xtests/outputs/error_level_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for option --level (-L): invalid digit found in string diff --git a/xtests/outputs/error_level_nines.ansitxt b/xtests/outputs/error_level_nines.ansitxt new file mode 100644 index 0000000..895fc0a --- /dev/null +++ b/xtests/outputs/error_level_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for option --level (-L): number too large to fit in target type diff --git a/xtests/outputs/error_tree_all_all.ansitxt b/xtests/outputs/error_tree_all_all.ansitxt new file mode 100644 index 0000000..b7e21c2 --- /dev/null +++ b/xtests/outputs/error_tree_all_all.ansitxt @@ -0,0 +1 @@ +exa: Option --tree is useless given --all --all diff --git a/xtests/outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt b/xtests/outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt new file mode 100644 index 0000000..1a50d75 --- /dev/null +++ b/xtests/outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt @@ -0,0 +1,3 @@ +.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes +.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB +.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB diff --git a/xtests/outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt b/xtests/outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt new file mode 100644 index 0000000..e02074e --- /dev/null +++ b/xtests/outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt @@ -0,0 +1,5 @@ +.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes .rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/11_MiB .rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB +.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB .rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes .rw-r--r-- 14M cassowary  1 Jan 12:34 /testcases/files/13_MiB +.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB .rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB .rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes +.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes .rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/12_MiB .rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB +.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB .rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes .rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB diff --git a/xtests/outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt b/xtests/outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt new file mode 100644 index 0000000..98ff7d1 --- /dev/null +++ b/xtests/outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt @@ -0,0 +1,15 @@ +.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes +.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB +.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB +.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes +.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB +.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB +.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes +.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB +.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/11_MiB +.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes +.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB +.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/12_MiB +.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes +.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB +.rw-r--r-- 14M cassowary  1 Jan 12:34 /testcases/files/13_MiB diff --git a/xtests/outputs/files_paths_long_grid_header_1file.ansitxt b/xtests/outputs/files_long_grid_header_1file.ansitxt similarity index 100% rename from xtests/outputs/files_paths_long_grid_header_1file.ansitxt rename to xtests/outputs/files_long_grid_header_1file.ansitxt diff --git a/xtests/outputs/files_paths_long_grid_header_2files.ansitxt b/xtests/outputs/files_long_grid_header_2files.ansitxt similarity index 100% rename from xtests/outputs/files_paths_long_grid_header_2files.ansitxt rename to xtests/outputs/files_long_grid_header_2files.ansitxt diff --git a/xtests/outputs/git1+2_long_nested.ansitxt b/xtests/outputs/git1+2_long_nested.ansitxt index 186707a..21c8bb3 100644 --- a/xtests/outputs/git1+2_long_nested.ansitxt +++ b/xtests/outputs/git1+2_long_nested.ansitxt @@ -8,7 +8,7 @@ .rw-rw-r-- 20 cassowary  1 Jan 12:34 -M unstaged /testcases/git2/target: -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file /testcases/git2/deeply: drwxrwxr-x - cassowary  1 Jan 12:34 -N nested diff --git a/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt index 611f077..2ef959a 100644 --- a/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt @@ -1 +1 @@ -music.m4a nested +music.m4a nested nested2 diff --git a/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt index 97fab8c..ac6e7f3 100644 --- a/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt @@ -1,2 +1,3 @@ music.m4a nested +nested2 diff --git a/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt index 83a274f..710d840 100644 --- a/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt @@ -1,2 +1,3 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +drwxrwxr-x - cassowary  1 Jan 12:34 nested2 diff --git a/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt index ff8567b..5543504 100644 --- a/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt @@ -1 +1 @@ -.rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested drwxrwxr-x - cassowary  1 Jan 12:34 nested2 diff --git a/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt index 07df2c6..2ea2167 100644 --- a/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt @@ -1,5 +1,8 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +drwxrwxr-x - cassowary  1 Jan 12:34 nested2 /testcases/git2/ignoreds/nested: .rw-rw-r-- 0 cassowary  1 Jan 12:34 funky chicken.m4a + +/testcases/git2/ignoreds/nested2: diff --git a/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt index 39b5a1f..0c1605e 100644 --- a/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt @@ -1,4 +1,5 @@ drwxrwxr-x - cassowary  1 Jan 12:34 /testcases/git2/ignoreds .rw-rw-r-- 0 cassowary  1 Jan 12:34 ├── music.m4a -drwxrwxr-x - cassowary  1 Jan 12:34 └── nested -.rw-rw-r-- 0 cassowary  1 Jan 12:34  └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 ├── nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34 │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 └── nested2 diff --git a/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt index a727537..d9b969a 100644 --- a/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt @@ -1,4 +1,5 @@ /testcases/git2/ignoreds ├── music.m4a -└── nested - └── funky chicken.m4a +├── nested +│ └── funky chicken.m4a +└── nested2 diff --git a/xtests/outputs/git2_long_ignoredcontent.ansitxt b/xtests/outputs/git2_long_ignoredcontent.ansitxt new file mode 100644 index 0000000..238c3b0 --- /dev/null +++ b/xtests/outputs/git2_long_ignoredcontent.ansitxt @@ -0,0 +1 @@ +drwxrwxr-x - cassowary  1 Jan 12:34 -- /testcases/git2/ignoreds/nested2 diff --git a/xtests/outputs/git2_long_ignoreddir.ansitxt b/xtests/outputs/git2_long_ignoreddir.ansitxt index 6a636a0..fff9898 100644 --- a/xtests/outputs/git2_long_ignoreddir.ansitxt +++ b/xtests/outputs/git2_long_ignoreddir.ansitxt @@ -1 +1 @@ -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file diff --git a/xtests/outputs/git2_long_ignorednested.ansitxt b/xtests/outputs/git2_long_ignorednested.ansitxt index d44d313..6e81c36 100644 --- a/xtests/outputs/git2_long_ignorednested.ansitxt +++ b/xtests/outputs/git2_long_ignorednested.ansitxt @@ -1,3 +1,4 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I music.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -N nested +drwxrwxr-x - cassowary  1 Jan 12:34 -- nested2 diff --git a/xtests/outputs/git2_long_multiple.ansitxt b/xtests/outputs/git2_long_multiple.ansitxt index 280e8c9..8654aaf 100644 --- a/xtests/outputs/git2_long_multiple.ansitxt +++ b/xtests/outputs/git2_long_multiple.ansitxt @@ -5,6 +5,7 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I music.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -N nested +drwxrwxr-x - cassowary  1 Jan 12:34 -- nested2 /testcases/git2/target: -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file diff --git a/xtests/outputs/git2_long_recurse.ansitxt b/xtests/outputs/git2_long_recurse.ansitxt index fcee924..8eb1b3a 100644 --- a/xtests/outputs/git2_long_recurse.ansitxt +++ b/xtests/outputs/git2_long_recurse.ansitxt @@ -20,10 +20,14 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I music.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -N nested +drwxrwxr-x - cassowary  1 Jan 12:34 -- nested2 /testcases/git2/ignoreds/nested: .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I 70s grove.mp3 .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N funky chicken.m4a +/testcases/git2/ignoreds/nested2: +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I ievan polkka.mp3 + /testcases/git2/target: -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file diff --git a/xtests/outputs/git2_long_recurse_gitignore.ansitxt b/xtests/outputs/git2_long_recurse_gitignore.ansitxt index 5f98671..140808e 100644 --- a/xtests/outputs/git2_long_recurse_gitignore.ansitxt +++ b/xtests/outputs/git2_long_recurse_gitignore.ansitxt @@ -18,6 +18,9 @@ /testcases/git2/ignoreds: .rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +drwxrwxr-x - cassowary  1 Jan 12:34 nested2 /testcases/git2/ignoreds/nested: .rw-rw-r-- 0 cassowary  1 Jan 12:34 funky chicken.m4a + +/testcases/git2/ignoreds/nested2: diff --git a/xtests/outputs/git2_long_tree.ansitxt b/xtests/outputs/git2_long_tree.ansitxt index f206507..ca0d2bb 100644 --- a/xtests/outputs/git2_long_tree.ansitxt +++ b/xtests/outputs/git2_long_tree.ansitxt @@ -9,8 +9,10 @@ drwxrwxr-x - cassowary  1 Jan 12:34 -N ├── ignoreds .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N │ ├── music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ ├── music.mp3 -drwxrwxr-x - cassowary  1 Jan 12:34 -N │ └── nested -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ ├── 70s grove.mp3 -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -N │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 -N │ ├── nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ │ ├── 70s grove.mp3 +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -N │ │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 -- │ └── nested2 +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ └── ievan polkka.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -I └── target -.rw-rw-r-- 0 cassowary  1 Jan 12:34 --  └── another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I  └── another ignored file diff --git a/xtests/outputs/git2_long_tree_gitignore.ansitxt b/xtests/outputs/git2_long_tree_gitignore.ansitxt index 3513fea..824b459 100644 --- a/xtests/outputs/git2_long_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_long_tree_gitignore.ansitxt @@ -8,5 +8,6 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 │ └── subfile drwxrwxr-x - cassowary  1 Jan 12:34 └── ignoreds .rw-rw-r-- 0 cassowary  1 Jan 12:34  ├── music.m4a -drwxrwxr-x - cassowary  1 Jan 12:34  └── nested -.rw-rw-r-- 0 cassowary  1 Jan 12:34  └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34  ├── nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34  │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34  └── nested2 diff --git a/xtests/outputs/git2_tree_gitignore.ansitxt b/xtests/outputs/git2_tree_gitignore.ansitxt index b1a3f2f..053699b 100644 --- a/xtests/outputs/git2_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_tree_gitignore.ansitxt @@ -8,5 +8,6 @@ │ └── subfile └── ignoreds  ├── music.m4a - └── nested - └── funky chicken.m4a + ├── nested + │ └── funky chicken.m4a + └── nested2 diff --git a/xtests/outputs/help.ansitxt b/xtests/outputs/help.ansitxt index 750a66f..4e8cf52 100644 --- a/xtests/outputs/help.ansitxt +++ b/xtests/outputs/help.ansitxt @@ -20,7 +20,7 @@ DISPLAY OPTIONS FILTERING AND SORTING OPTIONS -a, --all show hidden and 'dot' files - -d, --list-dirs list directories like regular files + -d, --list-dirs list directories as files; don't list their contents -L, --level DEPTH limit the depth of recursion -r, --reverse reverse the sort order -s, --sort SORT_FIELD which field to sort by diff --git a/xtests/outputs/links_long_classify.ansitxt b/xtests/outputs/links_long_classify.ansitxt new file mode 100644 index 0000000..9747e04 --- /dev/null +++ b/xtests/outputs/links_long_classify.ansitxt @@ -0,0 +1,10 @@ +lrwxrwxrwx 7 vagrant broken -> nowhere +lrwxrwxrwx 1 vagrant current_dir -> ./ +lrwxrwxrwx 12 vagrant forbidden -> /proc/1/root +lrwxrwxrwx 6 vagrant itself -> itself +lrwxrwxrwx 2 vagrant parent_dir -> ../ +lrwxrwxrwx 1 vagrant root -> // +.rw-rw-r-- 0 vagrant some_file +lrwxrwxrwx 26 vagrant some_file_absolute -> /testcases/links/some_file +lrwxrwxrwx 9 vagrant some_file_relative -> some_file +lrwxrwxrwx 4 vagrant usr -> /usr/