parallel_disk_usage/
args.rs

1pub mod fraction;
2pub mod quantity;
3pub mod threads;
4
5pub use fraction::Fraction;
6pub use quantity::Quantity;
7pub use threads::Threads;
8
9use crate::{bytes_format::BytesFormat, visualizer::ColumnWidthDistribution};
10use clap::{ColorChoice, Parser};
11use std::{num::NonZeroUsize, path::PathBuf};
12use terminal_size::{terminal_size, Width};
13use text_block_macros::text_block;
14
15/// The CLI arguments.
16#[derive(Debug, Clone, Parser)]
17#[clap(
18    name = "pdu",
19
20    version,
21
22    long_about = text_block! {
23        "Summarize disk usage of the set of files, recursively for directories."
24        ""
25        "Copyright: Apache-2.0 © 2021 Hoàng Văn Khải <https://github.com/KSXGitHub/>"
26        "Sponsor: https://github.com/sponsors/KSXGitHub"
27    },
28
29    after_help = text_block! {
30        "EXAMPLES:"
31        "    $ pdu"
32        "    $ pdu path/to/file/or/directory"
33        "    $ pdu file.txt dir/"
34        "    $ pdu --quantity=apparent-size"
35        "    $ pdu --bytes-format=plain"
36        "    $ pdu --bytes-format=binary"
37        "    $ pdu --min-ratio=0"
38        "    $ pdu --min-ratio=0.05"
39        "    $ pdu --min-ratio=0 --json-output | jq"
40        "    $ pdu --min-ratio=0 < disk-usage.json"
41    },
42
43    after_long_help = text_block! {
44        "EXAMPLES:"
45        "    Show disk usage chart of current working directory"
46        "    $ pdu"
47        ""
48        "    Show disk usage chart of a single file or directory"
49        "    $ pdu path/to/file/or/directory"
50        ""
51        "    Compare disk usages of multiple files and/or directories"
52        "    $ pdu file.txt dir/"
53        ""
54        "    Show chart in apparent sizes instead of block sizes"
55        "    $ pdu --quantity=apparent-size"
56        ""
57        "    Show sizes in plain numbers instead of metric units"
58        "    $ pdu --bytes-format=plain"
59        ""
60        "    Show sizes in base 2¹⁰ units (binary) instead of base 10³ units (metric)"
61        "    $ pdu --bytes-format=binary"
62        ""
63        "    Show disk usage chart of all entries regardless of size"
64        "    $ pdu --min-ratio=0"
65        ""
66        "    Only show disk usage chart of entries whose size is at least 5% of total"
67        "    $ pdu --min-ratio=0.05"
68        ""
69        "    Show disk usage data as JSON instead of chart"
70        "    $ pdu --min-ratio=0 --json-output | jq"
71        ""
72        "    Visualize existing JSON representation of disk usage data"
73        "    $ pdu --min-ratio=0 < disk-usage.json"
74    },
75
76    color = ColorChoice::Never,
77)]
78pub struct Args {
79    /// List of files and/or directories.
80    pub files: Vec<PathBuf>,
81
82    /// Read JSON data from stdin.
83    #[clap(long, conflicts_with = "quantity")]
84    pub json_input: bool,
85
86    /// Print JSON data instead of an ASCII chart.
87    #[clap(long)]
88    pub json_output: bool,
89
90    /// How to display the numbers of bytes.
91    #[clap(long, value_enum, default_value_t = BytesFormat::MetricUnits)]
92    pub bytes_format: BytesFormat,
93
94    /// Print the tree top-down instead of bottom-up.
95    #[clap(long)]
96    pub top_down: bool,
97
98    /// Set the root of the bars to the right.
99    #[clap(long)]
100    pub align_right: bool,
101
102    /// Aspect of the files/directories to be measured.
103    #[clap(long, value_enum, default_value_t = Quantity::DEFAULT)]
104    pub quantity: Quantity,
105
106    /// Maximum depth to display the data (must be greater than 0).
107    #[clap(long, default_value = "10")]
108    pub max_depth: NonZeroUsize,
109
110    /// Width of the visualization.
111    #[clap(long, conflicts_with = "column_width")]
112    pub total_width: Option<usize>,
113
114    /// Maximum widths of the tree column and width of the bar column.
115    #[clap(long, number_of_values = 2, value_names = &["TREE_WIDTH", "BAR_WIDTH"])]
116    pub column_width: Option<Vec<usize>>,
117
118    /// Minimal size proportion required to appear.
119    #[clap(long, default_value = "0.01")]
120    pub min_ratio: Fraction,
121
122    /// Preserve order of entries.
123    #[clap(long)]
124    pub no_sort: bool,
125
126    /// Prevent filesystem error messages from appearing in stderr.
127    #[clap(long)]
128    pub silent_errors: bool,
129
130    /// Report progress being made at the expense of performance.
131    #[clap(long)]
132    pub progress: bool,
133
134    /// Set the maximum number of threads to spawn. Could be either "auto", "max", or a number.
135    #[clap(long, default_value_t = Threads::Auto)]
136    pub threads: Threads,
137}
138
139impl Args {
140    /// Deduce [`ColumnWidthDistribution`] from `--total-width` or `--column-width`.
141    pub(crate) fn column_width_distribution(&self) -> ColumnWidthDistribution {
142        match (self.total_width, self.column_width.as_deref()) {
143            (None, None) => {
144                ColumnWidthDistribution::total(if let Some((Width(width), _)) = terminal_size() {
145                    width as usize
146                } else {
147                    150
148                })
149            }
150            (Some(total_width), None) => ColumnWidthDistribution::total(total_width),
151            (None, Some([tree_width, bar_width])) => {
152                ColumnWidthDistribution::components(*tree_width, *bar_width)
153            }
154            (total_width, column_width) => {
155                dbg!(total_width, column_width);
156                panic!("Something goes wrong")
157            }
158        }
159    }
160}