Skip to content

Commit 550f2d2

Browse files
committed
Add context to all option number parse errors
Fixes GH-839.
1 parent 3104346 commit 550f2d2

14 files changed

+149
-20
lines changed

src/options/dir_action.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Parsing the options for `DirAction`.
22
33
use crate::options::parser::MatchedFlags;
4-
use crate::options::{flags, OptionsError};
4+
use crate::options::{flags, OptionsError, NumberSource};
55

66
use crate::fs::dir_action::{DirAction, RecurseOptions};
77

@@ -55,17 +55,21 @@ impl RecurseOptions {
5555
/// determined earlier. The maximum level should be a number, and this
5656
/// will fail with an `Err` if it isn’t.
5757
pub fn deduce(matches: &MatchedFlags<'_>, tree: bool) -> Result<Self, OptionsError> {
58-
let max_depth = if let Some(level) = matches.get(&flags::LEVEL)? {
59-
match level.to_string_lossy().parse() {
60-
Ok(l) => Some(l),
61-
Err(e) => return Err(OptionsError::FailedParse(e)),
58+
if let Some(level) = matches.get(&flags::LEVEL)? {
59+
let arg_str = level.to_string_lossy();
60+
match arg_str.parse() {
61+
Ok(l) => {
62+
Ok(Self { tree, max_depth: Some(l) })
63+
}
64+
Err(e) => {
65+
let source = NumberSource::Arg(&flags::LEVEL);
66+
Err(OptionsError::FailedParse(arg_str.to_string(), source, e))
67+
}
6268
}
6369
}
6470
else {
65-
None
66-
};
67-
68-
Ok(Self { tree, max_depth })
71+
Ok(Self { tree, max_depth: None })
72+
}
6973
}
7074
}
7175

src/options/error.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,38 @@ pub enum OptionsError {
3737
TreeAllAll,
3838

3939
/// A numeric option was given that failed to be parsed as a number.
40-
FailedParse(ParseIntError),
40+
FailedParse(String, NumberSource, ParseIntError),
4141

4242
/// A glob ignore was given that failed to be parsed as a pattern.
4343
FailedGlobPattern(String),
4444
}
4545

46+
/// The source of a string that failed to be parsed as a number.
47+
#[derive(PartialEq, Debug)]
48+
pub enum NumberSource {
49+
50+
/// It came... from a command-line argument!
51+
Arg(&'static Arg),
52+
53+
/// It came... from the enviroment!
54+
Env(&'static str),
55+
}
56+
4657
impl From<glob::PatternError> for OptionsError {
4758
fn from(error: glob::PatternError) -> Self {
4859
Self::FailedGlobPattern(error.to_string())
4960
}
5061
}
5162

63+
impl fmt::Display for NumberSource {
64+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65+
match self {
66+
Self::Arg(arg) => write!(f, "option {}", arg),
67+
Self::Env(env) => write!(f, "environment variable {}", env),
68+
}
69+
}
70+
}
71+
5272
impl fmt::Display for OptionsError {
5373
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5474
use crate::options::parser::TakesValue;
@@ -71,7 +91,7 @@ impl fmt::Display for OptionsError {
7191
Self::Useless(a, true, b) => write!(f, "Option {} is useless given option {}", a, b),
7292
Self::Useless2(a, b1, b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2),
7393
Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"),
74-
Self::FailedParse(ref e) => write!(f, "Failed to parse number: {}", e),
94+
Self::FailedParse(s, n, e) => write!(f, "Value {:?} not valid for {}: {}", s, n, e),
7595
Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e),
7696
}
7797
}

src/options/file_name.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::options::{flags, OptionsError};
1+
use crate::options::{flags, OptionsError, NumberSource};
22
use crate::options::parser::MatchedFlags;
33
use crate::options::vars::{self, Vars};
44

@@ -30,8 +30,13 @@ impl ShowIcons {
3030
}
3131
else if let Some(columns) = vars.get(vars::EXA_ICON_SPACING).and_then(|s| s.into_string().ok()) {
3232
match columns.parse() {
33-
Ok(width) => Ok(Self::On(width)),
34-
Err(e) => Err(OptionsError::FailedParse(e)),
33+
Ok(width) => {
34+
Ok(Self::On(width))
35+
}
36+
Err(e) => {
37+
let source = NumberSource::Env(vars::EXA_ICON_SPACING);
38+
Err(OptionsError::FailedParse(columns, source, e))
39+
}
3540
}
3641
}
3742
else {

src/options/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ mod theme;
8484
mod view;
8585

8686
mod error;
87-
pub use self::error::OptionsError;
87+
pub use self::error::{OptionsError, NumberSource};
8888

8989
mod help;
9090
use self::help::HelpString;

src/options/view.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::fs::feature::xattr;
2-
use crate::options::{flags, OptionsError, Vars};
2+
use crate::options::{flags, OptionsError, NumberSource, Vars};
33
use crate::options::parser::MatchedFlags;
44
use crate::output::{View, Mode, TerminalWidth, grid, details};
55
use crate::output::grid_details::{self, RowThreshold};
@@ -151,8 +151,13 @@ impl TerminalWidth {
151151

152152
if let Some(columns) = vars.get(vars::COLUMNS).and_then(|s| s.into_string().ok()) {
153153
match columns.parse() {
154-
Ok(width) => Ok(Self::Set(width)),
155-
Err(e) => Err(OptionsError::FailedParse(e)),
154+
Ok(width) => {
155+
Ok(Self::Set(width))
156+
}
157+
Err(e) => {
158+
let source = NumberSource::Env(vars::COLUMNS);
159+
Err(OptionsError::FailedParse(columns, source, e))
160+
}
156161
}
157162
}
158163
else {
@@ -168,8 +173,13 @@ impl RowThreshold {
168173

169174
if let Some(columns) = vars.get(vars::EXA_GRID_ROWS).and_then(|s| s.into_string().ok()) {
170175
match columns.parse() {
171-
Ok(rows) => Ok(Self::MinimumRows(rows)),
172-
Err(e) => Err(OptionsError::FailedParse(e)),
176+
Ok(rows) => {
177+
Ok(Self::MinimumRows(rows))
178+
}
179+
Err(e) => {
180+
let source = NumberSource::Env(vars::EXA_GRID_ROWS);
181+
Err(OptionsError::FailedParse(columns, source, e))
182+
}
173183
}
174184
}
175185
else {

xtests/errors.toml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,85 @@ stdout = { empty = true }
1515
stderr = { string = "To sort newest files last, try \"--sort newest\", or just \"-snew\""}
1616
status = 3
1717
tags = [ 'error', 'long', 'sort' ]
18+
19+
20+
# Invalid values for $COLUMNS
21+
22+
[[cmd]]
23+
name = "‘COLUMNS=999... exa’ shows an error about the number size"
24+
shell = "exa"
25+
environment = { "COLUMNS" = "99999999999999999999999" }
26+
stdout = { empty = true }
27+
stderr = { file = "outputs/error_columns_nines.ansitxt" }
28+
status = 3
29+
tags = [ 'error', 'env' ]
30+
31+
[[cmd]]
32+
name = "‘COLUMNS=abcdef exa’ shows an error about invalid digits"
33+
shell = "exa"
34+
environment = { "COLUMNS" = "abcdef" }
35+
stdout = { empty = true }
36+
stderr = { file = "outputs/error_columns_invalid.ansitxt" }
37+
status = 3
38+
tags = [ 'error', 'env' ]
39+
40+
41+
# Invalid values for $EXA_GRID_ROWS
42+
43+
[[cmd]]
44+
name = "‘EXA_GRID_ROWS=999... exa -lG’ shows an error about the number size"
45+
shell = "exa -lG"
46+
environment = { "EXA_GRID_ROWS" = "99999999999999999999999" }
47+
stdout = { empty = true }
48+
stderr = { file = "outputs/error_grid_rows_nines.ansitxt" }
49+
status = 3
50+
tags = [ 'error', 'env' ]
51+
52+
[[cmd]]
53+
name = "‘EXA_GRID_ROWS=abcdef exa -lG’ shows an error about invalid digits"
54+
shell = "exa -lG"
55+
environment = { "EXA_GRID_ROWS" = "abcdef" }
56+
stdout = { empty = true }
57+
stderr = { file = "outputs/error_grid_rows_invalid.ansitxt" }
58+
status = 3
59+
tags = [ 'error', 'env' ]
60+
61+
62+
# Invalid values for $EXA_ICON_SPACING
63+
64+
[[cmd]]
65+
name = "‘EXA_ICON_SPACING=999... exa --icons’ shows an error about the number size"
66+
shell = "exa --icons"
67+
environment = { "EXA_ICON_SPACING" = "99999999999999999999999" }
68+
stdout = { empty = true }
69+
stderr = { file = "outputs/error_icon_spacing_nines.ansitxt" }
70+
status = 3
71+
tags = [ 'error', 'env', 'icons' ]
72+
73+
[[cmd]]
74+
name = "‘EXA_ICON_SPACING=abcdef exa --icons’ shows an error about invalid digits"
75+
shell = "exa --icons"
76+
environment = { "EXA_ICON_SPACING" = "abcdef" }
77+
stdout = { empty = true }
78+
stderr = { file = "outputs/error_icon_spacing_invalid.ansitxt" }
79+
status = 3
80+
tags = [ 'error', 'env', 'icons' ]
81+
82+
83+
# Invalid values for --level (-L)
84+
85+
[[cmd]]
86+
name = "‘exa -TL999...’ shows an error about the number size"
87+
shell = "exa -TL99999999999999999999999"
88+
stdout = { empty = true }
89+
stderr = { file = "outputs/error_level_nines.ansitxt" }
90+
status = 3
91+
tags = [ 'error', 'tree', 'level' ]
92+
93+
[[cmd]]
94+
name = "‘exa -TLabcdef’ shows an error about invalid digits"
95+
shell = "exa -TLabcdef"
96+
stdout = { empty = true }
97+
stderr = { file = "outputs/error_level_invalid.ansitxt" }
98+
status = 3
99+
tags = [ 'error', 'tree', 'level' ]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exa: Value "abcdef" not valid for environment variable COLUMNS: invalid digit found in string
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exa: Value "99999999999999999999999" not valid for environment variable COLUMNS: number too large to fit in target type
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exa: Value "abcdef" not valid for environment variable EXA_GRID_ROWS: invalid digit found in string
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exa: Value "99999999999999999999999" not valid for environment variable EXA_GRID_ROWS: number too large to fit in target type

0 commit comments

Comments
 (0)