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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
use std::fmt;
use clap::{Parser, ValueEnum, ValueHint};
// For single thread mode set this variable on your command line:
// export RAYON_NUM_THREADS=1
/// Like du but more intuitive
#[derive(Debug, Parser)]
#[command(name("Dust"), version)]
pub struct Cli {
/// Depth to show
#[arg(short, long)]
pub depth: Option<usize>,
/// Number of threads to use
#[arg(short('T'), long)]
pub threads: Option<usize>,
/// Specify a config file to use
#[arg(long, value_name("FILE"), value_hint(ValueHint::FilePath))]
pub config: Option<String>,
/// Number of lines of output to show. (Default is terminal_height - 10)
#[arg(short, long, value_name("NUMBER"))]
pub number_of_lines: Option<usize>,
/// Subdirectories will not have their path shortened
#[arg(short('p'), long)]
pub full_paths: bool,
/// Exclude any file or directory with this path
#[arg(short('X'), long, value_name("PATH"), value_hint(ValueHint::AnyPath))]
pub ignore_directory: Option<Vec<String>>,
/// Exclude any file or directory with a regex matching that listed in this
/// file, the file entries will be added to the ignore regexs provided by
/// --invert_filter
#[arg(short('I'), long, value_name("FILE"), value_hint(ValueHint::FilePath))]
pub ignore_all_in_file: Option<String>,
/// dereference sym links - Treat sym links as directories and go into them
#[arg(short('L'), long)]
pub dereference_links: bool,
/// Only count the files and directories on the same filesystem as the
/// supplied directory
#[arg(short('x'), long)]
pub limit_filesystem: bool,
/// Use file length instead of blocks
#[arg(short('s'), long)]
pub apparent_size: bool,
/// Print tree upside down (biggest highest)
#[arg(short, long)]
pub reverse: bool,
/// No colors will be printed (Useful for commands like: watch)
#[arg(short('c'), long)]
pub no_colors: bool,
/// Force colors print
#[arg(short('C'), long)]
pub force_colors: bool,
/// No percent bars or percentages will be displayed
#[arg(short('b'), long)]
pub no_percent_bars: bool,
/// percent bars moved to right side of screen
#[arg(short('B'), long)]
pub bars_on_right: bool,
/// Minimum size file to include in output
#[arg(short('z'), long)]
pub min_size: Option<String>,
/// For screen readers. Removes bars. Adds new column: depth level (May want
/// to use -p too for full path)
#[arg(short('R'), long)]
pub screen_reader: bool,
/// No total row will be displayed
#[arg(long)]
pub skip_total: bool,
/// Directory 'size' is number of child files instead of disk size
#[arg(short, long)]
pub filecount: bool,
/// Do not display hidden files
// Do not use 'h' this is used by 'help'
#[arg(short, long)]
pub ignore_hidden: bool,
/// Exclude filepaths matching this regex. To ignore png files type: -v
/// "\.png$"
#[arg(
short('v'),
long,
value_name("REGEX"),
conflicts_with("filter"),
conflicts_with("file_types")
)]
pub invert_filter: Option<Vec<String>>,
/// Only include filepaths matching this regex. For png files type: -e
/// "\.png$"
#[arg(short('e'), long, value_name("REGEX"), conflicts_with("file_types"))]
pub filter: Option<Vec<String>>,
/// show only these file types
#[arg(short('t'), long, conflicts_with("depth"), conflicts_with("only_dir"))]
pub file_types: bool,
/// Specify width of output overriding the auto detection of terminal width
#[arg(short('w'), long, value_name("WIDTH"))]
pub terminal_width: Option<usize>,
/// Disable the progress indication.
#[arg(short('P'), long)]
pub no_progress: bool,
/// Print path with errors.
#[arg(long)]
pub print_errors: bool,
/// Only directories will be displayed.
#[arg(
short('D'),
long,
conflicts_with("only_file"),
conflicts_with("file_types")
)]
pub only_dir: bool,
/// Only files will be displayed. (Finds your largest files)
#[arg(short('F'), long, conflicts_with("only_dir"))]
pub only_file: bool,
/// Changes output display size. si will print sizes in powers of 1000. b k
/// m g t kb mb gb tb will print the whole tree in that size.
#[arg(short, long, value_enum, value_name("FORMAT"), ignore_case(true))]
pub output_format: Option<OutputFormat>,
/// Specify memory to use as stack size - use if you see: 'fatal runtime
/// error: stack overflow' (default low memory=1048576, high
/// memory=1073741824)
#[arg(short('S'), long)]
pub stack_size: Option<usize>,
/// Input files or directories.
#[arg(value_name("PATH"), value_hint(ValueHint::AnyPath))]
pub params: Option<Vec<String>>,
/// Output the directory tree as json to the current directory
#[arg(short('j'), long)]
pub output_json: bool,
/// +/-n matches files modified more/less than n days ago , and n matches
/// files modified exactly n days ago, days are rounded down.That is +n =>
/// (−∞, curr−(n+1)), n => [curr−(n+1), curr−n), and -n => (𝑐𝑢𝑟𝑟−𝑛, +∞)
#[arg(short('M'), long, allow_hyphen_values(true))]
pub mtime: Option<String>,
/// just like -mtime, but based on file access time
#[arg(short('A'), long, allow_hyphen_values(true))]
pub atime: Option<String>,
/// just like -mtime, but based on file change time
#[arg(short('y'), long, allow_hyphen_values(true))]
pub ctime: Option<String>,
/// run dust on NUL-terminated file names specified in file; if argument is
/// -, then read names from standard input
#[arg(long, value_hint(ValueHint::AnyPath))]
pub files0_from: Option<String>,
/// Keep these directories collapsed
#[arg(long, value_hint(ValueHint::AnyPath))]
pub collapse: Option<Vec<String>>,
/// Directory 'size' is max filetime of child files instead of disk size.
/// while a/c/m for last accessed/changed/modified time
#[arg(short('m'), long, value_enum)]
pub filetime: Option<FileTime>,
}
#[derive(Clone, Copy, Debug, ValueEnum)]
#[value(rename_all = "lower")]
pub enum OutputFormat {
/// SI prefix (powers of 1000)
SI,
/// byte (B)
B,
/// kibibyte (KiB)
#[value(name = "k", alias("kib"))]
KiB,
/// mebibyte (MiB)
#[value(name = "m", alias("mib"))]
MiB,
/// gibibyte (GiB)
#[value(name = "g", alias("gib"))]
GiB,
/// tebibyte (TiB)
#[value(name = "t", alias("tib"))]
TiB,
/// kilobyte (kB)
KB,
/// megabyte (MB)
MB,
/// gigabyte (GB)
GB,
/// terabyte (TB)
TB,
}
impl fmt::Display for OutputFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SI => write!(f, "si"),
Self::B => write!(f, "b"),
Self::KiB => write!(f, "k"),
Self::MiB => write!(f, "m"),
Self::GiB => write!(f, "g"),
Self::TiB => write!(f, "t"),
Self::KB => write!(f, "kb"),
Self::MB => write!(f, "mb"),
Self::GB => write!(f, "gb"),
Self::TB => write!(f, "tb"),
}
}
}
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum FileTime {
/// last accessed time
#[value(name = "a", alias("accessed"))]
Accessed,
/// last changed time
#[value(name = "c", alias("changed"))]
Changed,
/// last modified time
#[value(name = "m", alias("modified"))]
Modified,
}