use std::fmt; use crate::fs::feature::xattr; use crate::options::flags; use crate::options::parser::MatchedFlags; static OPTIONS: &str = r##" -?, --help show list of command-line options -v, --version show version of exa DISPLAY OPTIONS -1, --oneline display one entry per line -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 -R, --recurse recurse into directories -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 --icons display icons FILTERING AND SORTING OPTIONS -a, --all show hidden and 'dot' files -d, --list-dirs list directories like regular files -L, --level DEPTH limit the depth of recursion -r, --reverse reverse the sort order -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' Valid sort fields: name, Name, extension, Extension, size, type, modified, accessed, created, inode, and none. date, time, old, and new all refer to modified. "##; static LONG_OPTIONS: &str = r##" LONG VIEW OPTIONS -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 -m, --modified use the modified timestamp field -S, --blocks show number of file system blocks -t, --time FIELD which timestamp field to list (modified, accessed, created) -u, --accessed use the accessed timestamp field -U, --created use the created timestamp field --changed use the changed timestamp field --time-style how to format timestamps (default, iso, long-iso, full-iso) --no-permissions suppress the permissions field --no-filesize suppress the filesize field --no-user suppress the user 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 OCTAL_HELP: &str = r##" --octal-permissions list each file's permission in octal format"##; /// 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. #[derive(PartialEq, Debug, Copy, Clone)] pub struct HelpString { /// Only show the help for the long section, not all the help. only_long: bool, /// Whether the --git option should be included in the help. git: bool, /// Whether the --extended option should be included in the help. xattrs: bool, } 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. /// /// 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! pub fn deduce(matches: &MatchedFlags) -> Result<(), Self> { if matches.count(&flags::HELP) > 0 { let only_long = matches.count(&flags::LONG) > 0; let git = cfg!(feature="git"); let xattrs = xattr::ENABLED; Err(Self { only_long, git, xattrs }) } else { Ok(()) // no help needs to be shown } } } 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:\n exa [options] [files...]")?; if ! self.only_long { write!(f, "{}", OPTIONS)?; } write!(f, "{}", LONG_OPTIONS)?; if self.git { write!(f, "\n{}", GIT_HELP)?; } if self.xattrs { write!(f, "\n{}", EXTENDED_HELP)?; } write!(f, "\n{}", OCTAL_HELP)?; Ok(()) } } #[cfg(test)] mod test { use crate::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") ]; let opts = Options::parse(&args, &None); assert!(opts.is_err()) } #[test] fn help_with_file() { let args = [ os("--help"), os("me") ]; let opts = Options::parse(&args, &None); assert!(opts.is_err()) } #[test] fn unhelpful() { let args = []; let opts = Options::parse(&args, &None); assert!(opts.is_ok()) // no help when --help isn’t passed } }