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
pub mod fraction;
pub mod quantity;
pub use fraction::Fraction;
pub use quantity::Quantity;
use crate::{bytes_format::BytesFormat, visualizer::ColumnWidthDistribution};
use std::{num::NonZeroUsize, path::PathBuf};
use structopt::StructOpt;
use strum::VariantNames;
use terminal_size::{terminal_size, Width};
use text_block_macros::text_block;
#[derive(Debug, Clone, StructOpt)]
#[structopt(
name = "pdu",
long_about = text_block! {
"Summarize disk usage of the set of files, recursively for directories."
""
"Copyright: Apache-2.0 © 2021 Hoàng Văn Khải <https://ksxgithub.github.io/>"
"Donation: https://patreon.com/khai96_"
},
after_help = text_block! {
"EXAMPLES:"
" Show disk usage chart of current working directory"
" $ pdu"
""
" Show disk usage chart of a single file or directory"
" $ pdu path/to/file/or/directory"
""
" Compare disk usages of multiple files and/or directories"
" $ pdu file.txt dir/"
""
" Show chart in block sizes instead of apparent sizes"
" $ pdu --quantity=blksize"
""
" Show data in plain numbers instead of metric units"
" $ pdu --bytes-format=plain"
""
" Show data in base 2¹⁰ units (binary) instead of base 10³ units (metric)"
" $ pdu --bytes-format=binary"
""
" Show disk usage chart of all entries regardless of size"
" $ pdu --min-ratio=0"
""
" Only show disk usage chart of entries whose size is at least 5% of total"
" $ pdu --min-ratio=0.05"
""
" Show disk usage data as JSON instead of chart"
" $ pdu --min-ratio=0 --json-output | jq"
""
" Visualize existing JSON representation of disk usage data"
" $ pdu --min-ratio=0 < disk-usage.json"
},
)]
pub struct Args {
#[structopt(name = "files")]
pub files: Vec<PathBuf>,
#[structopt(long, conflicts_with = "quantity")]
pub json_input: bool,
#[structopt(long)]
pub json_output: bool,
#[structopt(long, possible_values = BytesFormat::VARIANTS, default_value = BytesFormat::default_value())]
pub bytes_format: BytesFormat,
#[structopt(long)]
pub top_down: bool,
#[structopt(long, possible_values = Quantity::VARIANTS, default_value = Quantity::default_value())]
pub quantity: Quantity,
#[structopt(long, default_value = "10")]
pub max_depth: NonZeroUsize,
#[structopt(long, conflicts_with = "column-width")]
pub total_width: Option<usize>,
#[structopt(long, number_of_values = 2, value_names = &["tree-width", "bar-width"])]
pub column_width: Option<Vec<usize>>,
#[structopt(long, default_value = "0.01")]
pub min_ratio: Fraction,
#[structopt(long)]
pub no_sort: bool,
#[structopt(long)]
pub silent_errors: bool,
#[structopt(long)]
pub progress: bool,
}
impl Args {
pub(crate) fn column_width_distribution(&self) -> ColumnWidthDistribution {
match (self.total_width, self.column_width.as_deref()) {
(None, None) => {
ColumnWidthDistribution::total(if let Some((Width(width), _)) = terminal_size() {
width as usize
} else {
150
})
}
(Some(total_width), None) => ColumnWidthDistribution::total(total_width),
(None, Some([tree_width, bar_width])) => {
ColumnWidthDistribution::components(*tree_width, *bar_width)
}
(total_width, column_width) => {
dbg!(total_width, column_width);
panic!("Something goes wrong")
}
}
}
}