diff --git a/src/options/dir_action.rs b/src/options/dir_action.rs index 0cc31fa..e729b86 100644 --- a/src/options/dir_action.rs +++ b/src/options/dir_action.rs @@ -1,7 +1,7 @@ //! Parsing the options for `DirAction`. use crate::options::parser::MatchedFlags; -use crate::options::{flags, OptionsError}; +use crate::options::{flags, OptionsError, NumberSource}; use crate::fs::dir_action::{DirAction, RecurseOptions}; @@ -55,17 +55,21 @@ impl RecurseOptions { /// determined earlier. The maximum level should be a number, and this /// will fail with an `Err` if it isn’t. pub fn deduce(matches: &MatchedFlags<'_>, tree: bool) -> Result { - let max_depth = if let Some(level) = matches.get(&flags::LEVEL)? { - match level.to_string_lossy().parse() { - Ok(l) => Some(l), - Err(e) => return Err(OptionsError::FailedParse(e)), + if let Some(level) = matches.get(&flags::LEVEL)? { + let arg_str = level.to_string_lossy(); + match arg_str.parse() { + Ok(l) => { + Ok(Self { tree, max_depth: Some(l) }) + } + Err(e) => { + let source = NumberSource::Arg(&flags::LEVEL); + Err(OptionsError::FailedParse(arg_str.to_string(), source, e)) + } } } else { - None - }; - - Ok(Self { tree, max_depth }) + Ok(Self { tree, max_depth: None }) + } } } diff --git a/src/options/error.rs b/src/options/error.rs index 2b724e1..1b1aa87 100644 --- a/src/options/error.rs +++ b/src/options/error.rs @@ -37,18 +37,38 @@ pub enum OptionsError { TreeAllAll, /// A numeric option was given that failed to be parsed as a number. - FailedParse(ParseIntError), + FailedParse(String, NumberSource, ParseIntError), /// A glob ignore was given that failed to be parsed as a pattern. FailedGlobPattern(String), } +/// The source of a string that failed to be parsed as a number. +#[derive(PartialEq, Debug)] +pub enum NumberSource { + + /// It came... from a command-line argument! + Arg(&'static Arg), + + /// It came... from the enviroment! + Env(&'static str), +} + impl From for OptionsError { fn from(error: glob::PatternError) -> Self { Self::FailedGlobPattern(error.to_string()) } } +impl fmt::Display for NumberSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Arg(arg) => write!(f, "option {}", arg), + Self::Env(env) => write!(f, "environment variable {}", env), + } + } +} + impl fmt::Display for OptionsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::options::parser::TakesValue; @@ -71,7 +91,7 @@ impl fmt::Display for OptionsError { Self::Useless(a, true, b) => write!(f, "Option {} is useless given option {}", a, b), Self::Useless2(a, b1, b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2), Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"), - Self::FailedParse(ref e) => write!(f, "Failed to parse number: {}", e), + Self::FailedParse(s, n, e) => write!(f, "Value {:?} not valid for {}: {}", s, n, e), Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e), } } diff --git a/src/options/file_name.rs b/src/options/file_name.rs index 96131bb..2c1db1a 100644 --- a/src/options/file_name.rs +++ b/src/options/file_name.rs @@ -1,4 +1,4 @@ -use crate::options::{flags, OptionsError}; +use crate::options::{flags, OptionsError, NumberSource}; use crate::options::parser::MatchedFlags; use crate::options::vars::{self, Vars}; @@ -30,8 +30,13 @@ impl ShowIcons { } else if let Some(columns) = vars.get(vars::EXA_ICON_SPACING).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(width) => Ok(Self::On(width)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(width) => { + Ok(Self::On(width)) + } + Err(e) => { + let source = NumberSource::Env(vars::EXA_ICON_SPACING); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { diff --git a/src/options/mod.rs b/src/options/mod.rs index 26e9c81..747213b 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -84,7 +84,7 @@ mod theme; mod view; mod error; -pub use self::error::OptionsError; +pub use self::error::{OptionsError, NumberSource}; mod help; use self::help::HelpString; diff --git a/src/options/view.rs b/src/options/view.rs index 6f13c87..6d7abac 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -1,5 +1,5 @@ use crate::fs::feature::xattr; -use crate::options::{flags, OptionsError, Vars}; +use crate::options::{flags, OptionsError, NumberSource, Vars}; use crate::options::parser::MatchedFlags; use crate::output::{View, Mode, TerminalWidth, grid, details}; use crate::output::grid_details::{self, RowThreshold}; @@ -151,8 +151,13 @@ impl TerminalWidth { if let Some(columns) = vars.get(vars::COLUMNS).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(width) => Ok(Self::Set(width)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(width) => { + Ok(Self::Set(width)) + } + Err(e) => { + let source = NumberSource::Env(vars::COLUMNS); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { @@ -168,8 +173,13 @@ impl RowThreshold { if let Some(columns) = vars.get(vars::EXA_GRID_ROWS).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(rows) => Ok(Self::MinimumRows(rows)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(rows) => { + Ok(Self::MinimumRows(rows)) + } + Err(e) => { + let source = NumberSource::Env(vars::EXA_GRID_ROWS); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { diff --git a/xtests/errors.toml b/xtests/errors.toml index 150e73e..ed50d9d 100644 --- a/xtests/errors.toml +++ b/xtests/errors.toml @@ -15,3 +15,85 @@ stdout = { empty = true } stderr = { string = "To sort newest files last, try \"--sort newest\", or just \"-snew\""} status = 3 tags = [ 'error', 'long', 'sort' ] + + +# Invalid values for $COLUMNS + +[[cmd]] +name = "‘COLUMNS=999... exa’ shows an error about the number size" +shell = "exa" +environment = { "COLUMNS" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_columns_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + +[[cmd]] +name = "‘COLUMNS=abcdef exa’ shows an error about invalid digits" +shell = "exa" +environment = { "COLUMNS" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_columns_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + + +# Invalid values for $EXA_GRID_ROWS + +[[cmd]] +name = "‘EXA_GRID_ROWS=999... exa -lG’ shows an error about the number size" +shell = "exa -lG" +environment = { "EXA_GRID_ROWS" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_grid_rows_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + +[[cmd]] +name = "‘EXA_GRID_ROWS=abcdef exa -lG’ shows an error about invalid digits" +shell = "exa -lG" +environment = { "EXA_GRID_ROWS" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_grid_rows_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + + +# Invalid values for $EXA_ICON_SPACING + +[[cmd]] +name = "‘EXA_ICON_SPACING=999... exa --icons’ shows an error about the number size" +shell = "exa --icons" +environment = { "EXA_ICON_SPACING" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_icon_spacing_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env', 'icons' ] + +[[cmd]] +name = "‘EXA_ICON_SPACING=abcdef exa --icons’ shows an error about invalid digits" +shell = "exa --icons" +environment = { "EXA_ICON_SPACING" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_icon_spacing_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env', 'icons' ] + + +# Invalid values for --level (-L) + +[[cmd]] +name = "‘exa -TL999...’ shows an error about the number size" +shell = "exa -TL99999999999999999999999" +stdout = { empty = true } +stderr = { file = "outputs/error_level_nines.ansitxt" } +status = 3 +tags = [ 'error', 'tree', 'level' ] + +[[cmd]] +name = "‘exa -TLabcdef’ shows an error about invalid digits" +shell = "exa -TLabcdef" +stdout = { empty = true } +stderr = { file = "outputs/error_level_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'tree', 'level' ] diff --git a/xtests/outputs/error_columns_invalid.ansitxt b/xtests/outputs/error_columns_invalid.ansitxt new file mode 100644 index 0000000..1455322 --- /dev/null +++ b/xtests/outputs/error_columns_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable COLUMNS: invalid digit found in string diff --git a/xtests/outputs/error_columns_nines.ansitxt b/xtests/outputs/error_columns_nines.ansitxt new file mode 100644 index 0000000..f1ecc7f --- /dev/null +++ b/xtests/outputs/error_columns_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable COLUMNS: number too large to fit in target type diff --git a/xtests/outputs/error_grid_rows_invalid.ansitxt b/xtests/outputs/error_grid_rows_invalid.ansitxt new file mode 100644 index 0000000..c1474d9 --- /dev/null +++ b/xtests/outputs/error_grid_rows_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable EXA_GRID_ROWS: invalid digit found in string diff --git a/xtests/outputs/error_grid_rows_nines.ansitxt b/xtests/outputs/error_grid_rows_nines.ansitxt new file mode 100644 index 0000000..35750bb --- /dev/null +++ b/xtests/outputs/error_grid_rows_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable EXA_GRID_ROWS: number too large to fit in target type diff --git a/xtests/outputs/error_icon_spacing_invalid.ansitxt b/xtests/outputs/error_icon_spacing_invalid.ansitxt new file mode 100644 index 0000000..aaec7f3 --- /dev/null +++ b/xtests/outputs/error_icon_spacing_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable EXA_ICON_SPACING: invalid digit found in string diff --git a/xtests/outputs/error_icon_spacing_nines.ansitxt b/xtests/outputs/error_icon_spacing_nines.ansitxt new file mode 100644 index 0000000..44f3ad1 --- /dev/null +++ b/xtests/outputs/error_icon_spacing_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable EXA_ICON_SPACING: number too large to fit in target type diff --git a/xtests/outputs/error_level_invalid.ansitxt b/xtests/outputs/error_level_invalid.ansitxt new file mode 100644 index 0000000..d7f4a03 --- /dev/null +++ b/xtests/outputs/error_level_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for option --level (-L): invalid digit found in string diff --git a/xtests/outputs/error_level_nines.ansitxt b/xtests/outputs/error_level_nines.ansitxt new file mode 100644 index 0000000..895fc0a --- /dev/null +++ b/xtests/outputs/error_level_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for option --level (-L): number too large to fit in target type