From f7b8f97873228396954c31574a1a12ac3f7b6c65 Mon Sep 17 00:00:00 2001 From: Stefan Holderbach Date: Mon, 6 Mar 2023 11:31:07 +0100 Subject: [PATCH] Document and critically review `ShellError` variants - Ep. 2 (#8326) Continuation of #8229 # Description The `ShellError` enum at the moment is kind of messy. Many variants are basic tuple structs where you always have to reference the implementation with its macro invocation to know which field serves which purpose. Furthermore we have both variants that are kind of redundant or either overly broad to be useful for the user to match on or overly specific with few uses. So I set out to start fixing the lacking documentation and naming to make it feasible to critically review the individual usages and fix those. Furthermore we can decide to join or split up variants that don't seem to be fit for purpose. **Everyone:** Feel free to add review comments if you spot inconsistent use of `ShellError` variants. - Name fields of `SE::IncorrectValue` - Merge and name fields on `SE::TypeMismatch` - Name fields on `SE::UnsupportedOperator` - Name fields on `AssignmentRequires*` and fix doc - Name fields on `SE::UnknownOperator` - Name fields on `SE::MissingParameter` - Name fields on `SE::DelimiterError` - Name fields on `SE::IncompatibleParametersSingle` # User-Facing Changes (None now, end goal more explicit and consistent error messages) # Tests + Formatting (No additional tests needed so far) --- crates/nu-cli/src/repl.rs | 14 ++-- crates/nu-command/src/bytes/at.rs | 8 +-- crates/nu-command/src/bytes/build_.rs | 8 +-- crates/nu-command/src/bytes/remove.rs | 8 +-- crates/nu-command/src/bytes/replace.rs | 8 +-- crates/nu-command/src/charting/histogram.rs | 20 +++--- .../src/conversions/into/datetime.rs | 8 +-- crates/nu-command/src/conversions/into/int.rs | 6 +- .../nu-command/src/conversions/into/string.rs | 8 +-- .../nu-command/src/dataframe/eager/rename.rs | 8 +-- .../src/dataframe/expressions/is_in.rs | 8 +-- .../nu-command/src/dataframe/lazy/groupby.rs | 8 +-- crates/nu-command/src/dataframe/lazy/join.rs | 16 ++--- crates/nu-command/src/dataframe/utils.rs | 8 +-- .../values/nu_dataframe/between_values.rs | 16 ++--- .../values/nu_dataframe/operations.rs | 12 ++-- .../values/nu_expression/custom_value.rs | 8 +-- crates/nu-command/src/date/format.rs | 5 +- crates/nu-command/src/date/to_timezone.rs | 5 +- crates/nu-command/src/filesystem/mkdir.rs | 8 +-- crates/nu-command/src/filesystem/open.rs | 16 ++--- crates/nu-command/src/filesystem/touch.rs | 16 ++--- crates/nu-command/src/filesystem/watch.rs | 8 +-- crates/nu-command/src/filters/drop/nth.rs | 31 +++++---- crates/nu-command/src/filters/find.rs | 6 +- crates/nu-command/src/filters/headers.rs | 25 +++---- crates/nu-command/src/filters/rename.rs | 14 ++-- crates/nu-command/src/filters/roll/mod.rs | 13 ++-- crates/nu-command/src/filters/skip/skip_.rs | 17 +++-- crates/nu-command/src/filters/sort_by.rs | 5 +- crates/nu-command/src/filters/uniq_by.rs | 5 +- crates/nu-command/src/formats/from/csv.rs | 6 +- .../nu-command/src/formats/from/delimited.rs | 14 ++-- crates/nu-command/src/formats/from/ods.rs | 8 +-- crates/nu-command/src/formats/from/xlsx.rs | 8 +-- crates/nu-command/src/formats/to/csv.rs | 7 +- crates/nu-command/src/generators/cal.rs | 21 +++--- crates/nu-command/src/network/http/client.rs | 9 ++- crates/nu-command/src/network/url/join.rs | 29 ++++---- crates/nu-command/src/platform/ansi/ansi_.rs | 33 +++++---- .../nu-command/src/platform/ansi/gradient.rs | 14 ++-- crates/nu-command/src/platform/ansi/link.rs | 5 +- crates/nu-command/src/platform/ansi/strip.rs | 5 +- crates/nu-command/src/strings/char_.rs | 49 ++++++------- .../src/strings/encode_decode/base64.rs | 8 +-- .../nu-command/src/strings/format/command.rs | 16 ++--- crates/nu-command/src/strings/mod.rs | 16 ++--- crates/nu-command/src/strings/parse.rs | 6 +- crates/nu-command/src/strings/split/words.rs | 12 ++-- .../nu-command/src/strings/str_/index_of.rs | 23 +++---- crates/nu-command/src/strings/str_/replace.rs | 5 +- .../nu-command/src/strings/str_/substring.rs | 65 ++++++++++-------- crates/nu-command/src/system/which_.rs | 8 +-- crates/nu-engine/src/env.rs | 8 +-- crates/nu-engine/src/eval.rs | 22 +++--- crates/nu-protocol/src/pipeline_data.rs | 12 ++-- crates/nu-protocol/src/shell_error.rs | 68 ++++++++++++------- crates/nu-protocol/src/value/custom_value.rs | 2 +- crates/nu-protocol/src/value/mod.rs | 22 ++++-- src/command.rs | 5 +- 60 files changed, 477 insertions(+), 375 deletions(-) diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index db8d0a2575..7ea22265ea 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -846,10 +846,10 @@ pub fn eval_env_change_hook( } } x => { - return Err(ShellError::TypeMismatch( - "record for the 'env_change' hook".to_string(), - x.span()?, - )); + return Err(ShellError::TypeMismatch { + err_message: "record for the 'env_change' hook".to_string(), + span: x.span()?, + }); } } } @@ -1109,10 +1109,10 @@ fn run_hook_block( if let Some(arg) = arguments.get(idx) { callee_stack.add_var(*var_id, arg.1.clone()) } else { - return Err(ShellError::IncompatibleParametersSingle( - "This hook block has too many parameters".into(), + return Err(ShellError::IncompatibleParametersSingle { + msg: "This hook block has too many parameters".into(), span, - )); + }); } } } diff --git a/crates/nu-command/src/bytes/at.rs b/crates/nu-command/src/bytes/at.rs index 273beba6ce..0356fcafb3 100644 --- a/crates/nu-command/src/bytes/at.rs +++ b/crates/nu-command/src/bytes/at.rs @@ -277,10 +277,10 @@ fn at_impl(input: &[u8], arg: &Arguments, span: Span) -> Value { match start.cmp(&end) { Ordering::Equal => Value::Binary { val: vec![], span }, Ordering::Greater => Value::Error { - error: ShellError::TypeMismatch( - "End must be greater than or equal to Start".to_string(), - arg.arg_span, - ), + error: ShellError::TypeMismatch { + err_message: "End must be greater than or equal to Start".to_string(), + span: arg.arg_span, + }, }, Ordering::Less => Value::Binary { val: { diff --git a/crates/nu-command/src/bytes/build_.rs b/crates/nu-command/src/bytes/build_.rs index 4b607e61d6..5ddf6f3a09 100644 --- a/crates/nu-command/src/bytes/build_.rs +++ b/crates/nu-command/src/bytes/build_.rs @@ -55,10 +55,10 @@ impl Command for BytesBuild { // Explicitly propagate errors instead of dropping them. Value::Error { error } => return Err(error), other => { - return Err(ShellError::TypeMismatch( - "only binary data arguments are supported".to_string(), - other.expect_span(), - )) + return Err(ShellError::TypeMismatch { + err_message: "only binary data arguments are supported".to_string(), + span: other.expect_span(), + }) } } } diff --git a/crates/nu-command/src/bytes/remove.rs b/crates/nu-command/src/bytes/remove.rs index b24c60d44f..fd196ba029 100644 --- a/crates/nu-command/src/bytes/remove.rs +++ b/crates/nu-command/src/bytes/remove.rs @@ -61,10 +61,10 @@ impl Command for BytesRemove { let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths); let pattern_to_remove = call.req::>>(engine_state, stack, 0)?; if pattern_to_remove.item.is_empty() { - return Err(ShellError::TypeMismatch( - "the pattern to remove cannot be empty".to_string(), - pattern_to_remove.span, - )); + return Err(ShellError::TypeMismatch { + err_message: "the pattern to remove cannot be empty".to_string(), + span: pattern_to_remove.span, + }); } let pattern_to_remove: Vec = pattern_to_remove.item; diff --git a/crates/nu-command/src/bytes/replace.rs b/crates/nu-command/src/bytes/replace.rs index 05885c3e46..ebe1130850 100644 --- a/crates/nu-command/src/bytes/replace.rs +++ b/crates/nu-command/src/bytes/replace.rs @@ -61,10 +61,10 @@ impl Command for BytesReplace { let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths); let find = call.req::>>(engine_state, stack, 0)?; if find.item.is_empty() { - return Err(ShellError::TypeMismatch( - "the pattern to find cannot be empty".to_string(), - find.span, - )); + return Err(ShellError::TypeMismatch { + err_message: "the pattern to find cannot be empty".to_string(), + span: find.span, + }); } let arg = Arguments { diff --git a/crates/nu-command/src/charting/histogram.rs b/crates/nu-command/src/charting/histogram.rs index da33526cc3..c667fc9b16 100644 --- a/crates/nu-command/src/charting/histogram.rs +++ b/crates/nu-command/src/charting/histogram.rs @@ -99,11 +99,12 @@ impl Command for Histogram { let frequency_column_name = match frequency_name_arg { Some(inner) => { if ["value", "count", "quantile", "percentage"].contains(&inner.item.as_str()) { - return Err(ShellError::TypeMismatch( - "frequency-column-name can't be 'value', 'count' or 'percentage'" - .to_string(), - inner.span, - )); + return Err(ShellError::TypeMismatch { + err_message: + "frequency-column-name can't be 'value', 'count' or 'percentage'" + .to_string(), + span: inner.span, + }); } inner.item } @@ -118,10 +119,11 @@ impl Command for Histogram { "normalize" => PercentageCalcMethod::Normalize, "relative" => PercentageCalcMethod::Relative, _ => { - return Err(ShellError::TypeMismatch( - "calc method can only be 'normalize' or 'relative'".to_string(), - inner.span, - )) + return Err(ShellError::TypeMismatch { + err_message: "calc method can only be 'normalize' or 'relative'" + .to_string(), + span: inner.span, + }) } }, }; diff --git a/crates/nu-command/src/conversions/into/datetime.rs b/crates/nu-command/src/conversions/into/datetime.rs index c62b30fc83..ba71e5db7d 100644 --- a/crates/nu-command/src/conversions/into/datetime.rs +++ b/crates/nu-command/src/conversions/into/datetime.rs @@ -290,10 +290,10 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { }, Zone::Error => Value::Error { // This is an argument error, not an input error - error: ShellError::TypeMismatch( - "Invalid timezone or offset".to_string(), - *span, - ), + error: ShellError::TypeMismatch { + err_message: "Invalid timezone or offset".to_string(), + span: *span, + }, }, }, }; diff --git a/crates/nu-command/src/conversions/into/int.rs b/crates/nu-command/src/conversions/into/int.rs index 82878a4125..e4375e8de5 100644 --- a/crates/nu-command/src/conversions/into/int.rs +++ b/crates/nu-command/src/conversions/into/int.rs @@ -70,10 +70,10 @@ impl Command for SubCommand { let radix: u32 = match radix { Some(Value::Int { val, span }) => { if !(2..=36).contains(&val) { - return Err(ShellError::TypeMismatch( - "Radix must lie in the range [2, 36]".to_string(), + return Err(ShellError::TypeMismatch { + err_message: "Radix must lie in the range [2, 36]".to_string(), span, - )); + }); } val as u32 } diff --git a/crates/nu-command/src/conversions/into/string.rs b/crates/nu-command/src/conversions/into/string.rs index 03e53eac7e..be61e6544b 100644 --- a/crates/nu-command/src/conversions/into/string.rs +++ b/crates/nu-command/src/conversions/into/string.rs @@ -154,10 +154,10 @@ fn string_helper( let decimals_value: Option = call.get_flag(engine_state, stack, "decimals")?; if let Some(decimal_val) = decimals_value { if decimals && decimal_val.is_negative() { - return Err(ShellError::TypeMismatch( - "Cannot accept negative integers for decimals arguments".to_string(), - head, - )); + return Err(ShellError::TypeMismatch { + err_message: "Cannot accept negative integers for decimals arguments".to_string(), + span: head, + }); } } let cell_paths = call.rest(engine_state, stack, 0)?; diff --git a/crates/nu-command/src/dataframe/eager/rename.rs b/crates/nu-command/src/dataframe/eager/rename.rs index 9ea417655f..ffe02d5c34 100644 --- a/crates/nu-command/src/dataframe/eager/rename.rs +++ b/crates/nu-command/src/dataframe/eager/rename.rs @@ -156,10 +156,10 @@ fn command_lazy( if columns.len() != new_names.len() { let value: Value = call.req(engine_state, stack, 1)?; - return Err(ShellError::IncompatibleParametersSingle( - "New name list has different size to column list".into(), - value.span()?, - )); + return Err(ShellError::IncompatibleParametersSingle { + msg: "New name list has different size to column list".into(), + span: value.span()?, + }); } let lazy = lazy.into_polars(); diff --git a/crates/nu-command/src/dataframe/expressions/is_in.rs b/crates/nu-command/src/dataframe/expressions/is_in.rs index 2f1dc95122..42d77b50a5 100644 --- a/crates/nu-command/src/dataframe/expressions/is_in.rs +++ b/crates/nu-command/src/dataframe/expressions/is_in.rs @@ -83,10 +83,10 @@ impl Command for ExprIsIn { let list = values.as_series(call.head)?; if matches!(list.dtype(), DataType::Object(..)) { - return Err(ShellError::IncompatibleParametersSingle( - "Cannot use a mixed list as argument".into(), - call.head, - )); + return Err(ShellError::IncompatibleParametersSingle { + msg: "Cannot use a mixed list as argument".into(), + span: call.head, + }); } let expr: NuExpression = expr.into_polars().is_in(lit(list)).into(); diff --git a/crates/nu-command/src/dataframe/lazy/groupby.rs b/crates/nu-command/src/dataframe/lazy/groupby.rs index 4eaa756e4a..9a9337eb5c 100644 --- a/crates/nu-command/src/dataframe/lazy/groupby.rs +++ b/crates/nu-command/src/dataframe/lazy/groupby.rs @@ -122,10 +122,10 @@ impl Command for ToLazyGroupBy { .any(|expr| !matches!(expr, Expr::Column(..))) { let value: Value = call.req(engine_state, stack, 0)?; - return Err(ShellError::IncompatibleParametersSingle( - "Expected only Col expressions".into(), - value.span()?, - )); + return Err(ShellError::IncompatibleParametersSingle { + msg: "Expected only Col expressions".into(), + span: value.span()?, + }); } let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; diff --git a/crates/nu-command/src/dataframe/lazy/join.rs b/crates/nu-command/src/dataframe/lazy/join.rs index 7940f492d3..1689009982 100644 --- a/crates/nu-command/src/dataframe/lazy/join.rs +++ b/crates/nu-command/src/dataframe/lazy/join.rs @@ -195,20 +195,20 @@ impl Command for LazyJoin { if left_on.len() != right_on.len() { let right_on: Value = call.req(engine_state, stack, 2)?; - return Err(ShellError::IncompatibleParametersSingle( - "The right column list has a different size to the left column list".into(), - right_on.span()?, - )); + return Err(ShellError::IncompatibleParametersSingle { + msg: "The right column list has a different size to the left column list".into(), + span: right_on.span()?, + }); } // Checking that both list of expressions are made out of col expressions or strings for (index, list) in &[(1usize, &left_on), (2, &left_on)] { if list.iter().any(|expr| !matches!(expr, Expr::Column(..))) { let value: Value = call.req(engine_state, stack, *index)?; - return Err(ShellError::IncompatibleParametersSingle( - "Expected only a string, col expressions or list of strings".into(), - value.span()?, - )); + return Err(ShellError::IncompatibleParametersSingle { + msg: "Expected only a string, col expressions or list of strings".into(), + span: value.span()?, + }); } } diff --git a/crates/nu-command/src/dataframe/utils.rs b/crates/nu-command/src/dataframe/utils.rs index 58f7589f63..982797cef2 100644 --- a/crates/nu-command/src/dataframe/utils.rs +++ b/crates/nu-command/src/dataframe/utils.rs @@ -7,9 +7,9 @@ pub fn extract_strings(value: Value) -> Result, ShellError> { ) { (Ok(col), Err(_)) => Ok(vec![col]), (Err(_), Ok(cols)) => Ok(cols), - _ => Err(ShellError::IncompatibleParametersSingle( - "Expected a string or list of strings".into(), - value.span()?, - )), + _ => Err(ShellError::IncompatibleParametersSingle { + msg: "Expected a string or list of strings".into(), + span: value.span()?, + }), } } diff --git a/crates/nu-command/src/dataframe/values/nu_dataframe/between_values.rs b/crates/nu-command/src/dataframe/values/nu_dataframe/between_values.rs index c81d38eabc..020b94d333 100644 --- a/crates/nu-command/src/dataframe/values/nu_dataframe/between_values.rs +++ b/crates/nu-command/src/dataframe/values/nu_dataframe/between_values.rs @@ -128,13 +128,13 @@ pub(super) fn compute_between_series( )), } } - _ => Err(ShellError::IncompatibleParametersSingle( - format!( + _ => Err(ShellError::IncompatibleParametersSingle { + msg: format!( "Operation {} can only be done with boolean values", operator.item ), - operation_span, - )), + span: operation_span, + }), }, Operator::Boolean(Boolean::Or) => match lhs.dtype() { DataType::Boolean => { @@ -157,13 +157,13 @@ pub(super) fn compute_between_series( )), } } - _ => Err(ShellError::IncompatibleParametersSingle( - format!( + _ => Err(ShellError::IncompatibleParametersSingle { + msg: format!( "Operation {} can only be done with boolean values", operator.item ), - operation_span, - )), + span: operation_span, + }), }, _ => Err(ShellError::OperatorMismatch { op_span: operator.span, diff --git a/crates/nu-command/src/dataframe/values/nu_dataframe/operations.rs b/crates/nu-command/src/dataframe/values/nu_dataframe/operations.rs index 615ef15b57..6c3d13baf1 100644 --- a/crates/nu-command/src/dataframe/values/nu_dataframe/operations.rs +++ b/crates/nu-command/src/dataframe/values/nu_dataframe/operations.rs @@ -151,10 +151,10 @@ impl NuDataFrame { } Axis::Column => { if self.df.width() != other.df.width() { - return Err(ShellError::IncompatibleParametersSingle( - "Dataframes with different number of columns".into(), + return Err(ShellError::IncompatibleParametersSingle { + msg: "Dataframes with different number of columns".into(), span, - )); + }); } if !self @@ -163,10 +163,10 @@ impl NuDataFrame { .iter() .all(|col| other.df.get_column_names().contains(col)) { - return Err(ShellError::IncompatibleParametersSingle( - "Dataframes with different columns names".into(), + return Err(ShellError::IncompatibleParametersSingle { + msg: "Dataframes with different columns names".into(), span, - )); + }); } let new_cols = self diff --git a/crates/nu-command/src/dataframe/values/nu_expression/custom_value.rs b/crates/nu-command/src/dataframe/values/nu_expression/custom_value.rs index ee85756303..528b861303 100644 --- a/crates/nu-command/src/dataframe/values/nu_expression/custom_value.rs +++ b/crates/nu-command/src/dataframe/values/nu_expression/custom_value.rs @@ -76,10 +76,10 @@ fn compute_with_value( polars::prelude::Expr::Literal(..) => { with_operator(operator, left, rhs, lhs_span, right.span()?, op) } - _ => Err(ShellError::TypeMismatch( - "Only literal expressions or number".into(), - right.span()?, - )), + _ => Err(ShellError::TypeMismatch { + err_message: "Only literal expressions or number".into(), + span: right.span()?, + }), } } _ => { diff --git a/crates/nu-command/src/date/format.rs b/crates/nu-command/src/date/format.rs index fae16e3e81..fd487bd079 100644 --- a/crates/nu-command/src/date/format.rs +++ b/crates/nu-command/src/date/format.rs @@ -132,7 +132,10 @@ where span, }, Err(_) => Value::Error { - error: ShellError::TypeMismatch("invalid format".to_string(), span), + error: ShellError::TypeMismatch { + err_message: "invalid format".to_string(), + span, + }, }, } } diff --git a/crates/nu-command/src/date/to_timezone.rs b/crates/nu-command/src/date/to_timezone.rs index a0fe576c53..37de40f1f3 100644 --- a/crates/nu-command/src/date/to_timezone.rs +++ b/crates/nu-command/src/date/to_timezone.rs @@ -137,7 +137,10 @@ fn _to_timezone(dt: DateTime, timezone: &Spanned, span: Spa match datetime_in_timezone(&dt, timezone.item.as_str()) { Ok(dt) => Value::Date { val: dt, span }, Err(_) => Value::Error { - error: ShellError::TypeMismatch(String::from("invalid time zone"), timezone.span), + error: ShellError::TypeMismatch { + err_message: String::from("invalid time zone"), + span: timezone.span, + }, }, } } diff --git a/crates/nu-command/src/filesystem/mkdir.rs b/crates/nu-command/src/filesystem/mkdir.rs index 739ab03212..851ab748de 100644 --- a/crates/nu-command/src/filesystem/mkdir.rs +++ b/crates/nu-command/src/filesystem/mkdir.rs @@ -55,10 +55,10 @@ impl Command for Mkdir { let mut stream: VecDeque = VecDeque::new(); if directories.peek().is_none() { - return Err(ShellError::MissingParameter( - "requires directory paths".to_string(), - call.head, - )); + return Err(ShellError::MissingParameter { + param_name: "requires directory paths".to_string(), + span: call.head, + }); } for (i, dir) in directories.enumerate() { diff --git a/crates/nu-command/src/filesystem/open.rs b/crates/nu-command/src/filesystem/open.rs index 04e0571986..8d314ce2ac 100644 --- a/crates/nu-command/src/filesystem/open.rs +++ b/crates/nu-command/src/filesystem/open.rs @@ -71,17 +71,17 @@ impl Command for Open { // Collect a filename from the input match input { PipelineData::Value(Value::Nothing { .. }, ..) => { - return Err(ShellError::MissingParameter( - "needs filename".to_string(), - call.head, - )) + return Err(ShellError::MissingParameter { + param_name: "needs filename".to_string(), + span: call.head, + }) } PipelineData::Value(val, ..) => val.as_spanned_string()?, _ => { - return Err(ShellError::MissingParameter( - "needs filename".to_string(), - call.head, - )); + return Err(ShellError::MissingParameter { + param_name: "needs filename".to_string(), + span: call.head, + }); } } }; diff --git a/crates/nu-command/src/filesystem/touch.rs b/crates/nu-command/src/filesystem/touch.rs index a8e8e17f6a..d08ba85c74 100644 --- a/crates/nu-command/src/filesystem/touch.rs +++ b/crates/nu-command/src/filesystem/touch.rs @@ -94,10 +94,10 @@ impl Command for Touch { Some(reference) => { let reference_path = Path::new(&reference.item); if !reference_path.exists() { - return Err(ShellError::TypeMismatch( - "path provided is invalid".to_string(), - reference.span, - )); + return Err(ShellError::TypeMismatch { + err_message: "path provided is invalid".to_string(), + span: reference.span, + }); } date = Some( @@ -119,10 +119,10 @@ impl Command for Touch { ); } None => { - return Err(ShellError::MissingParameter( - "reference".to_string(), - call.head, - )); + return Err(ShellError::MissingParameter { + param_name: "reference".to_string(), + span: call.head, + }); } } } diff --git a/crates/nu-command/src/filesystem/watch.rs b/crates/nu-command/src/filesystem/watch.rs index f02021e31b..adc508b6f1 100644 --- a/crates/nu-command/src/filesystem/watch.rs +++ b/crates/nu-command/src/filesystem/watch.rs @@ -95,10 +95,10 @@ impl Command for Watch { match nu_glob::Pattern::new(&absolute_path.to_string_lossy()) { Ok(pattern) => Some(pattern), Err(_) => { - return Err(ShellError::TypeMismatch( - "Glob pattern is invalid".to_string(), - glob.span, - )) + return Err(ShellError::TypeMismatch { + err_message: "Glob pattern is invalid".to_string(), + span: glob.span, + }) } } } diff --git a/crates/nu-command/src/filters/drop/nth.rs b/crates/nu-command/src/filters/drop/nth.rs index 919a44cc08..f366706e13 100644 --- a/crates/nu-command/src/filters/drop/nth.rs +++ b/crates/nu-command/src/filters/drop/nth.rs @@ -124,19 +124,20 @@ impl Command for DropNth { // check for negative range inputs, e.g., (2..-5) if from.is_negative() || to.is_negative() { let span: Spanned = call.req(engine_state, stack, 0)?; - return Err(ShellError::TypeMismatch( - "drop nth accepts only positive integers".to_string(), - span.span, - )); + return Err(ShellError::TypeMismatch { + err_message: "drop nth accepts only positive integers".to_string(), + span: span.span, + }); } // check if the upper bound is smaller than the lower bound, e.g., do not accept 4..2 if to < from { let span: Spanned = call.req(engine_state, stack, 0)?; - return Err(ShellError::TypeMismatch( - "The upper bound needs to be equal or larger to the lower bound" - .to_string(), - span.span, - )); + return Err(ShellError::TypeMismatch { + err_message: + "The upper bound needs to be equal or larger to the lower bound" + .to_string(), + span: span.span, + }); } // check for equality to isize::MAX because for some reason, @@ -191,12 +192,12 @@ fn extract_int_or_range( let range_opt = range_opt.map(Either::Right).ok(); - int_opt.or(range_opt).ok_or_else(|| { - ShellError::TypeMismatch( - "int or range".into(), - value.span().unwrap_or_else(|_| Span::new(0, 0)), - ) - }) + int_opt + .or(range_opt) + .ok_or_else(|| ShellError::TypeMismatch { + err_message: "int or range".into(), + span: value.span().unwrap_or_else(|_| Span::new(0, 0)), + }) } struct DropNthIterator { diff --git a/crates/nu-command/src/filters/find.rs b/crates/nu-command/src/filters/find.rs index 1e82e855cf..91af1d5f13 100644 --- a/crates/nu-command/src/filters/find.rs +++ b/crates/nu-command/src/filters/find.rs @@ -185,8 +185,10 @@ fn find_with_regex( let regex = flags.to_string() + regex.as_str(); - let re = Regex::new(regex.as_str()) - .map_err(|e| ShellError::TypeMismatch(format!("invalid regex: {e}"), span))?; + let re = Regex::new(regex.as_str()).map_err(|e| ShellError::TypeMismatch { + err_message: format!("invalid regex: {e}"), + span, + })?; input.filter( move |value| match value { diff --git a/crates/nu-command/src/filters/headers.rs b/crates/nu-command/src/filters/headers.rs index c67c0b1a68..8b3c1ae5a1 100644 --- a/crates/nu-command/src/filters/headers.rs +++ b/crates/nu-command/src/filters/headers.rs @@ -115,10 +115,10 @@ fn replace_headers(value: Value, headers: &[String]) -> Result Err(ShellError::TypeMismatch( - "record".to_string(), - value.span()?, - )), + _ => Err(ShellError::TypeMismatch { + err_message: "record".to_string(), + span: value.span()?, + }), } } @@ -138,10 +138,11 @@ fn extract_headers(value: &Value, config: &Config) -> Result, ShellE Value::Record { vals, .. } => { for v in vals { if !is_valid_header(v) { - return Err(ShellError::TypeMismatch( - "needs compatible type: Null, String, Bool, Float, Int".to_string(), - v.span()?, - )); + return Err(ShellError::TypeMismatch { + err_message: "needs compatible type: Null, String, Bool, Float, Int" + .to_string(), + span: v.span()?, + }); } } @@ -171,10 +172,10 @@ fn extract_headers(value: &Value, config: &Config) -> Result, ShellE Vec::new(), ) })?, - _ => Err(ShellError::TypeMismatch( - "record".to_string(), - value.span()?, - )), + _ => Err(ShellError::TypeMismatch { + err_message: "record".to_string(), + span: value.span()?, + }), } } diff --git a/crates/nu-command/src/filters/rename.rs b/crates/nu-command/src/filters/rename.rs index 3969a24086..964eec1cbe 100644 --- a/crates/nu-command/src/filters/rename.rs +++ b/crates/nu-command/src/filters/rename.rs @@ -108,11 +108,8 @@ fn rename( }) = call.get_flag(engine_state, stack, "column")? { if columns.is_empty() { - return Err(ShellError::TypeMismatch( - "The column list cannot be empty and must contain only two values: the column's name and its replacement value" - .to_string(), - column_span, - )); + return Err(ShellError::TypeMismatch { err_message: "The column list cannot be empty and must contain only two values: the column's name and its replacement value" + .to_string(), span: column_span }); } else { (Some(columns[0].span()?), column_span) } @@ -122,11 +119,8 @@ fn rename( if let Some(ref cols) = specified_column { if cols.len() != 2 { - return Err(ShellError::TypeMismatch( - "The column list must contain only two values: the column's name and its replacement value" - .to_string(), - list_span, - )); + return Err(ShellError::TypeMismatch { err_message: "The column list must contain only two values: the column's name and its replacement value" + .to_string(), span: list_span }); } } diff --git a/crates/nu-command/src/filters/roll/mod.rs b/crates/nu-command/src/filters/roll/mod.rs index c422a6b179..0c94a856ce 100644 --- a/crates/nu-command/src/filters/roll/mod.rs +++ b/crates/nu-command/src/filters/roll/mod.rs @@ -36,7 +36,10 @@ fn vertical_rotate_value( span, }) } - _ => Err(ShellError::TypeMismatch("list".to_string(), value.span()?)), + _ => Err(ShellError::TypeMismatch { + err_message: "list".to_string(), + span: value.span()?, + }), } } @@ -93,9 +96,9 @@ fn horizontal_rotate_value( Ok(Value::List { vals: values, span }) } - _ => Err(ShellError::TypeMismatch( - "record".to_string(), - value.span()?, - )), + _ => Err(ShellError::TypeMismatch { + err_message: "record".to_string(), + span: value.span()?, + }), } } diff --git a/crates/nu-command/src/filters/skip/skip_.rs b/crates/nu-command/src/filters/skip/skip_.rs index bfe6a12377..1274f96d5b 100644 --- a/crates/nu-command/src/filters/skip/skip_.rs +++ b/crates/nu-command/src/filters/skip/skip_.rs @@ -78,13 +78,18 @@ impl Command for Skip { let metadata = input.metadata(); let n: usize = match n { - Some(Value::Int { val, span }) => val.try_into().map_err(|err| { - ShellError::TypeMismatch( - format!("Could not convert {val} to unsigned integer: {err}"), + Some(Value::Int { val, span }) => { + val.try_into().map_err(|err| ShellError::TypeMismatch { + err_message: format!("Could not convert {val} to unsigned integer: {err}"), span, - ) - })?, - Some(_) => return Err(ShellError::TypeMismatch("expected integer".into(), span)), + })? + } + Some(_) => { + return Err(ShellError::TypeMismatch { + err_message: "expected integer".into(), + span, + }) + } None => 1, }; diff --git a/crates/nu-command/src/filters/sort_by.rs b/crates/nu-command/src/filters/sort_by.rs index 3ec5dd5c87..c606e03540 100644 --- a/crates/nu-command/src/filters/sort_by.rs +++ b/crates/nu-command/src/filters/sort_by.rs @@ -87,7 +87,10 @@ impl Command for SortBy { let mut vec: Vec<_> = input.into_iter_strict(call.head)?.collect(); if columns.is_empty() { - return Err(ShellError::MissingParameter("columns".into(), call.head)); + return Err(ShellError::MissingParameter { + param_name: "columns".into(), + span: call.head, + }); } crate::sort(&mut vec, columns, call.head, insensitive, natural)?; diff --git a/crates/nu-command/src/filters/uniq_by.rs b/crates/nu-command/src/filters/uniq_by.rs index 7510b4dd19..95bd1086f3 100644 --- a/crates/nu-command/src/filters/uniq_by.rs +++ b/crates/nu-command/src/filters/uniq_by.rs @@ -60,7 +60,10 @@ impl Command for UniqBy { let columns: Vec = call.rest(engine_state, stack, 0)?; if columns.is_empty() { - return Err(ShellError::MissingParameter("columns".into(), call.head)); + return Err(ShellError::MissingParameter { + param_name: "columns".into(), + span: call.head, + }); } let metadata = input.metadata(); diff --git a/crates/nu-command/src/formats/from/csv.rs b/crates/nu-command/src/formats/from/csv.rs index fc03cbfbf5..ac3237195b 100644 --- a/crates/nu-command/src/formats/from/csv.rs +++ b/crates/nu-command/src/formats/from/csv.rs @@ -124,10 +124,10 @@ fn from_csv( } else { let vec_s: Vec = s.chars().collect(); if vec_s.len() != 1 { - return Err(ShellError::MissingParameter( - "single character separator".into(), + return Err(ShellError::MissingParameter { + param_name: "single character separator".into(), span, - )); + }); }; vec_s[0] } diff --git a/crates/nu-command/src/formats/from/delimited.rs b/crates/nu-command/src/formats/from/delimited.rs index b5dbb24695..1b0d2dc86e 100644 --- a/crates/nu-command/src/formats/from/delimited.rs +++ b/crates/nu-command/src/formats/from/delimited.rs @@ -68,7 +68,10 @@ pub fn from_delimited_data( Ok( from_delimited_string_to_value(concat_string, noheaders, no_infer, sep, trim, name) - .map_err(|x| ShellError::DelimiterError(x.to_string(), name))? + .map_err(|x| ShellError::DelimiterError { + msg: x.to_string(), + span: name, + })? .into_pipeline_data_with_metadata(metadata), ) } @@ -80,11 +83,12 @@ pub fn trim_from_str(trim: Option) -> Result { "headers" => Ok(Trim::Headers), "fields" => Ok(Trim::Fields), "none" => Ok(Trim::None), - _ => Err(ShellError::TypeMismatch( - "the only possible values for trim are 'all', 'headers', 'fields' and 'none'" - .into(), + _ => Err(ShellError::TypeMismatch { + err_message: + "the only possible values for trim are 'all', 'headers', 'fields' and 'none'" + .into(), span, - )), + }), }, _ => Ok(Trim::None), } diff --git a/crates/nu-command/src/formats/from/ods.rs b/crates/nu-command/src/formats/from/ods.rs index 86d4e328f4..411ed70973 100644 --- a/crates/nu-command/src/formats/from/ods.rs +++ b/crates/nu-command/src/formats/from/ods.rs @@ -74,10 +74,10 @@ fn convert_columns(columns: &[Value], span: Span) -> Result, ShellEr .iter() .map(|value| match &value { Value::String { val: s, .. } => Ok(s.clone()), - _ => Err(ShellError::IncompatibleParametersSingle( - "Incorrect column format, Only string as column name".to_string(), - value.span().unwrap_or(span), - )), + _ => Err(ShellError::IncompatibleParametersSingle { + msg: "Incorrect column format, Only string as column name".to_string(), + span: value.span().unwrap_or(span), + }), }) .collect::, _>>()?; diff --git a/crates/nu-command/src/formats/from/xlsx.rs b/crates/nu-command/src/formats/from/xlsx.rs index e1198567c7..b0021e494b 100644 --- a/crates/nu-command/src/formats/from/xlsx.rs +++ b/crates/nu-command/src/formats/from/xlsx.rs @@ -74,10 +74,10 @@ fn convert_columns(columns: &[Value], span: Span) -> Result, ShellEr .iter() .map(|value| match &value { Value::String { val: s, .. } => Ok(s.clone()), - _ => Err(ShellError::IncompatibleParametersSingle( - "Incorrect column format, Only string as column name".to_string(), - value.span().unwrap_or(span), - )), + _ => Err(ShellError::IncompatibleParametersSingle { + msg: "Incorrect column format, Only string as column name".to_string(), + span: value.span().unwrap_or(span), + }), }) .collect::, _>>()?; diff --git a/crates/nu-command/src/formats/to/csv.rs b/crates/nu-command/src/formats/to/csv.rs index 64d27f3664..49c68c481e 100644 --- a/crates/nu-command/src/formats/to/csv.rs +++ b/crates/nu-command/src/formats/to/csv.rs @@ -88,10 +88,11 @@ fn to_csv( } else { let vec_s: Vec = s.chars().collect(); if vec_s.len() != 1 { - return Err(ShellError::TypeMismatch( - "Expected a single separator char from --separator".to_string(), + return Err(ShellError::TypeMismatch { + err_message: "Expected a single separator char from --separator" + .to_string(), span, - )); + }); }; vec_s[0] } diff --git a/crates/nu-command/src/generators/cal.rs b/crates/nu-command/src/generators/cal.rs index 9a199f7f2b..7015c48d1a 100644 --- a/crates/nu-command/src/generators/cal.rs +++ b/crates/nu-command/src/generators/cal.rs @@ -142,7 +142,10 @@ pub fn cal( } fn get_invalid_year_shell_error(head: Span) -> ShellError { - ShellError::TypeMismatch("The year is invalid".to_string(), head) + ShellError::TypeMismatch { + err_message: "The year is invalid".to_string(), + span: head, + } } struct MonthHelper { @@ -251,10 +254,10 @@ fn add_month_to_table( Err(()) => match full_year_value { Some(x) => return Err(get_invalid_year_shell_error(x.span)), None => { - return Err(ShellError::UnknownOperator( - "Issue parsing command, invalid command".to_string(), - tag, - )) + return Err(ShellError::UnknownOperator { + op_token: "Issue parsing command, invalid command".to_string(), + span: tag, + }) } }, }; @@ -275,10 +278,10 @@ fn add_month_to_table( if days_of_the_week.contains(&s.as_str()) { week_start_day = s.to_string(); } else { - return Err(ShellError::TypeMismatch( - "The specified week start day is invalid".to_string(), - day.span, - )); + return Err(ShellError::TypeMismatch { + err_message: "The specified week start day is invalid".to_string(), + span: day.span, + }); } } diff --git a/crates/nu-command/src/network/http/client.rs b/crates/nu-command/src/network/http/client.rs index b67be6b4fc..27b1e67888 100644 --- a/crates/nu-command/src/network/http/client.rs +++ b/crates/nu-command/src/network/http/client.rs @@ -210,11 +210,10 @@ pub fn request_set_timeout( if let Some(timeout) = timeout { let val = timeout.as_i64()?; if val.is_negative() || val < 1 { - return Err(ShellError::TypeMismatch( - "Timeout value must be an integer and larger than 0".to_string(), - // timeout is already guaranteed to not be an error - timeout.expect_span(), - )); + return Err(ShellError::TypeMismatch { + err_message: "Timeout value must be an integer and larger than 0".to_string(), + span: timeout.expect_span(), + }); } request = request.timeout(Duration::from_secs(val as u64)); diff --git a/crates/nu-command/src/network/url/join.rs b/crates/nu-command/src/network/url/join.rs index 14afc556d7..ca42ea529a 100644 --- a/crates/nu-command/src/network/url/join.rs +++ b/crates/nu-command/src/network/url/join.rs @@ -151,10 +151,12 @@ impl UrlComponents { port: Some(p), ..self }), - Err(_) => Err(ShellError::IncompatibleParametersSingle( - String::from("Port parameter should represent an unsigned integer"), + Err(_) => Err(ShellError::IncompatibleParametersSingle { + msg: String::from( + "Port parameter should represent an unsigned integer", + ), span, - )), + }), } } } @@ -163,12 +165,12 @@ impl UrlComponents { ..self }), Value::Error { error } => Err(error), - other => Err(ShellError::IncompatibleParametersSingle( - String::from( + other => Err(ShellError::IncompatibleParametersSingle { + msg: String::from( "Port parameter should be an unsigned integer or a string representing it", ), - other.expect_span(), - )), + span: other.expect_span(), + }), }; } @@ -210,10 +212,10 @@ impl UrlComponents { }) } Value::Error { error } => Err(error), - other => Err(ShellError::IncompatibleParametersSingle( - String::from("Key params has to be a record"), - other.expect_span(), - )), + other => Err(ShellError::IncompatibleParametersSingle { + msg: String::from("Key params has to be a record"), + span: other.expect_span(), + }), }; } @@ -324,7 +326,10 @@ impl UrlComponents { } fn generate_shell_error_for_missing_parameter(pname: String, span: Span) -> ShellError { - ShellError::MissingParameter(pname, span) + ShellError::MissingParameter { + param_name: pname, + span, + } } } diff --git a/crates/nu-command/src/platform/ansi/ansi_.rs b/crates/nu-command/src/platform/ansi/ansi_.rs index fda9dc0f51..4076215641 100644 --- a/crates/nu-command/src/platform/ansi/ansi_.rs +++ b/crates/nu-command/src/platform/ansi/ansi_.rs @@ -641,7 +641,12 @@ Format: # // this record is defined in nu-color-config crate let code: Value = match call.opt(engine_state, stack, 0)? { Some(c) => c, - None => return Err(ShellError::MissingParameter("code".into(), call.head)), + None => { + return Err(ShellError::MissingParameter { + param_name: "code".into(), + span: call.head, + }) + } }; let param_is_string = matches!(code, Value::String { val: _, span: _ }); @@ -672,12 +677,13 @@ Format: # if (escape || osc) && (param_is_valid_string) { let code_vec: Vec = code_string.chars().collect(); if code_vec[0] == '\\' { - return Err(ShellError::TypeMismatch( - "no need for escape characters".into(), - call.get_flag_expr("escape") + return Err(ShellError::TypeMismatch { + err_message: "no need for escape characters".into(), + span: call + .get_flag_expr("escape") .expect("Unexpected missing argument") .span, - )); + }); } } @@ -711,12 +717,13 @@ Format: # match str_to_ansi(&code_string) { Some(c) => c, None => { - return Err(ShellError::TypeMismatch( - String::from("Unknown ansi code"), - call.positional_nth(0) + return Err(ShellError::TypeMismatch { + err_message: String::from("Unknown ansi code"), + span: call + .positional_nth(0) .expect("Unexpected missing argument") .span, - )) + }) } } } @@ -737,10 +744,10 @@ Format: # "bg" => nu_style.bg = Some(v.as_string()?), "attr" => nu_style.attr = Some(v.as_string()?), _ => { - return Err(ShellError::IncompatibleParametersSingle( - format!("problem with key: {k}"), - code.expect_span(), - )) + return Err(ShellError::IncompatibleParametersSingle { + msg: format!("problem with key: {k}"), + span: code.expect_span(), + }) } } } diff --git a/crates/nu-command/src/platform/ansi/gradient.rs b/crates/nu-command/src/platform/ansi/gradient.rs index 03a3a82ddb..f8a18c1727 100644 --- a/crates/nu-command/src/platform/ansi/gradient.rs +++ b/crates/nu-command/src/platform/ansi/gradient.rs @@ -158,10 +158,11 @@ fn action( (None, None, None, None) => { // Error - no colors Value::Error { - error: ShellError::MissingParameter( - "please supply foreground and/or background color parameters".into(), - *command_span, - ), + error: ShellError::MissingParameter { + param_name: + "please supply foreground and/or background color parameters".into(), + span: *command_span, + }, } } (None, None, None, Some(bg_end)) => { @@ -285,7 +286,10 @@ fn action( let got = format!("value is {}, not string", other.get_type()); Value::Error { - error: ShellError::TypeMismatch(got, other.span().unwrap_or(*command_span)), + error: ShellError::TypeMismatch { + err_message: got, + span: other.span().unwrap_or(*command_span), + }, } } } diff --git a/crates/nu-command/src/platform/ansi/link.rs b/crates/nu-command/src/platform/ansi/link.rs index fdf92c1a2c..bdf79f3c06 100644 --- a/crates/nu-command/src/platform/ansi/link.rs +++ b/crates/nu-command/src/platform/ansi/link.rs @@ -139,7 +139,10 @@ fn process_value(value: &Value, text: &Option, command_span: &Span) -> V let got = format!("value is {}, not string", other.get_type()); Value::Error { - error: ShellError::TypeMismatch(got, other.span().unwrap_or(*command_span)), + error: ShellError::TypeMismatch { + err_message: got, + span: other.span().unwrap_or(*command_span), + }, } } } diff --git a/crates/nu-command/src/platform/ansi/strip.rs b/crates/nu-command/src/platform/ansi/strip.rs index 68b96cc2ef..ba611a1b72 100644 --- a/crates/nu-command/src/platform/ansi/strip.rs +++ b/crates/nu-command/src/platform/ansi/strip.rs @@ -58,7 +58,10 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, command_span: Span) -> Value let got = format!("value is {}, not string", other.get_type()); Value::Error { - error: ShellError::TypeMismatch(got, other.span().unwrap_or(command_span)), + error: ShellError::TypeMismatch { + err_message: got, + span: other.span().unwrap_or(command_span), + }, } } } diff --git a/crates/nu-command/src/strings/char_.rs b/crates/nu-command/src/strings/char_.rs index 9fa9250b7b..1a9c991a11 100644 --- a/crates/nu-command/src/strings/char_.rs +++ b/crates/nu-command/src/strings/char_.rs @@ -246,10 +246,10 @@ impl Command for Char { if call.has_flag("integer") { let args: Vec = call.rest(engine_state, stack, 0)?; if args.is_empty() { - return Err(ShellError::MissingParameter( - "missing at least one unicode character".into(), - call_span, - )); + return Err(ShellError::MissingParameter { + param_name: "missing at least one unicode character".into(), + span: call_span, + }); } let mut multi_byte = String::new(); for (i, &arg) in args.iter().enumerate() { @@ -263,10 +263,10 @@ impl Command for Char { } else if call.has_flag("unicode") { let args: Vec = call.rest(engine_state, stack, 0)?; if args.is_empty() { - return Err(ShellError::MissingParameter( - "missing at least one unicode character".into(), - call_span, - )); + return Err(ShellError::MissingParameter { + param_name: "missing at least one unicode character".into(), + span: call_span, + }); } let mut multi_byte = String::new(); for (i, arg) in args.iter().enumerate() { @@ -280,21 +280,22 @@ impl Command for Char { } else { let args: Vec = call.rest(engine_state, stack, 0)?; if args.is_empty() { - return Err(ShellError::MissingParameter( - "missing name of the character".into(), - call_span, - )); + return Err(ShellError::MissingParameter { + param_name: "missing name of the character".into(), + span: call_span, + }); } let special_character = str_to_character(&args[0]); if let Some(output) = special_character { Ok(Value::string(output, call_span).into_pipeline_data()) } else { - Err(ShellError::TypeMismatch( - "error finding named character".into(), - call.positional_nth(0) + Err(ShellError::TypeMismatch { + err_message: "error finding named character".into(), + span: call + .positional_nth(0) .expect("Unexpected missing argument") .span, - )) + }) } } } @@ -306,10 +307,10 @@ fn integer_to_unicode_char(value: i64, t: &Span) -> Result { if let Some(ch) = decoded_char { Ok(ch) } else { - Err(ShellError::TypeMismatch( - "not a valid Unicode codepoint".into(), - *t, - )) + Err(ShellError::TypeMismatch { + err_message: "not a valid Unicode codepoint".into(), + span: *t, + }) } } @@ -321,10 +322,10 @@ fn string_to_unicode_char(s: &str, t: &Span) -> Result { if let Some(ch) = decoded_char { Ok(ch) } else { - Err(ShellError::TypeMismatch( - "error decoding Unicode character".into(), - *t, - )) + Err(ShellError::TypeMismatch { + err_message: "error decoding Unicode character".into(), + span: *t, + }) } } diff --git a/crates/nu-command/src/strings/encode_decode/base64.rs b/crates/nu-command/src/strings/encode_decode/base64.rs index 6401b709e7..bb73f0a62a 100644 --- a/crates/nu-command/src/strings/encode_decode/base64.rs +++ b/crates/nu-command/src/strings/encode_decode/base64.rs @@ -187,10 +187,10 @@ fn action( } } other => Value::Error { - error: ShellError::TypeMismatch( - format!("string or binary, not {}", other.get_type()), - other.span().unwrap_or(command_span), - ), + error: ShellError::TypeMismatch { + err_message: format!("string or binary, not {}", other.get_type()), + span: other.span().unwrap_or(command_span), + }, }, } } diff --git a/crates/nu-command/src/strings/format/command.rs b/crates/nu-command/src/strings/format/command.rs index 9ef6173731..4e9d6d1fe9 100644 --- a/crates/nu-command/src/strings/format/command.rs +++ b/crates/nu-command/src/strings/format/command.rs @@ -157,10 +157,10 @@ fn extract_formatting_operations( } if column_span_end < column_span_start { - return Err(ShellError::DelimiterError( - "there are unmatched curly braces".to_string(), - error_span, - )); + return Err(ShellError::DelimiterError { + msg: "there are unmatched curly braces".to_string(), + span: error_span, + }); } if !column_name.is_empty() { @@ -301,10 +301,10 @@ fn format_record( } } Some(err) => { - return Err(ShellError::TypeMismatch( - format!("expression is invalid, detail message: {err:?}"), - *span, - )) + return Err(ShellError::TypeMismatch { + err_message: format!("expression is invalid, detail message: {err:?}"), + span: *span, + }) } } } diff --git a/crates/nu-command/src/strings/mod.rs b/crates/nu-command/src/strings/mod.rs index 10e59ab9d4..2d47afc576 100644 --- a/crates/nu-command/src/strings/mod.rs +++ b/crates/nu-command/src/strings/mod.rs @@ -26,16 +26,16 @@ pub fn grapheme_flags(call: &Call) -> Result { // Note that Nushell already prevents nonexistent flags from being used with commands, // so this function can be reused for both the --utf-8-bytes commands and the --code-points commands. if g_flag && call.has_flag("utf-8-bytes") { - Err(ShellError::IncompatibleParametersSingle( - "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(), - call.head, - ))? + Err(ShellError::IncompatibleParametersSingle { + msg: "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(), + span: call.head, + })? } if g_flag && call.has_flag("code-points") { - Err(ShellError::IncompatibleParametersSingle( - "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(), - call.head, - ))? + Err(ShellError::IncompatibleParametersSingle { + msg: "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(), + span: call.head, + })? } // Grapheme cluster usage is decided by the non-default -g flag Ok(g_flag) diff --git a/crates/nu-command/src/strings/parse.rs b/crates/nu-command/src/strings/parse.rs index 8e4e7898a7..1c795b2702 100644 --- a/crates/nu-command/src/strings/parse.rs +++ b/crates/nu-command/src/strings/parse.rs @@ -285,10 +285,10 @@ fn build_regex(input: &str, span: Span) -> Result { column.push(c); if loop_input.peek().is_none() { - return Err(ShellError::DelimiterError( - "Found opening `{` without an associated closing `}`".to_owned(), + return Err(ShellError::DelimiterError { + msg: "Found opening `{` without an associated closing `}`".to_owned(), span, - )); + }); } } diff --git a/crates/nu-command/src/strings/split/words.rs b/crates/nu-command/src/strings/split/words.rs index 7e9e229c8a..80895e073e 100644 --- a/crates/nu-command/src/strings/split/words.rs +++ b/crates/nu-command/src/strings/split/words.rs @@ -119,16 +119,16 @@ fn split_words( if matches!(word_length, None) { if call.has_flag("grapheme-clusters") { - return Err(ShellError::IncompatibleParametersSingle( - "--grapheme-clusters (-g) requires --min-word-length (-l)".to_string(), + return Err(ShellError::IncompatibleParametersSingle { + msg: "--grapheme-clusters (-g) requires --min-word-length (-l)".to_string(), span, - )); + }); } if call.has_flag("utf-8-bytes") { - return Err(ShellError::IncompatibleParametersSingle( - "--utf-8-bytes (-b) requires --min-word-length (-l)".to_string(), + return Err(ShellError::IncompatibleParametersSingle { + msg: "--utf-8-bytes (-b) requires --min-word-length (-l)".to_string(), span, - )); + }); } } let graphemes = grapheme_flags(call)?; diff --git a/crates/nu-command/src/strings/str_/index_of.rs b/crates/nu-command/src/strings/str_/index_of.rs index 2928076389..808a1e8f00 100644 --- a/crates/nu-command/src/strings/str_/index_of.rs +++ b/crates/nu-command/src/strings/str_/index_of.rs @@ -219,10 +219,10 @@ fn process_range( } Value::List { vals, .. } => { if vals.len() > 2 { - Err(ShellError::TypeMismatch( - String::from("there shouldn't be more than two indexes"), - head, - )) + Err(ShellError::TypeMismatch { + err_message: String::from("there shouldn't be more than two indexes"), + span: head, + }) } else { let idx: Vec = vals .iter() @@ -248,18 +248,15 @@ fn process_range( let end_index = r.1.parse::().unwrap_or(input_len as i32); if start_index < 0 || start_index > end_index { - return Err(ShellError::TypeMismatch( - String::from("start index can't be negative or greater than end index"), - head, - )); + return Err(ShellError::TypeMismatch { + err_message: String::from("start index can't be negative or greater than end index"), + span: head, + }); } if end_index < 0 || end_index < start_index || end_index > input_len as i32 { - return Err(ShellError::TypeMismatch( - String::from( - "end index can't be negative, smaller than start index or greater than input length"), - head, - )); + return Err(ShellError::TypeMismatch { err_message: String::from( + "end index can't be negative, smaller than start index or greater than input length"), span: head }); } Ok(IndexOfOptionalBounds(start_index, end_index)) } diff --git a/crates/nu-command/src/strings/str_/replace.rs b/crates/nu-command/src/strings/str_/replace.rs index 924cbd927a..b1c88bfee0 100644 --- a/crates/nu-command/src/strings/str_/replace.rs +++ b/crates/nu-command/src/strings/str_/replace.rs @@ -209,7 +209,10 @@ fn action( } } Err(e) => Value::Error { - error: ShellError::IncorrectValue(format!("Regex error: {e}"), find.span), + error: ShellError::IncorrectValue { + msg: format!("Regex error: {e}"), + span: find.span, + }, }, } } diff --git a/crates/nu-command/src/strings/str_/substring.rs b/crates/nu-command/src/strings/str_/substring.rs index d2f40595b3..5b253a7789 100644 --- a/crates/nu-command/src/strings/str_/substring.rs +++ b/crates/nu-command/src/strings/str_/substring.rs @@ -155,10 +155,10 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { match start.cmp(&end) { Ordering::Equal => Value::string("", head), Ordering::Greater => Value::Error { - error: ShellError::TypeMismatch( - "End must be greater than or equal to Start".to_string(), - head, - ), + error: ShellError::TypeMismatch { + err_message: "End must be greater than or equal to Start".to_string(), + span: head, + }, }, Ordering::Less => Value::String { val: { @@ -220,10 +220,10 @@ fn process_arguments(range: &Value, head: Span) -> Result<(isize, isize), ShellE } Value::List { vals, .. } => { if vals.len() > 2 { - Err(ShellError::TypeMismatch( - "More than two indices given".to_string(), - head, - )) + Err(ShellError::TypeMismatch { + err_message: "More than two indices given".to_string(), + span: head, + }) } else { let idx: Vec = vals .iter() @@ -231,11 +231,12 @@ fn process_arguments(range: &Value, head: Span) -> Result<(isize, isize), ShellE match v { Value::Int { val, .. } => Ok(val.to_string()), Value::String { val, .. } => Ok(val.to_string()), - _ => Err(ShellError::TypeMismatch( - "could not perform substring. Expecting a string or int" - .to_string(), - head, - )), + _ => Err(ShellError::TypeMismatch { + err_message: + "could not perform substring. Expecting a string or int" + .to_string(), + span: head, + }), } .unwrap_or_else(|_| String::from("")) }) @@ -243,14 +244,16 @@ fn process_arguments(range: &Value, head: Span) -> Result<(isize, isize), ShellE let start = idx .get(0) - .ok_or_else(|| { - ShellError::TypeMismatch("could not perform substring".to_string(), head) + .ok_or_else(|| ShellError::TypeMismatch { + err_message: "could not perform substring".to_string(), + span: head, })? .to_string(); let end = idx .get(1) - .ok_or_else(|| { - ShellError::TypeMismatch("could not perform substring".to_string(), head) + .ok_or_else(|| ShellError::TypeMismatch { + err_message: "could not perform substring".to_string(), + span: head, })? .to_string(); Ok(SubstringText(start, end)) @@ -261,35 +264,39 @@ fn process_arguments(range: &Value, head: Span) -> Result<(isize, isize), ShellE let start = idx .first() - .ok_or_else(|| { - ShellError::TypeMismatch("could not perform substring".to_string(), head) + .ok_or_else(|| ShellError::TypeMismatch { + err_message: "could not perform substring".to_string(), + span: head, })? .to_string(); let end = idx .get(1) - .ok_or_else(|| { - ShellError::TypeMismatch("could not perform substring".to_string(), head) + .ok_or_else(|| ShellError::TypeMismatch { + err_message: "could not perform substring".to_string(), + span: head, })? .to_string(); Ok(SubstringText(start, end)) } - _ => Err(ShellError::TypeMismatch( - "could not perform substring".to_string(), - head, - )), + _ => Err(ShellError::TypeMismatch { + err_message: "could not perform substring".to_string(), + span: head, + }), }?; let start = match &search { SubstringText(start, _) if start.is_empty() || start == "_" => 0, - SubstringText(start, _) => start.trim().parse().map_err(|_| { - ShellError::TypeMismatch("could not perform substring".to_string(), head) + SubstringText(start, _) => start.trim().parse().map_err(|_| ShellError::TypeMismatch { + err_message: "could not perform substring".to_string(), + span: head, })?, }; let end = match &search { SubstringText(_, end) if end.is_empty() || end == "_" => isize::max_value(), - SubstringText(_, end) => end.trim().parse().map_err(|_| { - ShellError::TypeMismatch("could not perform substring".to_string(), head) + SubstringText(_, end) => end.trim().parse().map_err(|_| ShellError::TypeMismatch { + err_message: "could not perform substring".to_string(), + span: head, })?, }; diff --git a/crates/nu-command/src/system/which_.rs b/crates/nu-command/src/system/which_.rs index 5758506d93..d370a45c22 100644 --- a/crates/nu-command/src/system/which_.rs +++ b/crates/nu-command/src/system/which_.rs @@ -254,10 +254,10 @@ fn which( let ctrlc = engine_state.ctrlc.clone(); if which_args.applications.is_empty() { - return Err(ShellError::MissingParameter( - "application".into(), - call.head, - )); + return Err(ShellError::MissingParameter { + param_name: "application".into(), + span: call.head, + }); } let mut output = vec![]; diff --git a/crates/nu-engine/src/env.rs b/crates/nu-engine/src/env.rs index 4424336e26..50b73a8a3e 100644 --- a/crates/nu-engine/src/env.rs +++ b/crates/nu-engine/src/env.rs @@ -360,10 +360,10 @@ fn get_converted_value( Err(e) => ConversionResult::ConversionError(e), } } else { - ConversionResult::ConversionError(ShellError::MissingParameter( - "block input".into(), - from_span, - )) + ConversionResult::ConversionError(ShellError::MissingParameter { + param_name: "block input".into(), + span: from_span, + }) } } else { ConversionResult::CellPathError diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index f0305f5112..a12a668f27 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -19,9 +19,10 @@ pub fn eval_operator(op: &Expression) -> Result { expr: Expr::Operator(operator), .. } => Ok(operator.clone()), - Expression { span, expr, .. } => { - Err(ShellError::UnknownOperator(format!("{expr:?}"), *span)) - } + Expression { span, expr, .. } => Err(ShellError::UnknownOperator { + op_token: format!("{expr:?}"), + span: *span, + }), } } @@ -339,7 +340,10 @@ pub fn eval_expression( let lhs = eval_expression(engine_state, stack, expr)?; match lhs { Value::Bool { val, .. } => Ok(Value::boolean(!val, expr.span)), - _ => Err(ShellError::TypeMismatch("bool".to_string(), expr.span)), + _ => Err(ShellError::TypeMismatch { + err_message: "bool".to_string(), + span: expr.span, + }), } } Expr::BinaryOp(lhs, op, rhs) => { @@ -454,7 +458,7 @@ pub fn eval_expression( stack.vars.insert(*var_id, rhs); Ok(Value::nothing(lhs.span)) } else { - Err(ShellError::AssignmentRequiresMutableVar(lhs.span)) + Err(ShellError::AssignmentRequiresMutableVar { lhs_span: lhs.span }) } } Expr::FullCellPath(cell_path) => match &cell_path.head.expr { @@ -496,12 +500,14 @@ pub fn eval_expression( } Ok(Value::nothing(cell_path.head.span)) } else { - Err(ShellError::AssignmentRequiresMutableVar(lhs.span)) + Err(ShellError::AssignmentRequiresMutableVar { + lhs_span: lhs.span, + }) } } - _ => Err(ShellError::AssignmentRequiresVar(lhs.span)), + _ => Err(ShellError::AssignmentRequiresVar { lhs_span: lhs.span }), }, - _ => Err(ShellError::AssignmentRequiresVar(lhs.span)), + _ => Err(ShellError::AssignmentRequiresVar { lhs_span: lhs.span }), } } } diff --git a/crates/nu-protocol/src/pipeline_data.rs b/crates/nu-protocol/src/pipeline_data.rs index 4a8c178f87..ac3da856a5 100644 --- a/crates/nu-protocol/src/pipeline_data.rs +++ b/crates/nu-protocol/src/pipeline_data.rs @@ -290,10 +290,14 @@ impl PipelineData { match self { PipelineData::Empty => Ok((String::new(), span, None)), PipelineData::Value(Value::String { val, span }, metadata) => Ok((val, span, metadata)), - PipelineData::Value(val, _) => { - Err(ShellError::TypeMismatch("string".into(), val.span()?)) - } - PipelineData::ListStream(_, _) => Err(ShellError::TypeMismatch("string".into(), span)), + PipelineData::Value(val, _) => Err(ShellError::TypeMismatch { + err_message: "string".into(), + span: val.span()?, + }), + PipelineData::ListStream(_, _) => Err(ShellError::TypeMismatch { + err_message: "string".into(), + span, + }), PipelineData::ExternalStream { stdout: None, metadata, diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index a21dd62b2b..01a3ee521f 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -98,17 +98,7 @@ pub enum ShellError { /// Convert the argument type before passing it in, or change the command to accept the type. #[error("Type mismatch.")] #[diagnostic(code(nu::shell::type_mismatch))] - TypeMismatch(String, #[label = "{0}"] Span), - - // TODO: merge with `TypeMismatch` as they are currently identical in capability - /// A command received an argument of the wrong type. - /// - /// ## Resolution - /// - /// Convert the argument type before passing it in, or change the command to accept the type. - #[error("Type mismatch.")] - #[diagnostic(code(nu::shell::type_mismatch))] - TypeMismatchGenericMessage { + TypeMismatch { err_message: String, #[label = "{err_message}"] span: Span, @@ -121,7 +111,11 @@ pub enum ShellError { /// Correct the argument value before passing it in or change the command. #[error("Incorrect value.")] #[diagnostic(code(nu::shell::incorrect_value))] - IncorrectValue(String, #[label = "{0}"] Span), + IncorrectValue { + msg: String, + #[label = "{msg}"] + span: Span, + }, /// This value cannot be used with this operator. /// @@ -129,45 +123,63 @@ pub enum ShellError { /// /// Not all values, for example custom values, can be used with all operators. Either /// implement support for the operator on this type, or convert the type to a supported one. - #[error("Unsupported operator: {0}.")] + #[error("Unsupported operator: {operator}.")] #[diagnostic(code(nu::shell::unsupported_operator))] - UnsupportedOperator(Operator, #[label = "unsupported operator"] Span), + UnsupportedOperator { + operator: Operator, + #[label = "unsupported operator"] + span: Span, + }, - /// This value cannot be used with this operator. + /// Invalid assignment left-hand side /// /// ## Resolution /// /// Assignment requires that you assign to a variable or variable cell path. #[error("Assignment operations require a variable.")] #[diagnostic(code(nu::shell::assignment_requires_variable))] - AssignmentRequiresVar(#[label = "needs to be a variable"] Span), + AssignmentRequiresVar { + #[label = "needs to be a variable"] + lhs_span: Span, + }, - /// This value cannot be used with this operator. + /// Invalid assignment left-hand side /// /// ## Resolution /// /// Assignment requires that you assign to a mutable variable or cell path. #[error("Assignment to an immutable variable.")] #[diagnostic(code(nu::shell::assignment_requires_mutable_variable))] - AssignmentRequiresMutableVar(#[label = "needs to be a mutable variable"] Span), + AssignmentRequiresMutableVar { + #[label = "needs to be a mutable variable"] + lhs_span: Span, + }, /// An operator was not recognized during evaluation. /// /// ## Resolution /// /// Did you write the correct operator? - #[error("Unknown operator: {0}.")] + #[error("Unknown operator: {op_token}.")] #[diagnostic(code(nu::shell::unknown_operator))] - UnknownOperator(String, #[label = "unknown operator"] Span), + UnknownOperator { + op_token: String, + #[label = "unknown operator"] + span: Span, + }, /// An expected command parameter is missing. /// /// ## Resolution /// /// Add the expected parameter and try again. - #[error("Missing parameter: {0}.")] + #[error("Missing parameter: {param_name}.")] #[diagnostic(code(nu::shell::missing_parameter))] - MissingParameter(String, #[label = "missing parameter: {0}"] Span), + MissingParameter { + param_name: String, + #[label = "missing parameter: {param_name}"] + span: Span, + }, /// Two parameters conflict with each other or are otherwise mutually exclusive. /// @@ -193,7 +205,11 @@ pub enum ShellError { /// Check your syntax for mismatched braces, RegExp syntax errors, etc, based on the specific error message. #[error("Delimiter error")] #[diagnostic(code(nu::shell::delimiter_error))] - DelimiterError(String, #[label("{0}")] Span), + DelimiterError { + msg: String, + #[label("{msg}")] + span: Span, + }, /// An operation received parameters with some sort of incompatibility /// (for example, different number of rows in a table, incompatible column names, etc). @@ -204,7 +220,11 @@ pub enum ShellError { /// inputs to make sure they match that way. #[error("Incompatible parameters.")] #[diagnostic(code(nu::shell::incompatible_parameters))] - IncompatibleParametersSingle(String, #[label = "{0}"] Span), + IncompatibleParametersSingle { + msg: String, + #[label = "{msg}"] + span: Span, + }, /// This build of nushell implements this feature, but it has not been enabled. /// diff --git a/crates/nu-protocol/src/value/custom_value.rs b/crates/nu-protocol/src/value/custom_value.rs index 25470dd900..40cf474ad1 100644 --- a/crates/nu-protocol/src/value/custom_value.rs +++ b/crates/nu-protocol/src/value/custom_value.rs @@ -55,6 +55,6 @@ pub trait CustomValue: fmt::Debug + Send + Sync { op: Span, _right: &Value, ) -> Result { - Err(ShellError::UnsupportedOperator(operator, op)) + Err(ShellError::UnsupportedOperator { operator, span: op }) } } diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 1a8af630d8..cdfbee834f 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -763,7 +763,7 @@ impl Value { // Records (and tables) are the only built-in which support column names, // so only use this message for them. Value::Record { .. } => { - err_or_null!(ShellError::TypeMismatchGenericMessage { + err_or_null!(ShellError::TypeMismatch { err_message: "Can't access record values with a row index. Try specifying a column name instead".into(), span: *origin_span, }, *origin_span) } @@ -2573,7 +2573,10 @@ impl Value { && (self.get_type() != Type::Any) && (rhs.get_type() != Type::Any) { - return Err(ShellError::TypeMismatch("compatible type".to_string(), op)); + return Err(ShellError::TypeMismatch { + err_message: "compatible type".to_string(), + span: op, + }); } if let Some(ordering) = self.partial_cmp(rhs) { @@ -2606,7 +2609,10 @@ impl Value { && (self.get_type() != Type::Any) && (rhs.get_type() != Type::Any) { - return Err(ShellError::TypeMismatch("compatible type".to_string(), op)); + return Err(ShellError::TypeMismatch { + err_message: "compatible type".to_string(), + span: op, + }); } self.partial_cmp(rhs) @@ -2637,7 +2643,10 @@ impl Value { && (self.get_type() != Type::Any) && (rhs.get_type() != Type::Any) { - return Err(ShellError::TypeMismatch("compatible type".to_string(), op)); + return Err(ShellError::TypeMismatch { + err_message: "compatible type".to_string(), + span: op, + }); } self.partial_cmp(rhs) @@ -2668,7 +2677,10 @@ impl Value { && (self.get_type() != Type::Any) && (rhs.get_type() != Type::Any) { - return Err(ShellError::TypeMismatch("compatible type".to_string(), op)); + return Err(ShellError::TypeMismatch { + err_message: "compatible type".to_string(), + span: op, + }); } match self.partial_cmp(rhs) { diff --git a/src/command.rs b/src/command.rs index 68ade3b2bc..5aab712756 100644 --- a/src/command.rs +++ b/src/command.rs @@ -121,7 +121,10 @@ pub(crate) fn parse_commandline_args( span: expr.span, })) } else { - Err(ShellError::TypeMismatch("string".into(), expr.span)) + Err(ShellError::TypeMismatch { + err_message: "string".into(), + span: expr.span, + }) } } else { Ok(None)