diff --git a/Cargo.lock b/Cargo.lock index 73820a33..8456d134 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,6 +488,7 @@ dependencies = [ "smart-default", "terminal_size", "text-block-macros", + "thiserror", "zero-copy-pads", ] diff --git a/Cargo.toml b/Cargo.toml index dd164a9f..634af498 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ cli-completions = ["cli"] pipe-trait = "^0.4.0" smart-default = "^0.6.0" derive_more = "^0.99.17" +thiserror = "^1.0.32" rayon = "^1.5.3" text-block-macros = "^0.1.1" rounded-div = "^0.1.2" diff --git a/exports/completion.bash b/exports/completion.bash index d07ced6e..0bef8c68 100644 --- a/exports/completion.bash +++ b/exports/completion.bash @@ -19,7 +19,7 @@ _pdu() { case "${cmd}" in pdu) - opts="-h --help --json-input --json-output --bytes-format --top-down --align-left --quantity --max-depth --total-width --column-width --min-ratio --no-sort --silent-errors --progress ..." + opts="-h -V --help --version --json-input --json-output --bytes-format --top-down --align-left --quantity --max-depth --total-width --column-width --min-ratio --no-sort --silent-errors --progress ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/exports/completion.elv b/exports/completion.elv index 5476f163..eaca9730 100644 --- a/exports/completion.elv +++ b/exports/completion.elv @@ -26,6 +26,8 @@ set edit:completion:arg-completer[pdu] = {|@words| cand --min-ratio 'Minimal size proportion required to appear' cand -h 'Print help information' cand --help 'Print help information' + cand -V 'Print version information' + cand --version 'Print version information' cand --json-input 'Read JSON data from stdin' cand --json-output 'Print JSON data instead of an ASCII chart' cand --top-down 'Print the tree top-down instead of bottom-up' diff --git a/exports/completion.fish b/exports/completion.fish index 607b286d..e331ba25 100644 --- a/exports/completion.fish +++ b/exports/completion.fish @@ -5,6 +5,7 @@ complete -c pdu -l total-width -d 'Width of the visualization' -r complete -c pdu -l column-width -d 'Maximum widths of the tree column and width of the bar column' -r complete -c pdu -l min-ratio -d 'Minimal size proportion required to appear' -r complete -c pdu -s h -l help -d 'Print help information' +complete -c pdu -s V -l version -d 'Print version information' complete -c pdu -l json-input -d 'Read JSON data from stdin' complete -c pdu -l json-output -d 'Print JSON data instead of an ASCII chart' complete -c pdu -l top-down -d 'Print the tree top-down instead of bottom-up' diff --git a/exports/completion.ps1 b/exports/completion.ps1 index ff295e47..b8c09a1d 100644 --- a/exports/completion.ps1 +++ b/exports/completion.ps1 @@ -29,6 +29,8 @@ Register-ArgumentCompleter -Native -CommandName 'pdu' -ScriptBlock { [CompletionResult]::new('--min-ratio', 'min-ratio', [CompletionResultType]::ParameterName, 'Minimal size proportion required to appear') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information') [CompletionResult]::new('--json-input', 'json-input', [CompletionResultType]::ParameterName, 'Read JSON data from stdin') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'Print JSON data instead of an ASCII chart') [CompletionResult]::new('--top-down', 'top-down', [CompletionResultType]::ParameterName, 'Print the tree top-down instead of bottom-up') diff --git a/exports/completion.zsh b/exports/completion.zsh index 81c038a9..1f4b440f 100644 --- a/exports/completion.zsh +++ b/exports/completion.zsh @@ -23,10 +23,12 @@ blksize\:"Measure block sizes, equivalent to the \[blksize\](std::os::unix::prel blocks\:"Count numbers of blocks, equivalent to the \[blocks\](std::os::unix::prelude::MetadataExt::blocks) method (POSIX only)"))' \ '--max-depth=[Maximum depth to display the data (must be greater than 0)]:MAX_DEPTH: ' \ '(--column-width)--total-width=[Width of the visualization]:TOTAL_WIDTH: ' \ -'*--column-width=[Maximum widths of the tree column and width of the bar column]:tree-width: :tree-width: ' \ -'*--min-ratio=[Minimal size proportion required to appear]:MIN_RATIO: ' \ +'*--column-width=[Maximum widths of the tree column and width of the bar column]:TREE_WIDTH: :TREE_WIDTH: ' \ +'--min-ratio=[Minimal size proportion required to appear]:MIN_RATIO: ' \ '-h[Print help information]' \ '--help[Print help information]' \ +'-V[Print version information]' \ +'--version[Print version information]' \ '(--quantity)--json-input[Read JSON data from stdin]' \ '--json-output[Print JSON data instead of an ASCII chart]' \ '--top-down[Print the tree top-down instead of bottom-up]' \ diff --git a/src/args.rs b/src/args.rs index a07504da..fadb6448 100644 --- a/src/args.rs +++ b/src/args.rs @@ -15,6 +15,8 @@ use text_block_macros::text_block; #[clap( name = "pdu", + version, + long_about = text_block! { "Summarize disk usage of the set of files, recursively for directories." "" @@ -108,11 +110,11 @@ pub struct Args { pub total_width: Option, /// Maximum widths of the tree column and width of the bar column. - #[clap(long, number_of_values = 2, value_names = &["tree-width", "bar-width"])] + #[clap(long, number_of_values = 2, value_names = &["TREE_WIDTH", "BAR_WIDTH"])] pub column_width: Option>, /// Minimal size proportion required to appear. - #[clap(long, default_value = "0.01", value_parser)] + #[clap(long, default_value = "0.01")] pub min_ratio: Fraction, /// Preserve order of entries. diff --git a/src/args/fraction.rs b/src/args/fraction.rs index 73af2839..0667a17b 100644 --- a/src/args/fraction.rs +++ b/src/args/fraction.rs @@ -1,23 +1,23 @@ -use clap::builder::{TypedValueParser, ValueParserFactory}; use derive_more::{AsRef, Deref, Display, Into}; use std::{ convert::{TryFrom, TryInto}, num::ParseFloatError, str::FromStr, }; +use thiserror::Error; /// Floating-point value that is greater than or equal to 0 and less than 1. #[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd, AsRef, Deref, Display, Into)] pub struct Fraction(f32); /// Error that occurs when calling [`Fraction::new`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)] pub enum ConversionError { /// Provided value is greater than or equal to 1. - #[display(fmt = "greater than or equal to 1")] + #[error("greater than or equal to 1")] UpperBound, /// Provided value is less than 0. - #[display(fmt = "less than 0")] + #[error("less than 0")] LowerBound, } @@ -42,7 +42,8 @@ impl TryFrom for Fraction { } } -#[derive(Debug, Clone, PartialEq, Eq, Display)] +#[derive(Debug, Clone, PartialEq, Eq, Error)] +#[error("{_0}")] pub enum FromStrError { ParseFloatError(ParseFloatError), Conversion(ConversionError), @@ -57,39 +58,3 @@ impl FromStr for Fraction { .map_err(FromStrError::Conversion) } } - -impl ValueParserFactory for Fraction { - type Parser = FractionValueParser; - fn value_parser() -> Self::Parser { - FractionValueParser - } -} - -/// The [parser](ValueParserFactory::Parser) of [`Fraction`]. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct FractionValueParser; - -impl TypedValueParser for FractionValueParser { - type Value = Fraction; - - fn parse_ref( - &self, - _: &clap::Command, - arg: Option<&clap::Arg>, - value: &std::ffi::OsStr, - ) -> Result { - let value = value - .to_str() - .ok_or_else(|| clap::Error::raw(clap::ErrorKind::InvalidUtf8, "Invalid UTF-8"))?; - value.parse().map_err(|error| { - clap::Error::raw( - clap::ErrorKind::ValueValidation, - format_args!( - "Invalid value {value:?} for '{arg}': {error}\n\nFor more information try --help\n", - arg = arg.map_or_else(|| "...".to_string(), |arg| arg.to_string()), - ), - ) - }) - } -} diff --git a/src/bytes_format/parsed_value.rs b/src/bytes_format/parsed_value.rs index 8d343ca5..f40101bc 100644 --- a/src/bytes_format/parsed_value.rs +++ b/src/bytes_format/parsed_value.rs @@ -1,16 +1,16 @@ -use derive_more::Display; +use thiserror::Error; /// Return value of [`Formatter::parse_value`](super::Formatter::parse_value). -#[derive(Debug, Display, Clone, Copy)] +#[derive(Debug, Clone, Copy, Error)] pub enum ParsedValue { /// When input value is less than `scale_base`. - #[display(fmt = "{} ", value)] + #[error("{value} ")] Small { /// Input value that is less than `scale_base`. value: u16, }, /// When input value is greater than `scale_base`. - #[display(fmt = "{:.1}{}", coefficient, unit)] + #[error("{coefficient:.1}{unit}")] Big { /// The visible part of the number. coefficient: f32, diff --git a/src/json_data/schema_version.rs b/src/json_data/schema_version.rs index 643f60ed..466966b4 100644 --- a/src/json_data/schema_version.rs +++ b/src/json_data/schema_version.rs @@ -1,9 +1,9 @@ #[cfg(feature = "json")] -use derive_more::Display; -#[cfg(feature = "json")] use serde::{Deserialize, Serialize}; #[cfg(feature = "json")] use std::convert::TryFrom; +#[cfg(feature = "json")] +use thiserror::Error; /// Content of [`SchemaVersion`]. pub const SCHEMA_VERSION: &str = "2021-06-05"; @@ -16,12 +16,8 @@ pub struct SchemaVersion; /// Error when trying to parse [`SchemaVersion`]. #[cfg(feature = "json")] -#[derive(Debug, Display)] -#[display( - fmt = "InvalidSchema: {:?}: input schema is not {:?}", - input, - SCHEMA_VERSION -)] +#[derive(Debug, Error)] +#[error("InvalidSchema: {:?}: input schema is not {:?}", input, SCHEMA_VERSION)] pub struct InvalidSchema { /// The input string. pub input: String, diff --git a/src/runtime_error.rs b/src/runtime_error.rs index fdbaf0af..0a903020 100644 --- a/src/runtime_error.rs +++ b/src/runtime_error.rs @@ -1,21 +1,21 @@ -use derive_more::Display; +use thiserror::Error; /// Error caused by the CLI program. -#[derive(Debug, Display)] +#[derive(Debug, Error)] #[non_exhaustive] pub enum RuntimeError { /// When it fails to write JSON representation of /// [DataTreeReflection](crate::data_tree::Reflection) to stdout. - #[display(fmt = "SerializationFailure: {}", _0)] + #[error("SerializationFailure: {_0}")] SerializationFailure(serde_json::Error), /// When it fails to read JSON representation of /// [DataTreeReflection](crate::data_tree::Reflection) from stdin. - #[display(fmt = "DeserializationFailure: {}", _0)] + #[error("DeserializationFailure: {_0}")] DeserializationFailure(serde_json::Error), /// When both `--json-input` and file names are both specified. - #[display(fmt = "JsonInputArgConflict: Arguments exist alongside --json-input")] + #[error("JsonInputArgConflict: Arguments exist alongside --json-input")] JsonInputArgConflict, /// When input JSON data is not a valid tree. - #[display(fmt = "InvalidInputReflection: {}", _0)] + #[error("InvalidInputReflection: {_0}")] InvalidInputReflection(String), }