2017-06-23 21:50:29 +00:00
|
|
|
|
use std::fmt;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
2017-08-05 13:33:32 +00:00
|
|
|
|
use options::flags;
|
2017-08-05 18:11:00 +00:00
|
|
|
|
use options::parser::MatchedFlags;
|
2017-08-05 13:33:32 +00:00
|
|
|
|
use fs::feature::xattr;
|
|
|
|
|
|
2017-06-23 20:22:39 +00:00
|
|
|
|
|
|
|
|
|
static OPTIONS: &str = r##"
|
2017-05-06 22:00:45 +00:00
|
|
|
|
-?, --help show list of command-line options
|
|
|
|
|
-v, --version show version of exa
|
|
|
|
|
|
2016-04-17 19:38:37 +00:00
|
|
|
|
DISPLAY OPTIONS
|
|
|
|
|
-1, --oneline display one entry per line
|
2017-05-06 22:00:45 +00:00
|
|
|
|
-l, --long display extended file metadata as a table
|
|
|
|
|
-G, --grid display entries as a grid (default)
|
|
|
|
|
-x, --across sort the grid across, rather than downwards
|
2016-04-17 19:38:37 +00:00
|
|
|
|
-R, --recurse recurse into directories
|
2017-05-06 22:00:45 +00:00
|
|
|
|
-T, --tree recurse into directories as a tree
|
|
|
|
|
-F, --classify display type indicator by file names
|
|
|
|
|
--colo[u]r=WHEN when to use terminal colours (always, auto, never)
|
|
|
|
|
--colo[u]r-scale highlight levels of file sizes distinctly
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
FILTERING AND SORTING OPTIONS
|
2017-06-29 12:24:55 +00:00
|
|
|
|
-a, --all show hidden and 'dot' files
|
2017-05-06 22:00:45 +00:00
|
|
|
|
-d, --list-dirs list directories like regular files
|
|
|
|
|
-r, --reverse reverse the sort order
|
2017-08-12 10:39:12 +00:00
|
|
|
|
-s, --sort SORT_FIELD which field to sort by
|
2016-04-17 19:38:37 +00:00
|
|
|
|
--group-directories-first list directories before other files
|
2016-10-30 14:47:38 +00:00
|
|
|
|
-I, --ignore-glob GLOBS glob patterns (pipe-separated) of files to ignore
|
2017-06-29 13:57:43 +00:00
|
|
|
|
Valid sort fields: name, Name, extension, Extension, size, type,
|
2017-09-13 22:26:06 +00:00
|
|
|
|
modified, accessed, created, inode, and none.
|
|
|
|
|
date, time, old, and new all refer to modified.
|
2016-04-17 19:38:37 +00:00
|
|
|
|
"##;
|
|
|
|
|
|
2017-06-23 20:22:39 +00:00
|
|
|
|
static LONG_OPTIONS: &str = r##"
|
2016-04-17 19:38:37 +00:00
|
|
|
|
LONG VIEW OPTIONS
|
2017-05-06 22:00:45 +00:00
|
|
|
|
-b, --binary list file sizes with binary prefixes
|
|
|
|
|
-B, --bytes list file sizes in bytes, without any prefixes
|
|
|
|
|
-g, --group list each file's group
|
|
|
|
|
-h, --header add a header row to each column
|
|
|
|
|
-H, --links list each file's number of hard links
|
|
|
|
|
-i, --inode list each file's inode number
|
|
|
|
|
-L, --level DEPTH limit the depth of recursion
|
|
|
|
|
-m, --modified use the modified timestamp field
|
2016-04-17 19:38:37 +00:00
|
|
|
|
-S, --blocks show number of file system blocks
|
2017-05-06 22:00:45 +00:00
|
|
|
|
-t, --time FIELD which timestamp field to list (modified, accessed, created)
|
|
|
|
|
-u, --accessed use the accessed timestamp field
|
2017-07-05 23:52:27 +00:00
|
|
|
|
-U, --created use the created timestamp field
|
|
|
|
|
--time-style how to format timestamps (default, iso, long-iso, full-iso)"##;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
2017-06-23 20:22:39 +00:00
|
|
|
|
static GIT_HELP: &str = r##" --git list each file's Git status, if tracked"##;
|
|
|
|
|
static EXTENDED_HELP: &str = r##" -@, --extended list each file's extended attributes and sizes"##;
|
|
|
|
|
|
2017-08-05 13:33:32 +00:00
|
|
|
|
|
|
|
|
|
/// All the information needed to display the help text, which depends
|
|
|
|
|
/// on which features are enabled and whether the user only wants to
|
|
|
|
|
/// see one section’s help.
|
2017-06-23 21:50:29 +00:00
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
|
|
|
pub struct HelpString {
|
2017-08-05 13:33:32 +00:00
|
|
|
|
|
|
|
|
|
/// Only show the help for the long section, not all the help.
|
2017-08-05 18:45:55 +00:00
|
|
|
|
only_long: bool,
|
2017-08-05 13:33:32 +00:00
|
|
|
|
|
|
|
|
|
/// Whether the --git option should be included in the help.
|
2017-08-05 18:45:55 +00:00
|
|
|
|
git: bool,
|
2017-08-05 13:33:32 +00:00
|
|
|
|
|
|
|
|
|
/// Whether the --extended option should be included in the help.
|
2017-08-05 18:45:55 +00:00
|
|
|
|
xattrs: bool,
|
2017-06-23 21:50:29 +00:00
|
|
|
|
}
|
2017-06-23 20:22:39 +00:00
|
|
|
|
|
2017-08-05 13:33:32 +00:00
|
|
|
|
impl HelpString {
|
|
|
|
|
|
|
|
|
|
/// Determines how to show help, if at all, based on the user’s
|
|
|
|
|
/// command-line arguments. This one works backwards from the other
|
|
|
|
|
/// ‘deduce’ functions, returning Err if help needs to be shown.
|
Be stricter in strict mode
Now the code actually starts to use the Strictness flag that was added in the earlier commit! Well, the *code* doesn’t, but the tests do: the macros that create the test cases now have a parameter for which tests they should run. It’s usually ‘Both’ for both strict mode and default mode, but can be specified to only run in one, for when the results differ (usually when options override one another)
The downside to strict mode is that, now, *any* call to `matches.has` or `matches.get` could fail, because an option could have been specified twice, and this is the place where those are checked for. This makes the code a little less ergonomic in places, but that’s what the ? operator is for. The only place this has really had an effect is in `Classify::deduce`, which used to just return a boolean but can now fail.
In order to more thoroughly test the mode, some of the older parts of the code can now act more strict. For example, `TerminalColours::deduce` will now use the last-given option rather than searching for “colours” before “colors”.
Help and Version continue doing their own thing.
2017-08-09 08:21:29 +00:00
|
|
|
|
///
|
|
|
|
|
/// We don’t do any strict-mode error checking here: it’s OK to give
|
|
|
|
|
/// the --help or --long flags more than once. Actually checking for
|
|
|
|
|
/// errors when the user wants help is kind of petty!
|
2017-08-05 18:11:00 +00:00
|
|
|
|
pub fn deduce(matches: &MatchedFlags) -> Result<(), HelpString> {
|
Be stricter in strict mode
Now the code actually starts to use the Strictness flag that was added in the earlier commit! Well, the *code* doesn’t, but the tests do: the macros that create the test cases now have a parameter for which tests they should run. It’s usually ‘Both’ for both strict mode and default mode, but can be specified to only run in one, for when the results differ (usually when options override one another)
The downside to strict mode is that, now, *any* call to `matches.has` or `matches.get` could fail, because an option could have been specified twice, and this is the place where those are checked for. This makes the code a little less ergonomic in places, but that’s what the ? operator is for. The only place this has really had an effect is in `Classify::deduce`, which used to just return a boolean but can now fail.
In order to more thoroughly test the mode, some of the older parts of the code can now act more strict. For example, `TerminalColours::deduce` will now use the last-given option rather than searching for “colours” before “colors”.
Help and Version continue doing their own thing.
2017-08-09 08:21:29 +00:00
|
|
|
|
if matches.count(&flags::HELP) > 0 {
|
|
|
|
|
let only_long = matches.count(&flags::LONG) > 0;
|
2017-08-05 13:33:32 +00:00
|
|
|
|
let git = cfg!(feature="git");
|
|
|
|
|
let xattrs = xattr::ENABLED;
|
|
|
|
|
Err(HelpString { only_long, git, xattrs })
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Ok(()) // no help needs to be shown
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-23 21:50:29 +00:00
|
|
|
|
impl fmt::Display for HelpString {
|
2017-08-05 13:33:32 +00:00
|
|
|
|
|
|
|
|
|
/// Format this help options into an actual string of help
|
|
|
|
|
/// text to be displayed to the user.
|
2017-06-23 21:50:29 +00:00
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
|
try!(write!(f, "Usage:\n exa [options] [files...]\n"));
|
2017-06-23 20:22:39 +00:00
|
|
|
|
|
2017-06-23 21:50:29 +00:00
|
|
|
|
if !self.only_long {
|
|
|
|
|
try!(write!(f, "{}", OPTIONS));
|
|
|
|
|
}
|
2017-06-23 20:22:39 +00:00
|
|
|
|
|
2017-06-23 21:50:29 +00:00
|
|
|
|
try!(write!(f, "{}", LONG_OPTIONS));
|
2017-06-23 20:22:39 +00:00
|
|
|
|
|
2017-06-23 21:50:29 +00:00
|
|
|
|
if self.git {
|
|
|
|
|
try!(write!(f, "\n{}", GIT_HELP));
|
|
|
|
|
}
|
2017-06-23 20:22:39 +00:00
|
|
|
|
|
2017-06-23 21:50:29 +00:00
|
|
|
|
if self.xattrs {
|
|
|
|
|
try!(write!(f, "\n{}", EXTENDED_HELP));
|
|
|
|
|
}
|
2017-06-23 20:22:39 +00:00
|
|
|
|
|
2017-06-23 21:50:29 +00:00
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2017-06-23 20:22:39 +00:00
|
|
|
|
}
|
2017-08-05 13:33:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test {
|
|
|
|
|
use options::Options;
|
|
|
|
|
use std::ffi::OsString;
|
|
|
|
|
|
|
|
|
|
fn os(input: &'static str) -> OsString {
|
|
|
|
|
let mut os = OsString::new();
|
|
|
|
|
os.push(input);
|
|
|
|
|
os
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn help() {
|
|
|
|
|
let args = [ os("--help") ];
|
2017-08-13 10:14:58 +00:00
|
|
|
|
let opts = Options::parse(&args, &None);
|
2017-08-05 13:33:32 +00:00
|
|
|
|
assert!(opts.is_err())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn help_with_file() {
|
|
|
|
|
let args = [ os("--help"), os("me") ];
|
2017-08-13 10:14:58 +00:00
|
|
|
|
let opts = Options::parse(&args, &None);
|
2017-08-05 13:33:32 +00:00
|
|
|
|
assert!(opts.is_err())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn unhelpful() {
|
|
|
|
|
let args = [];
|
2017-08-13 10:14:58 +00:00
|
|
|
|
let opts = Options::parse(&args, &None);
|
2017-08-05 13:33:32 +00:00
|
|
|
|
assert!(opts.is_ok()) // no help when --help isn’t passed
|
|
|
|
|
}
|
|
|
|
|
}
|