summaryrefslogtreecommitdiffstats
path: root/src/options/help.rs
blob: c934fea6dbe018715facb85836063b74c2c37ca7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use std::fmt;

use crate::options::flags;
use crate::options::parser::MatchedFlags;
use crate::fs::feature::xattr;


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)]
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<(), HelpString> {
        if matches.count(&flags::HELP) > 0 {
            let only_long = matches.count(&flags::LONG) > 0;
            let git       = cfg!(feature="git");
            let xattrs    = xattr::ENABLED;
            Err(HelpString { 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
    }
}