diff --git a/README.md b/README.md index b9f546e..fac14ba 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ exa’s options are almost, but not quite, entirely unlike `ls`’s. - **--colo[u]r**: when to use terminal colours - **--colo[u]r-scale**: highlight levels of file sizes distinctly - **--icons**: display icons +- **--no-icons**: don't display icons (always overrides --icons) ### Filtering options @@ -82,6 +83,7 @@ These options are available when running with `--long` (`-l`): - **--git**: list each file’s Git status, if tracked or ignored - **--time-style**: how to format timestamps - **--no-permissions**: suppress the permissions field +- **--octal-permissions**: list each file's permission in octal format - **--no-filesize**: suppress the filesize field - **--no-user**: suppress the user field - **--no-time**: suppress the time field diff --git a/completions/completions.fish b/completions/completions.fish index 4126607..e868e8e 100755 --- a/completions/completions.fish +++ b/completions/completions.fish @@ -15,6 +15,7 @@ complete -c exa -l 'colour' -d "When to use terminal colours" complete -c exa -l 'color-scale' -d "Highlight levels of file sizes distinctly" complete -c exa -l 'colour-scale' -d "Highlight levels of file sizes distinctly" complete -c exa -l 'icons' -d "Display icons" +complete -c exa -l 'no-icons' -d "Don't display icons" # Filtering and sorting options complete -c exa -l 'group-directories-first' -d "Sort directories before other files" @@ -75,6 +76,7 @@ complete -c exa -l 'time-style' -x -d "How to format timestamps" -a " full-iso\t'Display full ISO timestamps, up to the nanosecond' " complete -c exa -l 'no-permissions' -d "Suppress the permissions field" +complete -c exa -l 'octal-permissions' -d "List each file's permission in octal format" complete -c exa -l 'no-filesize' -d "Suppress the filesize field" complete -c exa -l 'no-user' -d "Suppress the user field" complete -c exa -l 'no-time' -d "Suppress the time field" diff --git a/completions/completions.zsh b/completions/completions.zsh index a700d47..d51332e 100644 --- a/completions/completions.zsh +++ b/completions/completions.zsh @@ -22,6 +22,7 @@ __exa() { --colo{,u}r"[When to use terminal colours]" \ --colo{,u}r-scale"[Highlight levels of file sizes distinctly]" \ --icons"[Display icons]" \ + --no-icons"[Hide icons]" \ --group-directories-first"[Sort directories before other files]" \ --git-ignore"[Ignore files mentioned in '.gitignore']" \ {-a,--all}"[Show hidden and 'dot' files]" \ @@ -43,6 +44,7 @@ __exa() { {-t,--time}="[Which time field to show]:(time field):(accessed changed created modified)" \ --time-style="[How to format timestamps]:(time style):(default iso long-iso full-iso)" \ --no-permissions"[Suppress the permissions field]" \ + --octal-permissions"[List each file's permission in octal format]" \ --no-filesize"[Suppress the filesize field]" \ --no-user"[Suppress the user field]" \ --no-time"[Suppress the time field]" \ diff --git a/man/exa.1.md b/man/exa.1.md index a0a97de..3b89d0a 100644 --- a/man/exa.1.md +++ b/man/exa.1.md @@ -72,6 +72,9 @@ Valid settings are ‘`always`’, ‘`automatic`’, and ‘`never`’. `--icons` : Display icons next to file names. +`--no-icons` +: Don't display icons. (Always overrides --icons) + FILTERING AND SORTING OPTIONS ============================= @@ -101,7 +104,7 @@ Sort fields starting with a capital letter will sort uppercase before lowercase: `-I`, `--ignore-glob=GLOBS` : Glob patterns, pipe-separated, of files to ignore. -`--git-ignore` +`--git-ignore` [if exa was built with git support] : Do not list files that are ignored by Git. `--group-directories-first` @@ -174,7 +177,7 @@ These options are available when running with `--long` (`-l`): `-@`, `--extended` : List each file’s extended attributes and sizes. -`--git` +`--git` [if exa was built with git support] : List each file’s Git status, if tracked. diff --git a/src/fs/feature/mod.rs b/src/fs/feature/mod.rs index c4fc20e..10f4915 100644 --- a/src/fs/feature/mod.rs +++ b/src/fs/feature/mod.rs @@ -27,7 +27,7 @@ pub mod git { } pub fn get(&self, _index: &Path, _prefix_lookup: bool) -> f::Git { - panic!("Tried to query a Git cache, but Git support is disabled") + unreachable!(); } } } diff --git a/src/fs/feature/xattr.rs b/src/fs/feature/xattr.rs index 30343c7..b819d24 100644 --- a/src/fs/feature/xattr.rs +++ b/src/fs/feature/xattr.rs @@ -7,9 +7,7 @@ use std::io; use std::path::Path; -pub const ENABLED: bool = - cfg!(feature="git") && - cfg!(any(target_os = "macos", target_os = "linux")); +pub const ENABLED: bool = cfg!(any(target_os = "macos", target_os = "linux")); pub trait FileAttributes { diff --git a/src/main.rs b/src/main.rs index ad1a797..ac69533 100644 --- a/src/main.rs +++ b/src/main.rs @@ -264,13 +264,15 @@ impl<'args> Exa<'args> { match (mode, self.console_width) { (Mode::Grid(ref opts), Some(console_width)) => { - let r = grid::Render { files, theme, file_style, opts, console_width }; + let filter = &self.options.filter; + let r = grid::Render { files, theme, file_style, opts, console_width, filter }; r.render(&mut self.writer) } (Mode::Grid(_), None) | (Mode::Lines, _) => { - let r = lines::Render { files, theme, file_style }; + let filter = &self.options.filter; + let r = lines::Render { files, theme, file_style, filter }; r.render(&mut self.writer) } diff --git a/src/options/error.rs b/src/options/error.rs index 95f1771..2b724e1 100644 --- a/src/options/error.rs +++ b/src/options/error.rs @@ -16,7 +16,7 @@ pub enum OptionsError { /// The user supplied an illegal choice to an Argument. BadArgument(&'static Arg, OsString), - /// The user supplied a set of options + /// The user supplied a set of options that are unsupported Unsupported(String), /// An option was given twice or more in strict mode. diff --git a/src/options/file_name.rs b/src/options/file_name.rs index d29f454..96131bb 100644 --- a/src/options/file_name.rs +++ b/src/options/file_name.rs @@ -25,7 +25,7 @@ impl Classify { impl ShowIcons { pub fn deduce(matches: &MatchedFlags<'_>, vars: &V) -> Result { - if ! matches.has(&flags::ICONS)? { + if matches.has(&flags::NO_ICONS)? || !matches.has(&flags::ICONS)? { Ok(Self::Off) } else if let Some(columns) = vars.get(vars::EXA_ICON_SPACING).and_then(|s| s.into_string().ok()) { diff --git a/src/options/flags.rs b/src/options/flags.rs index 88d53da..16ab04a 100644 --- a/src/options/flags.rs +++ b/src/options/flags.rs @@ -58,6 +58,7 @@ pub static NO_PERMISSIONS: Arg = Arg { short: None, long: "no-permissions", take pub static NO_FILESIZE: Arg = Arg { short: None, long: "no-filesize", takes_value: TakesValue::Forbidden }; pub static NO_USER: Arg = Arg { short: None, long: "no-user", takes_value: TakesValue::Forbidden }; pub static NO_TIME: Arg = Arg { short: None, long: "no-time", takes_value: TakesValue::Forbidden }; +pub static NO_ICONS: Arg = Arg { short: None, long: "no-icons", takes_value: TakesValue::Forbidden }; // optional feature options pub static GIT: Arg = Arg { short: None, long: "git", takes_value: TakesValue::Forbidden }; @@ -76,7 +77,7 @@ pub static ALL_ARGS: Args = Args(&[ &BINARY, &BYTES, &GROUP, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED, &BLOCKS, &TIME, &ACCESSED, &CREATED, &TIME_STYLE, - &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, + &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &NO_ICONS, &GIT, &EXTENDED, &OCTAL ]); diff --git a/src/options/help.rs b/src/options/help.rs index d7b986a..dacf106 100644 --- a/src/options/help.rs +++ b/src/options/help.rs @@ -5,7 +5,7 @@ use crate::options::flags; use crate::options::parser::MatchedFlags; -static USAGE: &str = r##"Usage: +static USAGE_PART1: &str = "Usage: exa [options] [files...] META OPTIONS @@ -23,6 +23,7 @@ DISPLAY OPTIONS --colo[u]r=WHEN when to use terminal colours (always, auto, never) --colo[u]r-scale highlight levels of file sizes distinctly --icons display icons + --no-icons don't display icons (always overrides --icons) FILTERING AND SORTING OPTIONS -a, --all show hidden and 'dot' files @@ -32,8 +33,9 @@ FILTERING AND SORTING OPTIONS -s, --sort SORT_FIELD which field to sort by --group-directories-first list directories before other files -D, --only-dirs list only directories - -I, --ignore-glob GLOBS glob patterns (pipe-separated) of files to ignore - --git-ignore ignore files mentioned in '.gitignore' + -I, --ignore-glob GLOBS glob patterns (pipe-separated) of files to ignore"; + + static USAGE_PART2: &str = " \ Valid sort fields: name, Name, extension, Extension, size, type, modified, accessed, created, inode, and none. date, time, old, and new all refer to modified. @@ -56,10 +58,11 @@ LONG VIEW OPTIONS --octal-permissions list each file's permission in octal format --no-filesize suppress the filesize field --no-user suppress the user field - --no-time suppress the time field"##; + --no-time suppress the time field"; -static GIT_HELP: &str = r##" --git list each file's Git status, if tracked or ignored"##; -static EXTENDED_HELP: &str = r##" -@, --extended list each file's extended attributes and sizes"##; +static GIT_FILTER_HELP: &str = " --git-ignore ignore files mentioned in '.gitignore'"; +static GIT_VIEW_HELP: &str = " --git list each file's Git status, if tracked or ignored"; +static EXTENDED_HELP: &str = " -@, --extended list each file's extended attributes and sizes"; /// All the information needed to display the help text, which depends @@ -92,14 +95,20 @@ impl fmt::Display for HelpString { /// Format this help options into an actual string of help /// text to be displayed to the user. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - writeln!(f, "{}", USAGE)?; + write!(f, "{}", USAGE_PART1)?; - if cfg!(feature="git") { - writeln!(f, "{}", GIT_HELP)?; + if cfg!(feature = "git") { + write!(f, "\n{}", GIT_FILTER_HELP)?; + } + + write!(f, "\n{}", USAGE_PART2)?; + + if cfg!(feature = "git") { + write!(f, "\n{}", GIT_VIEW_HELP)?; } if xattr::ENABLED { - writeln!(f, "{}", EXTENDED_HELP)?; + write!(f, "\n{}", EXTENDED_HELP)?; } Ok(()) diff --git a/src/options/mod.rs b/src/options/mod.rs index ae974c4..26e9c81 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -176,6 +176,13 @@ impl Options { /// Determines the complete set of options based on the given command-line /// arguments, after they’ve been parsed. fn deduce(matches: &MatchedFlags<'_>, vars: &V) -> Result { + if cfg!(not(feature = "git")) && + matches.has_where_any(|f| f.matches(&flags::GIT) || f.matches(&flags::GIT_IGNORE)).is_some() { + return Err(OptionsError::Unsupported(format!( + "Options --git and --git-ignore can't be used because `git` feature was disabled in this build of exa" + ))); + } + let view = View::deduce(matches, vars)?; let dir_action = DirAction::deduce(matches, matches!(view.mode, Mode::Details(_)))?; let filter = FileFilter::deduce(matches)?; diff --git a/src/options/version.rs b/src/options/version.rs index 6d2e05e..3a52f70 100644 --- a/src/options/version.rs +++ b/src/options/version.rs @@ -31,7 +31,11 @@ impl VersionString { impl fmt::Display for VersionString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - writeln!(f, "{}", include!(concat!(env!("OUT_DIR"), "/version_string.txt"))) + writeln!( + f, + "{} (git support: {})", + include!(concat!(env!("OUT_DIR"), "/version_string.txt")), + if cfg!(feature = "git") { "enabled" } else { "disabled" }) } } diff --git a/src/options/view.rs b/src/options/view.rs index 9ad42ae..9c2ed13 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -91,7 +91,7 @@ impl Mode { } } - if cfg!(feature = "git") && matches.has(&flags::GIT)? { + if matches.has(&flags::GIT)? { return Err(OptionsError::Useless(&flags::GIT, false, &flags::LONG)); } else if matches.has(&flags::LEVEL)? && ! matches.has(&flags::RECURSE)? && ! matches.has(&flags::TREE)? { @@ -192,7 +192,7 @@ impl TableOptions { impl Columns { fn deduce(matches: &MatchedFlags<'_>) -> Result { let time_types = TimeTypes::deduce(matches)?; - let git = cfg!(feature = "git") && matches.has(&flags::GIT)?; + let git = matches.has(&flags::GIT)?; let blocks = matches.has(&flags::BLOCKS)?; let group = matches.has(&flags::GROUP)?; diff --git a/src/output/file_name.rs b/src/output/file_name.rs index 31bde71..fcf02f2 100644 --- a/src/output/file_name.rs +++ b/src/output/file_name.rs @@ -132,9 +132,9 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { bits.push(style.paint(file_icon)); match spaces_count { - 1 => bits.push(Style::default().paint(" ")), - 2 => bits.push(Style::default().paint(" ")), - n => bits.push(Style::default().paint(spaces(n))), + 1 => bits.push(style.paint(" ")), + 2 => bits.push(style.paint(" ")), + n => bits.push(style.paint(spaces(n))), } } diff --git a/src/output/grid.rs b/src/output/grid.rs index 952d909..290ee8b 100644 --- a/src/output/grid.rs +++ b/src/output/grid.rs @@ -3,6 +3,7 @@ use std::io::{self, Write}; use term_grid as tg; use crate::fs::File; +use crate::fs::filter::FileFilter; use crate::output::file_name::Options as FileStyle; use crate::theme::Theme; @@ -26,10 +27,11 @@ pub struct Render<'a> { pub file_style: &'a FileStyle, pub opts: &'a Options, pub console_width: usize, + pub filter: &'a FileFilter, } impl<'a> Render<'a> { - pub fn render(&self, w: &mut W) -> io::Result<()> { + pub fn render(mut self, w: &mut W) -> io::Result<()> { let mut grid = tg::Grid::new(tg::GridOptions { direction: self.opts.direction(), filling: tg::Filling::Spaces(2), @@ -37,6 +39,7 @@ impl<'a> Render<'a> { grid.reserve(self.files.len()); + self.filter.sort_files(&mut self.files); for file in &self.files { let filename = self.file_style.for_file(file, self.theme).paint(); diff --git a/src/output/icons.rs b/src/output/icons.rs index 09b285a..2a9373d 100644 --- a/src/output/icons.rs +++ b/src/output/icons.rs @@ -2,6 +2,8 @@ use ansi_term::Style; use crate::fs::File; use crate::info::filetype::FileExtensions; +use lazy_static::lazy_static; +use std::collections::HashMap; pub trait FileIcon { @@ -42,156 +44,293 @@ pub fn iconify_style<'a>(style: Style) -> Style { } + +lazy_static! { + static ref MAP_BY_NAME: HashMap<&'static str, char> = { + let mut m = HashMap::new(); + m.insert(".Trash", '\u{f1f8}'); //  + m.insert(".atom", '\u{e764}'); //  + m.insert(".bashprofile", '\u{e615}'); //  + m.insert(".bashrc", '\u{f489}'); //  + m.insert(".git", '\u{f1d3}'); //  + m.insert(".gitattributes", '\u{f1d3}'); //  + m.insert(".gitconfig", '\u{f1d3}'); //  + m.insert(".github", '\u{f408}'); //  + m.insert(".gitignore", '\u{f1d3}'); //  + m.insert(".gitmodules", '\u{f1d3}'); //  + m.insert(".rvm", '\u{e21e}'); //  + m.insert(".vimrc", '\u{e62b}'); //  + m.insert(".vscode", '\u{e70c}'); //  + m.insert(".zshrc", '\u{f489}'); //  + m.insert("Cargo.lock", '\u{e7a8}'); //  + m.insert("bin", '\u{e5fc}'); //  + m.insert("config", '\u{e5fc}'); //  + m.insert("docker-compose.yml", '\u{f308}'); //  + m.insert("Dockerfile", '\u{f308}'); //  + m.insert("ds_store", '\u{f179}'); //  + m.insert("gitignore_global", '\u{f1d3}'); //  + m.insert("gradle", '\u{e70e}'); //  + m.insert("gruntfile.coffee", '\u{e611}'); //  + m.insert("gruntfile.js", '\u{e611}'); //  + m.insert("gruntfile.ls", '\u{e611}'); //  + m.insert("gulpfile.coffee", '\u{e610}'); //  + m.insert("gulpfile.js", '\u{e610}'); //  + m.insert("gulpfile.ls", '\u{e610}'); //  + m.insert("hidden", '\u{f023}'); //  + m.insert("include", '\u{e5fc}'); //  + m.insert("lib", '\u{f121}'); //  + m.insert("localized", '\u{f179}'); //  + m.insert("Makefile", '\u{e779}'); //  + m.insert("node_modules", '\u{e718}'); //  + m.insert("npmignore", '\u{e71e}'); //  + m.insert("rubydoc", '\u{e73b}'); //  + m.insert("yarn.lock", '\u{e718}'); //  + + m + }; +} + pub fn icon_for_file(file: &File<'_>) -> char { let extensions = Box::new(FileExtensions); - if file.points_to_directory() { - '\u{f115}' - } - else if let Some(icon) = extensions.icon_file(file) { - icon + if let Some(icon) = MAP_BY_NAME.get(file.name.as_str()) { *icon } + else if file.points_to_directory() { + match file.name.as_str() { + "bin" => '\u{e5fc}', //  + ".git" => '\u{f1d3}', //  + ".idea" => '\u{e7b5}', //  + _ => '\u{f115}' //  + } } + else if let Some(icon) = extensions.icon_file(file) { icon } else if let Some(ext) = file.ext.as_ref() { match ext.as_str() { - "ai" => '\u{e7b4}', - "android" => '\u{e70e}', - "apple" => '\u{f179}', - "avro" => '\u{e60b}', - "clj" => '\u{e768}', - "coffee" => '\u{f0f4}', - "cpp" => '\u{e61d}', - "hpp" => '\u{e61d}', - "c" => '\u{e61e}', - "h" => '\u{e61e}', - "cs" => '\u{f81a}', - "css" => '\u{e749}', - "d" => '\u{e7af}', - "dart" => '\u{e798}', - "db" => '\u{f1c0}', - "diff" => '\u{f440}', - "patch" => '\u{f440}', - "rtf" => '\u{f1c2}', - "doc" => '\u{f1c2}', - "docx" => '\u{f1c2}', - "odt" => '\u{f1c2}', - "ebook" => '\u{e28b}', - "env" => '\u{f462}', - "epub" => '\u{e28a}', - "erl" => '\u{e7b1}', - "font" => '\u{f031}', - "gform" => '\u{f298}', - "git" => '\u{f1d3}', - "go" => '\u{e626}', - "hs" => '\u{e777}', - "htm" => '\u{f13b}', - "html" => '\u{f13b}', - "xhtml" => '\u{f13b}', - "iml" => '\u{e7b5}', - "java" => '\u{e204}', - "js" => '\u{e74e}', - "mjs" => '\u{e74e}', - "json" => '\u{e60b}', - "jsx" => '\u{e7ba}', - "vue" => '\u{fd42}', - "node" => '\u{f898}', - "less" => '\u{e758}', - "log" => '\u{f18d}', - "lua" => '\u{e620}', - "md" => '\u{f48a}', - "markdown" => '\u{f48a}', - "mustache" => '\u{e60f}', - "npmignore" => '\u{e71e}', - "pdf" => '\u{f1c1}', - "djvu" => '\u{f02d}', - "mobi" => '\u{f02d}', - "php" => '\u{e73d}', - "pl" => '\u{e769}', - "ppt" => '\u{f1c4}', - "pptx" => '\u{f1c4}', - "odp" => '\u{f1c4}', - "psd" => '\u{e7b8}', - "py" => '\u{e606}', - "r" => '\u{f25d}', - "rb" => '\u{e21e}', - "ru" => '\u{e21e}', - "erb" => '\u{e21e}', - "gem" => '\u{e21e}', - "rdb" => '\u{e76d}', - "rs" => '\u{e7a8}', - "rss" => '\u{f09e}', - "rubydoc" => '\u{e73b}', - "sass" => '\u{e74b}', - "stylus" => '\u{e759}', - "scala" => '\u{e737}', - "shell" => '\u{f489}', - "sqlite3" => '\u{e7c4}', - "styl" => '\u{e600}', - "latex" => '\u{e600}', - "tex" => '\u{e600}', - "ts" => '\u{e628}', - "tsx" => '\u{e628}', - "twig" => '\u{e61c}', - "txt" => '\u{f15c}', - "video" => '\u{f03d}', - "vim" => '\u{e62b}', - "xml" => '\u{e619}', - "yml" => '\u{f481}', - "yaml" => '\u{f481}', - "rar" => '\u{f410}', - "zip" => '\u{f410}', - "bz" => '\u{f410}', - "bz2" => '\u{f410}', - "xz" => '\u{f410}', - "taz" => '\u{f410}', - "tbz" => '\u{f410}', - "tbz2" => '\u{f410}', - "tz" => '\u{f410}', - "tar" => '\u{f410}', - "tzo" => '\u{f410}', - "lz" => '\u{f410}', - "lzh" => '\u{f410}', - "lzma" => '\u{f410}', - "lzo" => '\u{f410}', - "gz" => '\u{f410}', - "deb" => '\u{e77d}', - "rpm" => '\u{e7bb}', - "exe" => '\u{e70f}', - "msi" => '\u{e70f}', - "dll" => '\u{e70f}', - "cab" => '\u{e70f}', - "bat" => '\u{e70f}', - "cmd" => '\u{e70f}', - "sh" => '\u{f489}', - "bash" => '\u{f489}', - "zsh" => '\u{f489}', - "fish" => '\u{f489}', - "csh" => '\u{f489}', - "ini" => '\u{e615}', - "toml" => '\u{e615}', - "cfg" => '\u{e615}', - "conf" => '\u{e615}', - "apk" => '\u{e70e}', - "ttf" => '\u{f031}', - "woff" => '\u{f031}', - "woff2" => '\u{f031}', - "otf" => '\u{f031}', - "csv" => '\u{f1c3}', - "tsv" => '\u{f1c3}', - "xls" => '\u{f1c3}', - "xlsx" => '\u{f1c3}', - "ods" => '\u{f1c3}', - "so" => '\u{f17c}', - "sql" => '\u{f1c0}', - "jar" => '\u{e256}', - "jad" => '\u{e256}', - "class" => '\u{e256}', - "war" => '\u{e256}', - "groovy" => '\u{e775}', - "iso" => '\u{e271}', - "lock" => '\u{f023}', - "swift" => '\u{e755}', - "nix" => '\u{f313}', - _ => '\u{f016}' + "ai" => '\u{e7b4}', //  + "android" => '\u{e70e}', //  + "apk" => '\u{e70e}', //  + "apple" => '\u{f179}', //  + "avi" => '\u{f03d}', //  + "avro" => '\u{e60b}', //  + "awk" => '\u{f489}', //  + "bash" => '\u{f489}', //  + "bash_history" => '\u{f489}', //  + "bash_profile" => '\u{f489}', //  + "bashrc" => '\u{f489}', //  + "bat" => '\u{f17a}', //  + "bmp" => '\u{f1c5}', //  + "bz" => '\u{f410}', //  + "bz2" => '\u{f410}', //  + "c" => '\u{e61e}', //  + "c++" => '\u{e61d}', //  + "cab" => '\u{e70f}', //  + "cc" => '\u{e61d}', //  + "cfg" => '\u{e615}', //  + "class" => '\u{e256}', //  + "clj" => '\u{e768}', //  + "cljs" => '\u{e76a}', //  + "cls" => '\u{e600}', //  + "cmd" => '\u{e70f}', //  + "coffee" => '\u{f0f4}', //  + "conf" => '\u{e615}', //  + "cp" => '\u{e61d}', //  + "cpp" => '\u{e61d}', //  + "cs" => '\u{f81a}', //  + "csh" => '\u{f489}', //  + "cshtml" => '\u{f1fa}', //  + "csproj" => '\u{f81a}', //  + "css" => '\u{e749}', //  + "csv" => '\u{f1c3}', //  + "csx" => '\u{f81a}', //  + "cxx" => '\u{e61d}', //  + "d" => '\u{e7af}', //  + "dart" => '\u{e798}', //  + "db" => '\u{f1c0}', //  + "deb" => '\u{e77d}', //  + "diff" => '\u{f440}', //  + "djvu" => '\u{f02d}', //  + "dll" => '\u{e70f}', //  + "doc" => '\u{f1c2}', //  + "docx" => '\u{f1c2}', //  + "ds_store" => '\u{f179}', //  + "DS_store" => '\u{f179}', //  + "dump" => '\u{f1c0}', //  + "ebook" => '\u{e28b}', //  + "editorconfig" => '\u{e615}', //  + "ejs" => '\u{e618}', //  + "elm" => '\u{e62c}', //  + "env" => '\u{f462}', //  + "eot" => '\u{f031}', //  + "epub" => '\u{e28a}', //  + "erb" => '\u{e73b}', //  + "erl" => '\u{e7b1}', //  + "ex" => '\u{e62d}', //  + "exe" => '\u{f17a}', //  + "exs" => '\u{e62d}', //  + "fish" => '\u{f489}', //  + "flac" => '\u{f001}', //  + "flv" => '\u{f03d}', //  + "font" => '\u{f031}', //  + "gdoc" => '\u{f1c2}', //  + "gem" => '\u{e21e}', //  + "gemfile" => '\u{e21e}', //  + "gemspec" => '\u{e21e}', //  + "gform" => '\u{f298}', //  + "gif" => '\u{f1c5}', //  + "git" => '\u{f1d3}', //  + "gitattributes" => '\u{f1d3}', //  + "gitignore" => '\u{f1d3}', //  + "gitmodules" => '\u{f1d3}', //  + "go" => '\u{e626}', //  + "gradle" => '\u{e70e}', //  + "groovy" => '\u{e775}', //  + "gsheet" => '\u{f1c3}', //  + "gslides" => '\u{f1c4}', //  + "guardfile" => '\u{e21e}', //  + "gz" => '\u{f410}', //  + "h" => '\u{f0fd}', //  + "hbs" => '\u{e60f}', //  + "hpp" => '\u{f0fd}', //  + "hs" => '\u{e777}', //  + "htm" => '\u{f13b}', //  + "html" => '\u{f13b}', //  + "hxx" => '\u{f0fd}', //  + "ico" => '\u{f1c5}', //  + "image" => '\u{f1c5}', //  + "iml" => '\u{e7b5}', //  + "ini" => '\u{f17a}', //  + "ipynb" => '\u{e606}', //  + "iso" => '\u{e271}', //  + "jad" => '\u{e256}', //  + "jar" => '\u{e204}', //  + "java" => '\u{e204}', //  + "jpeg" => '\u{f1c5}', //  + "jpg" => '\u{f1c5}', //  + "js" => '\u{e74e}', //  + "json" => '\u{e60b}', //  + "jsx" => '\u{e7ba}', //  + "ksh" => '\u{f489}', //  + "latex" => '\u{e600}', //  + "less" => '\u{e758}', //  + "lhs" => '\u{e777}', //  + "license" => '\u{f718}', //  + "localized" => '\u{f179}', //  + "lock" => '\u{f023}', //  + "log" => '\u{f18d}', //  + "lua" => '\u{e620}', //  + "lz" => '\u{f410}', //  + "lzh" => '\u{f410}', //  + "lzma" => '\u{f410}', //  + "lzo" => '\u{f410}', //  + "m" => '\u{e61e}', //  + "mm" => '\u{e61d}', //  + "m4a" => '\u{f001}', //  + "markdown" => '\u{f48a}', //  + "md" => '\u{f48a}', //  + "mjs" => '\u{e74e}', //  + "mkd" => '\u{f48a}', //  + "mkv" => '\u{f03d}', //  + "mobi" => '\u{e28b}', //  + "mov" => '\u{f03d}', //  + "mp3" => '\u{f001}', //  + "mp4" => '\u{f03d}', //  + "msi" => '\u{e70f}', //  + "mustache" => '\u{e60f}', //  + "nix" => '\u{f313}', //  + "node" => '\u{f898}', //  + "npmignore" => '\u{e71e}', //  + "odp" => '\u{f1c4}', //  + "ods" => '\u{f1c3}', //  + "odt" => '\u{f1c2}', //  + "ogg" => '\u{f001}', //  + "ogv" => '\u{f03d}', //  + "otf" => '\u{f031}', //  + "patch" => '\u{f440}', //  + "pdf" => '\u{f1c1}', //  + "php" => '\u{e73d}', //  + "pl" => '\u{e769}', //  + "png" => '\u{f1c5}', //  + "ppt" => '\u{f1c4}', //  + "pptx" => '\u{f1c4}', //  + "procfile" => '\u{e21e}', //  + "properties" => '\u{e60b}', //  + "ps1" => '\u{f489}', //  + "psd" => '\u{e7b8}', //  + "pxm" => '\u{f1c5}', //  + "py" => '\u{e606}', //  + "pyc" => '\u{e606}', //  + "r" => '\u{f25d}', //  + "rakefile" => '\u{e21e}', //  + "rar" => '\u{f410}', //  + "razor" => '\u{f1fa}', //  + "rb" => '\u{e21e}', //  + "rdata" => '\u{f25d}', //  + "rdb" => '\u{e76d}', //  + "rdoc" => '\u{f48a}', //  + "rds" => '\u{f25d}', //  + "readme" => '\u{f48a}', //  + "rlib" => '\u{e7a8}', //  + "rmd" => '\u{f48a}', //  + "rpm" => '\u{e7bb}', //  + "rs" => '\u{e7a8}', //  + "rspec" => '\u{e21e}', //  + "rspec_parallel"=> '\u{e21e}', //  + "rspec_status" => '\u{e21e}', //  + "rss" => '\u{f09e}', //  + "rtf" => '\u{f718}', //  + "ru" => '\u{e21e}', //  + "rubydoc" => '\u{e73b}', //  + "sass" => '\u{e603}', //  + "scala" => '\u{e737}', //  + "scss" => '\u{e749}', //  + "sh" => '\u{f489}', //  + "shell" => '\u{f489}', //  + "slim" => '\u{e73b}', //  + "sln" => '\u{e70c}', //  + "so" => '\u{f17c}', //  + "sql" => '\u{f1c0}', //  + "sqlite3" => '\u{e7c4}', //  + "styl" => '\u{e600}', //  + "stylus" => '\u{e600}', //  + "svg" => '\u{f1c5}', //  + "swift" => '\u{e755}', //  + "tar" => '\u{f410}', //  + "taz" => '\u{f410}', //  + "tbz" => '\u{f410}', //  + "tbz2" => '\u{f410}', //  + "tex" => '\u{e600}', //  + "tiff" => '\u{f1c5}', //  + "toml" => '\u{e615}', //  + "ts" => '\u{e628}', //  + "tsv" => '\u{f1c3}', //  + "tsx" => '\u{e7ba}', //  + "ttf" => '\u{f031}', //  + "twig" => '\u{e61c}', //  + "txt" => '\u{f15c}', //  + "tz" => '\u{f410}', //  + "tzo" => '\u{f410}', //  + "video" => '\u{f03d}', //  + "vim" => '\u{e62b}', //  + "vue" => '\u{fd42}', // ﵂ + "war" => '\u{e256}', //  + "wav" => '\u{f001}', //  + "webm" => '\u{f03d}', //  + "webp" => '\u{f1c5}', //  + "windows" => '\u{f17a}', //  + "woff" => '\u{f031}', //  + "woff2" => '\u{f031}', //  + "xhtml" => '\u{f13b}', //  + "xls" => '\u{f1c3}', //  + "xlsx" => '\u{f1c3}', //  + "xml" => '\u{fabf}', // 謹 + "xul" => '\u{fabf}', // 謹 + "xz" => '\u{f410}', //  + "yaml" => '\u{f481}', //  + "yml" => '\u{f481}', //  + "zip" => '\u{f410}', //  + "zsh" => '\u{f489}', //  + "zsh-theme" => '\u{f489}', //  + "zshrc" => '\u{f489}', //  + _ => '\u{f15b}' //  } } else { diff --git a/src/output/lines.rs b/src/output/lines.rs index 9304a84..2343ce5 100644 --- a/src/output/lines.rs +++ b/src/output/lines.rs @@ -3,6 +3,7 @@ use std::io::{self, Write}; use ansi_term::ANSIStrings; use crate::fs::File; +use crate::fs::filter::FileFilter; use crate::output::cell::TextCellContents; use crate::output::file_name::{Options as FileStyle}; use crate::theme::Theme; @@ -13,10 +14,12 @@ pub struct Render<'a> { pub files: Vec>, pub theme: &'a Theme, pub file_style: &'a FileStyle, + pub filter: &'a FileFilter, } impl<'a> Render<'a> { - pub fn render(&self, w: &mut W) -> io::Result<()> { + pub fn render(mut self, w: &mut W) -> io::Result<()> { + self.filter.sort_files(&mut self.files); for file in &self.files { let name_cell = self.render_file(file); writeln!(w, "{}", ANSIStrings(&name_cell))?; diff --git a/src/output/table.rs b/src/output/table.rs index d77660d..af1061c 100644 --- a/src/output/table.rs +++ b/src/output/table.rs @@ -107,7 +107,7 @@ impl Columns { columns.push(Column::Timestamp(TimeType::Accessed)); } - if cfg!(feature = "git") && self.git && actually_enable_git { + if self.git && actually_enable_git { columns.push(Column::GitStatus); } diff --git a/xtests/grid-view.toml b/xtests/grid-view.toml index 978c5a9..05986b1 100644 --- a/xtests/grid-view.toml +++ b/xtests/grid-view.toml @@ -102,8 +102,7 @@ tags = [ 'env', 'grid' ] # columns and width tests with files -# (these rely on bash’s glob sort order) -# (some of the output files also have trailing whitespace) +# (warning: some of the output files have trailing whitespace) [[cmd]] name = "‘COLUMNS=100 exa’ with file arguments produces a grid of 3 columns, with full paths" diff --git a/xtests/outputs/exts_grid_sort_name_reverse.ansitxt b/xtests/outputs/exts_grid_sort_name_reverse.ansitxt new file mode 100644 index 0000000..93f07de --- /dev/null +++ b/xtests/outputs/exts_grid_sort_name_reverse.ansitxt @@ -0,0 +1,6 @@ +video.wmv lossless.flac crypto.signature compressed.tar.gz backup~ +VIDEO.AVI image.svg crypto.asc compressed.deb #SAVEFILE# +MUSIC.OGG IMAGE.PNG COMPRESSED.ZIP compiled.o +music.mp3 file.tmp compressed.txz compiled.js +Makefile DOCUMENT.XLSX compressed.tgz compiled.coffee +lossless.wav document.pdf compressed.tar.xz compiled.class diff --git a/xtests/outputs/exts_oneline_sort_name_reverse.ansitxt b/xtests/outputs/exts_oneline_sort_name_reverse.ansitxt new file mode 100644 index 0000000..f335667 --- /dev/null +++ b/xtests/outputs/exts_oneline_sort_name_reverse.ansitxt @@ -0,0 +1,26 @@ +video.wmv +VIDEO.AVI +MUSIC.OGG +music.mp3 +Makefile +lossless.wav +lossless.flac +image.svg +IMAGE.PNG +file.tmp +DOCUMENT.XLSX +document.pdf +crypto.signature +crypto.asc +COMPRESSED.ZIP +compressed.txz +compressed.tgz +compressed.tar.xz +compressed.tar.gz +compressed.deb +compiled.o +compiled.js +compiled.coffee +compiled.class +backup~ +#SAVEFILE# diff --git a/xtests/outputs/files_paths_grid_3col.ansitxt b/xtests/outputs/files_paths_grid_3col.ansitxt index 5523127..5990274 100644 --- a/xtests/outputs/files_paths_grid_3col.ansitxt +++ b/xtests/outputs/files_paths_grid_3col.ansitxt @@ -1,13 +1,13 @@ -/testcases/files/10_bytes /testcases/files/1_KiB /testcases/files/5_MiB -/testcases/files/10_KiB /testcases/files/1_MiB /testcases/files/6_bytes -/testcases/files/10_MiB /testcases/files/2_bytes /testcases/files/6_KiB -/testcases/files/11_bytes /testcases/files/2_KiB /testcases/files/6_MiB -/testcases/files/11_KiB /testcases/files/2_MiB /testcases/files/7_bytes -/testcases/files/11_MiB /testcases/files/3_bytes /testcases/files/7_KiB -/testcases/files/12_bytes /testcases/files/3_KiB /testcases/files/7_MiB -/testcases/files/12_KiB /testcases/files/3_MiB /testcases/files/8_bytes -/testcases/files/12_MiB /testcases/files/4_bytes /testcases/files/8_KiB -/testcases/files/13_bytes /testcases/files/4_KiB /testcases/files/8_MiB -/testcases/files/13_KiB /testcases/files/4_MiB /testcases/files/9_bytes -/testcases/files/13_MiB /testcases/files/5_bytes /testcases/files/9_KiB -/testcases/files/1_bytes /testcases/files/5_KiB /testcases/files/9_MiB +/testcases/files/1_bytes /testcases/files/5_KiB /testcases/files/9_MiB +/testcases/files/1_KiB /testcases/files/5_MiB /testcases/files/10_bytes +/testcases/files/1_MiB /testcases/files/6_bytes /testcases/files/10_KiB +/testcases/files/2_bytes /testcases/files/6_KiB /testcases/files/10_MiB +/testcases/files/2_KiB /testcases/files/6_MiB /testcases/files/11_bytes +/testcases/files/2_MiB /testcases/files/7_bytes /testcases/files/11_KiB +/testcases/files/3_bytes /testcases/files/7_KiB /testcases/files/11_MiB +/testcases/files/3_KiB /testcases/files/7_MiB /testcases/files/12_bytes +/testcases/files/3_MiB /testcases/files/8_bytes /testcases/files/12_KiB +/testcases/files/4_bytes /testcases/files/8_KiB /testcases/files/12_MiB +/testcases/files/4_KiB /testcases/files/8_MiB /testcases/files/13_bytes +/testcases/files/4_MiB /testcases/files/9_bytes /testcases/files/13_KiB +/testcases/files/5_bytes /testcases/files/9_KiB /testcases/files/13_MiB diff --git a/xtests/outputs/files_paths_grid_5col.ansitxt b/xtests/outputs/files_paths_grid_5col.ansitxt index eac4bde..a71bc94 100644 --- a/xtests/outputs/files_paths_grid_5col.ansitxt +++ b/xtests/outputs/files_paths_grid_5col.ansitxt @@ -1,8 +1,8 @@ -/testcases/files/10_bytes /testcases/files/12_MiB /testcases/files/2_KiB /testcases/files/5_bytes /testcases/files/7_MiB -/testcases/files/10_KiB /testcases/files/13_bytes /testcases/files/2_MiB /testcases/files/5_KiB /testcases/files/8_bytes -/testcases/files/10_MiB /testcases/files/13_KiB /testcases/files/3_bytes /testcases/files/5_MiB /testcases/files/8_KiB -/testcases/files/11_bytes /testcases/files/13_MiB /testcases/files/3_KiB /testcases/files/6_bytes /testcases/files/8_MiB -/testcases/files/11_KiB /testcases/files/1_bytes /testcases/files/3_MiB /testcases/files/6_KiB /testcases/files/9_bytes -/testcases/files/11_MiB /testcases/files/1_KiB /testcases/files/4_bytes /testcases/files/6_MiB /testcases/files/9_KiB -/testcases/files/12_bytes /testcases/files/1_MiB /testcases/files/4_KiB /testcases/files/7_bytes /testcases/files/9_MiB -/testcases/files/12_KiB /testcases/files/2_bytes /testcases/files/4_MiB /testcases/files/7_KiB +/testcases/files/1_bytes /testcases/files/3_MiB /testcases/files/6_KiB /testcases/files/9_bytes /testcases/files/11_MiB +/testcases/files/1_KiB /testcases/files/4_bytes /testcases/files/6_MiB /testcases/files/9_KiB /testcases/files/12_bytes +/testcases/files/1_MiB /testcases/files/4_KiB /testcases/files/7_bytes /testcases/files/9_MiB /testcases/files/12_KiB +/testcases/files/2_bytes /testcases/files/4_MiB /testcases/files/7_KiB /testcases/files/10_bytes /testcases/files/12_MiB +/testcases/files/2_KiB /testcases/files/5_bytes /testcases/files/7_MiB /testcases/files/10_KiB /testcases/files/13_bytes +/testcases/files/2_MiB /testcases/files/5_KiB /testcases/files/8_bytes /testcases/files/10_MiB /testcases/files/13_KiB +/testcases/files/3_bytes /testcases/files/5_MiB /testcases/files/8_KiB /testcases/files/11_bytes /testcases/files/13_MiB +/testcases/files/3_KiB /testcases/files/6_bytes /testcases/files/8_MiB /testcases/files/11_KiB diff --git a/xtests/outputs/files_paths_grid_7col.ansitxt b/xtests/outputs/files_paths_grid_7col.ansitxt index 7e9264f..1f8fbae 100644 --- a/xtests/outputs/files_paths_grid_7col.ansitxt +++ b/xtests/outputs/files_paths_grid_7col.ansitxt @@ -1,6 +1,6 @@ -/testcases/files/10_bytes /testcases/files/12_bytes /testcases/files/1_bytes /testcases/files/3_bytes /testcases/files/5_bytes /testcases/files/7_bytes /testcases/files/9_bytes -/testcases/files/10_KiB /testcases/files/12_KiB /testcases/files/1_KiB /testcases/files/3_KiB /testcases/files/5_KiB /testcases/files/7_KiB /testcases/files/9_KiB -/testcases/files/10_MiB /testcases/files/12_MiB /testcases/files/1_MiB /testcases/files/3_MiB /testcases/files/5_MiB /testcases/files/7_MiB /testcases/files/9_MiB -/testcases/files/11_bytes /testcases/files/13_bytes /testcases/files/2_bytes /testcases/files/4_bytes /testcases/files/6_bytes /testcases/files/8_bytes -/testcases/files/11_KiB /testcases/files/13_KiB /testcases/files/2_KiB /testcases/files/4_KiB /testcases/files/6_KiB /testcases/files/8_KiB -/testcases/files/11_MiB /testcases/files/13_MiB /testcases/files/2_MiB /testcases/files/4_MiB /testcases/files/6_MiB /testcases/files/8_MiB +/testcases/files/1_bytes /testcases/files/3_bytes /testcases/files/5_bytes /testcases/files/7_bytes /testcases/files/9_bytes /testcases/files/11_bytes /testcases/files/13_bytes +/testcases/files/1_KiB /testcases/files/3_KiB /testcases/files/5_KiB /testcases/files/7_KiB /testcases/files/9_KiB /testcases/files/11_KiB /testcases/files/13_KiB +/testcases/files/1_MiB /testcases/files/3_MiB /testcases/files/5_MiB /testcases/files/7_MiB /testcases/files/9_MiB /testcases/files/11_MiB /testcases/files/13_MiB +/testcases/files/2_bytes /testcases/files/4_bytes /testcases/files/6_bytes /testcases/files/8_bytes /testcases/files/10_bytes /testcases/files/12_bytes +/testcases/files/2_KiB /testcases/files/4_KiB /testcases/files/6_KiB /testcases/files/8_KiB /testcases/files/10_KiB /testcases/files/12_KiB +/testcases/files/2_MiB /testcases/files/4_MiB /testcases/files/6_MiB /testcases/files/8_MiB /testcases/files/10_MiB /testcases/files/12_MiB diff --git a/xtests/sorting.toml b/xtests/sorting.toml index f25d798..b81bde3 100644 --- a/xtests/sorting.toml +++ b/xtests/sorting.toml @@ -136,3 +136,22 @@ stdout = { string = "plum\npear\npeach" } stderr = { empty = true } status = 0 tags = [ 'oneline', 'sort', 'dates' ] + +# sorting with arguments specified + +[[cmd]] +name = "‘exa -G --sort=name -r’ with file arguments sorts by file name in reverse order" +shell = "cd /testcases/file-names-exts; exa -G --sort=name -r *" +environment = { COLUMNS = "80" } +stdout = { file = "outputs/exts_grid_sort_name_reverse.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'grid', 'sort', 'reverse' ] + +[[cmd]] +name = "‘exa -1 --sort=name -r’ with file arguments sorts by file name in reverse order" +shell = "cd /testcases/file-names-exts; exa -1 --sort=name -r *" +stdout = { file = "outputs/exts_oneline_sort_name_reverse.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'oneline', 'sort', 'reverse' ]