From 67eec92e761b023c67fa8c97b34eb81f122f2cfd Mon Sep 17 00:00:00 2001 From: Eric Hodel Date: Mon, 4 Dec 2023 01:19:32 -0800 Subject: [PATCH] Convert more ShellError variants to named fields (#11222) # Description Convert errors to named fields: * NeedsPositiveValue * MissingConfigValue * UnsupportedConfigValue * DowncastNotPossible * NonUtf8Custom * NonUtf8 * DidYouMeanCustom * DidYouMean * ReadingFile * RemoveNotPossible * ChangedModifiedTimeNotPossible * ChangedAccessTimeNotPossible Part of #10700 --- crates/nu-cli/src/eval_file.rs | 8 +- crates/nu-cli/src/reedline_config.rs | 174 +++++++++--------- crates/nu-cmd-base/src/hook.rs | 58 +++--- .../src/dataframe/values/nu_dataframe/mod.rs | 5 +- .../values/nu_dataframe/operations.rs | 8 +- .../values/nu_expression/custom_value.rs | 5 +- .../nu-cmd-lang/src/core_commands/hide_env.rs | 10 +- .../src/core_commands/overlay/use_.rs | 4 +- .../nu-command/src/charting/hashable_value.rs | 8 +- .../nu-command/src/database/values/sqlite.rs | 18 +- crates/nu-command/src/filesystem/ls.rs | 6 +- crates/nu-command/src/filesystem/rm.rs | 2 +- crates/nu-command/src/filesystem/touch.rs | 27 +-- crates/nu-command/src/filters/drop/column.rs | 2 +- crates/nu-command/src/filters/first.rs | 2 +- crates/nu-command/src/filters/last.rs | 2 +- crates/nu-command/src/formats/from/csv.rs | 8 +- crates/nu-command/src/formats/to/xml.rs | 2 +- crates/nu-command/src/network/url/join.rs | 20 +- crates/nu-command/src/platform/du.rs | 8 +- crates/nu-plugin/src/protocol/mod.rs | 2 +- crates/nu-protocol/src/config/helper.rs | 5 +- crates/nu-protocol/src/config/hooks.rs | 19 +- crates/nu-protocol/src/shell_error.rs | 74 ++++++-- crates/nu-protocol/src/value/from_value.rs | 14 +- crates/nu-protocol/src/value/mod.rs | 16 +- 26 files changed, 299 insertions(+), 208 deletions(-) diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index e630327697..4442f9e844 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -47,13 +47,13 @@ pub fn evaluate_file( let working_set = StateWorkingSet::new(engine_state); report_error( &working_set, - &ShellError::NonUtf8Custom( - format!( + &ShellError::NonUtf8Custom { + msg: format!( "Input file name '{}' is not valid UTF8", file_path.to_string_lossy() ), - Span::unknown(), - ), + span: Span::unknown(), + }, ); std::process::exit(1); }); diff --git a/crates/nu-cli/src/reedline_config.rs b/crates/nu-cli/src/reedline_config.rs index bd2bba5762..efd54d597d 100644 --- a/crates/nu-cli/src/reedline_config.rs +++ b/crates/nu-cli/src/reedline_config.rs @@ -139,18 +139,18 @@ fn add_menu( "columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config), "list" => add_list_menu(line_editor, menu, engine_state, stack, config), "description" => add_description_menu(line_editor, menu, engine_state, stack, config), - _ => Err(ShellError::UnsupportedConfigValue( - "columnar, list or description".to_string(), - menu.menu_type.into_abbreviated_string(config), - menu.menu_type.span(), - )), + _ => Err(ShellError::UnsupportedConfigValue { + expected: "columnar, list or description".to_string(), + value: menu.menu_type.into_abbreviated_string(config), + span: menu.menu_type.span(), + }), } } else { - Err(ShellError::UnsupportedConfigValue( - "only record type".to_string(), - menu.menu_type.into_abbreviated_string(config), - menu.menu_type.span(), - )) + Err(ShellError::UnsupportedConfigValue { + expected: "only record type".to_string(), + value: menu.menu_type.into_abbreviated_string(config), + span: menu.menu_type.span(), + }) } } @@ -261,11 +261,11 @@ pub(crate) fn add_columnar_menu( completer: Box::new(menu_completer), })) } - _ => Err(ShellError::UnsupportedConfigValue( - "block or omitted value".to_string(), - menu.source.into_abbreviated_string(config), + _ => Err(ShellError::UnsupportedConfigValue { + expected: "block or omitted value".to_string(), + value: menu.source.into_abbreviated_string(config), span, - )), + }), } } @@ -343,11 +343,11 @@ pub(crate) fn add_list_menu( completer: Box::new(menu_completer), })) } - _ => Err(ShellError::UnsupportedConfigValue( - "block or omitted value".to_string(), - menu.source.into_abbreviated_string(config), - menu.source.span(), - )), + _ => Err(ShellError::UnsupportedConfigValue { + expected: "block or omitted value".to_string(), + value: menu.source.into_abbreviated_string(config), + span: menu.source.span(), + }), } } @@ -461,11 +461,11 @@ pub(crate) fn add_description_menu( completer: Box::new(menu_completer), })) } - _ => Err(ShellError::UnsupportedConfigValue( - "closure or omitted value".to_string(), - menu.source.into_abbreviated_string(config), - menu.source.span(), - )), + _ => Err(ShellError::UnsupportedConfigValue { + expected: "closure or omitted value".to_string(), + value: menu.source.into_abbreviated_string(config), + span: menu.source.span(), + }), } } @@ -580,11 +580,11 @@ fn add_keybinding( "emacs" => add_parsed_keybinding(emacs_keybindings, keybinding, config), "vi_insert" => add_parsed_keybinding(insert_keybindings, keybinding, config), "vi_normal" => add_parsed_keybinding(normal_keybindings, keybinding, config), - m => Err(ShellError::UnsupportedConfigValue( - "emacs, vi_insert or vi_normal".to_string(), - m.to_string(), + m => Err(ShellError::UnsupportedConfigValue { + expected: "emacs, vi_insert or vi_normal".to_string(), + value: m.to_string(), span, - )), + }), }, Value::List { vals, .. } => { for inner_mode in vals { @@ -600,11 +600,11 @@ fn add_keybinding( Ok(()) } - v => Err(ShellError::UnsupportedConfigValue( - "string or list of strings".to_string(), - v.into_abbreviated_string(config), - v.span(), - )), + v => Err(ShellError::UnsupportedConfigValue { + expected: "string or list of strings".to_string(), + value: v.into_abbreviated_string(config), + span: v.span(), + }), } } @@ -630,11 +630,11 @@ fn add_parsed_keybinding( KeyModifiers::CONTROL | KeyModifiers::ALT | KeyModifiers::SHIFT } _ => { - return Err(ShellError::UnsupportedConfigValue( - "CONTROL, SHIFT, ALT or NONE".to_string(), - keybinding.modifier.into_abbreviated_string(config), - keybinding.modifier.span(), - )) + return Err(ShellError::UnsupportedConfigValue { + expected: "CONTROL, SHIFT, ALT or NONE".to_string(), + value: keybinding.modifier.into_abbreviated_string(config), + span: keybinding.modifier.span(), + }) } }; @@ -654,11 +654,11 @@ fn add_parsed_keybinding( let char = if let (Some(char), None) = (pos1, pos2) { char } else { - return Err(ShellError::UnsupportedConfigValue( - "char_".to_string(), - c.to_string(), - keybinding.keycode.span(), - )); + return Err(ShellError::UnsupportedConfigValue { + expected: "char_".to_string(), + value: c.to_string(), + span: keybinding.keycode.span(), + }); }; KeyCode::Char(char) @@ -681,21 +681,21 @@ fn add_parsed_keybinding( .parse() .ok() .filter(|num| matches!(num, 1..=20)) - .ok_or(ShellError::UnsupportedConfigValue( - "(f1|f2|...|f20)".to_string(), - format!("unknown function key: {c}"), - keybinding.keycode.span(), - ))?; + .ok_or(ShellError::UnsupportedConfigValue { + expected: "(f1|f2|...|f20)".to_string(), + value: format!("unknown function key: {c}"), + span: keybinding.keycode.span(), + })?; KeyCode::F(fn_num) } "null" => KeyCode::Null, "esc" | "escape" => KeyCode::Esc, _ => { - return Err(ShellError::UnsupportedConfigValue( - "crossterm KeyCode".to_string(), - keybinding.keycode.into_abbreviated_string(config), - keybinding.keycode.span(), - )) + return Err(ShellError::UnsupportedConfigValue { + expected: "crossterm KeyCode".to_string(), + value: keybinding.keycode.into_abbreviated_string(config), + span: keybinding.keycode.span(), + }) } }; if let Some(event) = parse_event(&keybinding.event, config)? { @@ -719,7 +719,10 @@ impl<'config> EventType<'config> { .map(Self::Send) .or_else(|_| extract_value("edit", record, span).map(Self::Edit)) .or_else(|_| extract_value("until", record, span).map(Self::Until)) - .map_err(|_| ShellError::MissingConfigValue("send, edit or until".to_string(), span)) + .map_err(|_| ShellError::MissingConfigValue { + missing_value: "send, edit or until".to_string(), + span, + }) } } @@ -749,11 +752,11 @@ fn parse_event(value: &Value, config: &Config) -> Result, .iter() .map(|value| match parse_event(value, config) { Ok(inner) => match inner { - None => Err(ShellError::UnsupportedConfigValue( - "List containing valid events".to_string(), - "Nothing value (null)".to_string(), - value.span(), - )), + None => Err(ShellError::UnsupportedConfigValue { + expected: "List containing valid events".to_string(), + value: "Nothing value (null)".to_string(), + span: value.span(), + }), Some(event) => Ok(event), }, Err(e) => Err(e), @@ -762,11 +765,11 @@ fn parse_event(value: &Value, config: &Config) -> Result, Ok(Some(ReedlineEvent::UntilFound(events))) } - v => Err(ShellError::UnsupportedConfigValue( - "list of events".to_string(), - v.into_abbreviated_string(config), - v.span(), - )), + v => Err(ShellError::UnsupportedConfigValue { + expected: "list of events".to_string(), + value: v.into_abbreviated_string(config), + span: v.span(), + }), }, }, Value::List { vals, .. } => { @@ -774,11 +777,11 @@ fn parse_event(value: &Value, config: &Config) -> Result, .iter() .map(|value| match parse_event(value, config) { Ok(inner) => match inner { - None => Err(ShellError::UnsupportedConfigValue( - "List containing valid events".to_string(), - "Nothing value (null)".to_string(), - value.span(), - )), + None => Err(ShellError::UnsupportedConfigValue { + expected: "List containing valid events".to_string(), + value: "Nothing value (null)".to_string(), + span: value.span(), + }), Some(event) => Ok(event), }, Err(e) => Err(e), @@ -788,11 +791,11 @@ fn parse_event(value: &Value, config: &Config) -> Result, Ok(Some(ReedlineEvent::Multiple(events))) } Value::Nothing { .. } => Ok(None), - v => Err(ShellError::UnsupportedConfigValue( - "record or list of records, null to unbind key".to_string(), - v.into_abbreviated_string(config), - v.span(), - )), + v => Err(ShellError::UnsupportedConfigValue { + expected: "record or list of records, null to unbind key".to_string(), + value: v.into_abbreviated_string(config), + span: v.span(), + }), } } @@ -840,11 +843,11 @@ fn event_from_record( ReedlineEvent::ExecuteHostCommand(cmd.into_string("", config)) } v => { - return Err(ShellError::UnsupportedConfigValue( - "Reedline event".to_string(), - v.to_string(), + return Err(ShellError::UnsupportedConfigValue { + expected: "Reedline event".to_string(), + value: v.to_string(), span, - )) + }) } }; @@ -954,11 +957,11 @@ fn edit_from_record( } "complete" => EditCommand::Complete, e => { - return Err(ShellError::UnsupportedConfigValue( - "reedline EditCommand".to_string(), - e.to_string(), + return Err(ShellError::UnsupportedConfigValue { + expected: "reedline EditCommand".to_string(), + value: e.to_string(), span, - )) + }) } }; @@ -971,7 +974,10 @@ fn extract_char(value: &Value, config: &Config) -> Result { .into_string("", config) .chars() .next() - .ok_or_else(|| ShellError::MissingConfigValue("char to insert".to_string(), span)) + .ok_or_else(|| ShellError::MissingConfigValue { + missing_value: "char to insert".to_string(), + span, + }) } #[cfg(test)] @@ -1101,6 +1107,6 @@ mod test { let span = Span::test_data(); let b = EventType::try_from_record(&event, span); - assert!(matches!(b, Err(ShellError::MissingConfigValue(_, _)))); + assert!(matches!(b, Err(ShellError::MissingConfigValue { .. }))); } } diff --git a/crates/nu-cmd-base/src/hook.rs b/crates/nu-cmd-base/src/hook.rs index ad7368f88c..d3893e006a 100644 --- a/crates/nu-cmd-base/src/hook.rs +++ b/crates/nu-cmd-base/src/hook.rs @@ -90,11 +90,11 @@ pub fn eval_hook( if let Some(err) = working_set.parse_errors.first() { report_error(&working_set, err); - return Err(ShellError::UnsupportedConfigValue( - "valid source code".into(), - "source code with syntax errors".into(), + return Err(ShellError::UnsupportedConfigValue { + expected: "valid source code".into(), + value: "source code with syntax errors".into(), span, - )); + }); } (output, working_set.render(), vars) @@ -164,11 +164,11 @@ pub fn eval_hook( { val } else { - return Err(ShellError::UnsupportedConfigValue( - "boolean output".to_string(), - "other PipelineData variant".to_string(), - other_span, - )); + return Err(ShellError::UnsupportedConfigValue { + expected: "boolean output".to_string(), + value: "other PipelineData variant".to_string(), + span: other_span, + }); } } Err(err) => { @@ -176,11 +176,11 @@ pub fn eval_hook( } } } else { - return Err(ShellError::UnsupportedConfigValue( - "block".to_string(), - format!("{}", condition.get_type()), - other_span, - )); + return Err(ShellError::UnsupportedConfigValue { + expected: "block".to_string(), + value: format!("{}", condition.get_type()), + span: other_span, + }); } } else { // always run the hook @@ -222,11 +222,11 @@ pub fn eval_hook( if let Some(err) = working_set.parse_errors.first() { report_error(&working_set, err); - return Err(ShellError::UnsupportedConfigValue( - "valid source code".into(), - "source code with syntax errors".into(), - source_span, - )); + return Err(ShellError::UnsupportedConfigValue { + expected: "valid source code".into(), + value: "source code with syntax errors".into(), + span: source_span, + }); } (output, working_set.render(), vars) @@ -277,11 +277,11 @@ pub fn eval_hook( )?; } other => { - return Err(ShellError::UnsupportedConfigValue( - "block or string".to_string(), - format!("{}", other.get_type()), - source_span, - )); + return Err(ShellError::UnsupportedConfigValue { + expected: "block or string".to_string(), + value: format!("{}", other.get_type()), + span: source_span, + }); } } } @@ -293,11 +293,11 @@ pub fn eval_hook( output = run_hook_block(engine_state, stack, val.block_id, input, arguments, span)?; } other => { - return Err(ShellError::UnsupportedConfigValue( - "string, block, record, or list of commands".into(), - format!("{}", other.get_type()), - other.span(), - )); + return Err(ShellError::UnsupportedConfigValue { + expected: "string, block, record, or list of commands".into(), + value: format!("{}", other.get_type()), + span: other.span(), + }); } } diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/mod.rs index 6e27296b60..79d0569551 100644 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/mod.rs +++ b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/mod.rs @@ -288,7 +288,10 @@ impl NuDataFrame { .collect::>(); let option = did_you_mean(&possibilities, column).unwrap_or_else(|| column.to_string()); - ShellError::DidYouMean(option, span) + ShellError::DidYouMean { + suggestion: option, + span, + } })?; let df = DataFrame::new(vec![s.clone()]).map_err(|e| { diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/operations.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/operations.rs index 4d18eb915b..683d0260ec 100644 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/operations.rs +++ b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/operations.rs @@ -24,10 +24,10 @@ impl NuDataFrame { match right { Value::CustomValue { val: rhs, .. } => { let rhs = rhs.as_any().downcast_ref::().ok_or_else(|| { - ShellError::DowncastNotPossible( - "Unable to create dataframe".to_string(), - rhs_span, - ) + ShellError::DowncastNotPossible { + msg: "Unable to create dataframe".to_string(), + span: rhs_span, + } })?; match (self.is_series(), rhs.is_series()) { diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/custom_value.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/custom_value.rs index a418ecf4c3..8b54221e82 100644 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/custom_value.rs +++ b/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/custom_value.rs @@ -57,7 +57,10 @@ fn compute_with_value( match right { Value::CustomValue { val: rhs, .. } => { let rhs = rhs.as_any().downcast_ref::().ok_or_else(|| { - ShellError::DowncastNotPossible("Unable to create expression".to_string(), rhs_span) + ShellError::DowncastNotPossible { + msg: "Unable to create expression".into(), + span: rhs_span, + } })?; match rhs.as_ref() { diff --git a/crates/nu-cmd-lang/src/core_commands/hide_env.rs b/crates/nu-cmd-lang/src/core_commands/hide_env.rs index 403f5a7a92..ba589e97f2 100644 --- a/crates/nu-cmd-lang/src/core_commands/hide_env.rs +++ b/crates/nu-cmd-lang/src/core_commands/hide_env.rs @@ -52,11 +52,11 @@ impl Command for HideEnv { .cloned() .collect(); if let Some(closest_match) = did_you_mean(&all_names, &name.item) { - return Err(ShellError::DidYouMeanCustom( - format!("Environment variable '{}' not found", name.item), - closest_match, - name.span, - )); + return Err(ShellError::DidYouMeanCustom { + msg: format!("Environment variable '{}' not found", name.item), + suggestion: closest_match, + span: name.span, + }); } else { return Err(ShellError::EnvVarNotFoundAtRuntime { envvar_name: name.item, diff --git a/crates/nu-cmd-lang/src/core_commands/overlay/use_.rs b/crates/nu-cmd-lang/src/core_commands/overlay/use_.rs index c5a14f4cb4..465ac12771 100644 --- a/crates/nu-cmd-lang/src/core_commands/overlay/use_.rs +++ b/crates/nu-cmd-lang/src/core_commands/overlay/use_.rs @@ -96,7 +96,9 @@ impl Command for OverlayUse { if let Some(name) = os_str.to_str() { name.to_string() } else { - return Err(ShellError::NonUtf8(name_arg.span)); + return Err(ShellError::NonUtf8 { + span: name_arg.span, + }); } } else { return Err(ShellError::OverlayNotFoundAtRuntime { diff --git a/crates/nu-command/src/charting/hashable_value.rs b/crates/nu-command/src/charting/hashable_value.rs index b8c665b197..dda79f2ceb 100644 --- a/crates/nu-command/src/charting/hashable_value.rs +++ b/crates/nu-command/src/charting/hashable_value.rs @@ -248,7 +248,13 @@ mod test { span, ), Value::nothing(span), - Value::error(ShellError::DidYouMean("what?".to_string(), span), span), + Value::error( + ShellError::DidYouMean { + suggestion: "what?".to_string(), + span, + }, + span, + ), Value::cell_path( CellPath { members: vec![PathMember::Int { diff --git a/crates/nu-command/src/database/values/sqlite.rs b/crates/nu-command/src/database/values/sqlite.rs index a922baf5f3..3a43773037 100644 --- a/crates/nu-command/src/database/values/sqlite.rs +++ b/crates/nu-command/src/database/values/sqlite.rs @@ -42,17 +42,25 @@ impl SQLiteDatabase { span: Span, ctrlc: Option>, ) -> Result { - let mut file = - File::open(path).map_err(|e| ShellError::ReadingFile(e.to_string(), span))?; + let mut file = File::open(path).map_err(|e| ShellError::ReadingFile { + msg: e.to_string(), + span, + })?; let mut buf: [u8; 16] = [0; 16]; file.read_exact(&mut buf) - .map_err(|e| ShellError::ReadingFile(e.to_string(), span)) + .map_err(|e| ShellError::ReadingFile { + msg: e.to_string(), + span, + }) .and_then(|_| { if buf == SQLITE_MAGIC_BYTES { Ok(SQLiteDatabase::new(path, ctrlc)) } else { - Err(ShellError::ReadingFile("Not a SQLite file".into(), span)) + Err(ShellError::ReadingFile { + msg: "Not a SQLite file".into(), + span, + }) } }) } @@ -515,7 +523,7 @@ pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value { ValueRef::Text(buf) => { let s = match std::str::from_utf8(buf) { Ok(v) => v, - Err(_) => return Value::error(ShellError::NonUtf8(span), span), + Err(_) => return Value::error(ShellError::NonUtf8 { span }, span), }; Value::string(s.to_string(), span) } diff --git a/crates/nu-command/src/filesystem/ls.rs b/crates/nu-command/src/filesystem/ls.rs index 5587a46172..65bb07df09 100644 --- a/crates/nu-command/src/filesystem/ls.rs +++ b/crates/nu-command/src/filesystem/ls.rs @@ -746,14 +746,14 @@ mod windows_helper { &mut find_data, ) { Ok(_) => Ok(find_data), - Err(e) => Err(ShellError::ReadingFile( - format!( + Err(e) => Err(ShellError::ReadingFile { + msg: format!( "Could not read metadata for '{}':\n '{}'", filename.to_string_lossy(), e ), span, - )), + }), } } } diff --git a/crates/nu-command/src/filesystem/rm.rs b/crates/nu-command/src/filesystem/rm.rs index 7b7fede149..a1ffeccc14 100644 --- a/crates/nu-command/src/filesystem/rm.rs +++ b/crates/nu-command/src/filesystem/rm.rs @@ -393,7 +393,7 @@ fn rm( if let Err(e) = result { let msg = format!("Could not delete {:}: {e:}", f.to_string_lossy()); - Value::error(ShellError::RemoveNotPossible(msg, span), span) + Value::error(ShellError::RemoveNotPossible { msg, span }, span) } else if verbose { let msg = if interactive && !confirmed { "not deleted" diff --git a/crates/nu-command/src/filesystem/touch.rs b/crates/nu-command/src/filesystem/touch.rs index e5cbdacb62..81e8ace5fb 100644 --- a/crates/nu-command/src/filesystem/touch.rs +++ b/crates/nu-command/src/filesystem/touch.rs @@ -151,12 +151,13 @@ impl Command for Touch { &item, FileTime::from_system_time(date.expect("should be a valid date").into()), ) { - return Err(ShellError::ChangeModifiedTimeNotPossible( - format!("Failed to change the modified time: {err}"), - call.positional_nth(index) + return Err(ShellError::ChangeModifiedTimeNotPossible { + msg: format!("Failed to change the modified time: {err}"), + span: call + .positional_nth(index) .expect("already checked positional") .span, - )); + }); }; } @@ -170,12 +171,13 @@ impl Command for Touch { ref_date_atime.expect("should be a valid date").into(), ), ) { - return Err(ShellError::ChangeAccessTimeNotPossible( - format!("Failed to change the access time: {err}"), - call.positional_nth(index) + return Err(ShellError::ChangeAccessTimeNotPossible { + msg: format!("Failed to change the access time: {err}"), + span: call + .positional_nth(index) .expect("already checked positional") .span, - )); + }); }; } else { // Should not panic as we return an error above if we can't parse the date @@ -183,12 +185,13 @@ impl Command for Touch { &item, FileTime::from_system_time(date.expect("should be a valid date").into()), ) { - return Err(ShellError::ChangeAccessTimeNotPossible( - format!("Failed to change the access time: {err}"), - call.positional_nth(index) + return Err(ShellError::ChangeAccessTimeNotPossible { + msg: format!("Failed to change the access time: {err}"), + span: call + .positional_nth(index) .expect("already checked positional") .span, - )); + }); }; } } diff --git a/crates/nu-command/src/filters/drop/column.rs b/crates/nu-command/src/filters/drop/column.rs index d7c20c40b3..f62959ee2b 100644 --- a/crates/nu-command/src/filters/drop/column.rs +++ b/crates/nu-command/src/filters/drop/column.rs @@ -50,7 +50,7 @@ impl Command for DropColumn { let columns = if let Some(columns) = columns { if columns.item < 0 { - return Err(ShellError::NeedsPositiveValue(columns.span)); + return Err(ShellError::NeedsPositiveValue { span: columns.span }); } else { columns.item as usize } diff --git a/crates/nu-command/src/filters/first.rs b/crates/nu-command/src/filters/first.rs index c3f2f2809c..864e2689ea 100644 --- a/crates/nu-command/src/filters/first.rs +++ b/crates/nu-command/src/filters/first.rs @@ -96,7 +96,7 @@ fn first_helper( // the first N elements is covered by `take` let return_single_element = rows.is_none(); let rows_desired: usize = match rows { - Some(i) if i < 0 => return Err(ShellError::NeedsPositiveValue(head)), + Some(i) if i < 0 => return Err(ShellError::NeedsPositiveValue { span: head }), Some(x) => x as usize, None => 1, }; diff --git a/crates/nu-command/src/filters/last.rs b/crates/nu-command/src/filters/last.rs index 2a5135f8f2..37535af4f3 100644 --- a/crates/nu-command/src/filters/last.rs +++ b/crates/nu-command/src/filters/last.rs @@ -77,7 +77,7 @@ impl Command for Last { // It has the same issue. let return_single_element = rows.is_none(); let rows_desired: usize = match rows { - Some(i) if i < 0 => return Err(ShellError::NeedsPositiveValue(head)), + Some(i) if i < 0 => return Err(ShellError::NeedsPositiveValue { span: head }), Some(x) => x as usize, None => 1, }; diff --git a/crates/nu-command/src/formats/from/csv.rs b/crates/nu-command/src/formats/from/csv.rs index 679d2d1e30..be54fd0e86 100644 --- a/crates/nu-command/src/formats/from/csv.rs +++ b/crates/nu-command/src/formats/from/csv.rs @@ -145,10 +145,10 @@ fn from_csv( let unicode_sep = u32::from_str_radix(&sep, 16); char::from_u32(unicode_sep.unwrap_or(b'\x1f' as u32)).unwrap_or(',') } else { - return Err(ShellError::NonUtf8Custom( - "separator should be a single char or a 4-byte unicode".to_string(), - call.span(), - )); + return Err(ShellError::NonUtf8Custom { + msg: "separator should be a single char or a 4-byte unicode".into(), + span: call.span(), + }); } } None => ',', diff --git a/crates/nu-command/src/formats/to/xml.rs b/crates/nu-command/src/formats/to/xml.rs index 95a3c16701..57026f4452 100644 --- a/crates/nu-command/src/formats/to/xml.rs +++ b/crates/nu-command/src/formats/to/xml.rs @@ -390,7 +390,7 @@ fn to_xml( let s = if let Ok(s) = String::from_utf8(b) { s } else { - return Err(ShellError::NonUtf8(head)); + return Err(ShellError::NonUtf8 { span: head }); }; Ok(Value::string(s, head).into_pipeline_data()) }) diff --git a/crates/nu-command/src/network/url/join.rs b/crates/nu-command/src/network/url/join.rs index 488d0aa8ee..1a1f96adae 100644 --- a/crates/nu-command/src/network/url/join.rs +++ b/crates/nu-command/src/network/url/join.rs @@ -302,16 +302,16 @@ impl UrlComponents { return Ok(true); } match key { - "host" => Err(ShellError::UnsupportedConfigValue( - "non-empty string".into(), - "empty string".into(), - value_span, - )), - "scheme" => Err(ShellError::UnsupportedConfigValue( - "non-empty string".into(), - "empty string".into(), - value_span, - )), + "host" => Err(ShellError::UnsupportedConfigValue { + expected: "non-empty string".into(), + value: "empty string".into(), + span: value_span, + }), + "scheme" => Err(ShellError::UnsupportedConfigValue { + expected: "non-empty string".into(), + value: "empty string".into(), + span: value_span, + }), _ => Ok(false), } } diff --git a/crates/nu-command/src/platform/du.rs b/crates/nu-command/src/platform/du.rs index 4d22fe5c1a..3519b4ba7c 100644 --- a/crates/nu-command/src/platform/du.rs +++ b/crates/nu-command/src/platform/du.rs @@ -82,12 +82,16 @@ impl Command for Du { let max_depth: Option> = call.get_flag(engine_state, stack, "max-depth")?; if let Some(ref max_depth) = max_depth { if max_depth.item < 0 { - return Err(ShellError::NeedsPositiveValue(max_depth.span)); + return Err(ShellError::NeedsPositiveValue { + span: max_depth.span, + }); } } if let Some(ref min_size) = min_size { if min_size.item < 0 { - return Err(ShellError::NeedsPositiveValue(min_size.span)); + return Err(ShellError::NeedsPositiveValue { + span: min_size.span, + }); } } let current_dir = current_dir(engine_state, stack)?; diff --git a/crates/nu-plugin/src/protocol/mod.rs b/crates/nu-plugin/src/protocol/mod.rs index f37c6c2d0e..c74fa17c0a 100644 --- a/crates/nu-plugin/src/protocol/mod.rs +++ b/crates/nu-plugin/src/protocol/mod.rs @@ -78,7 +78,7 @@ impl From for LabeledError { msg: format!("can't convert from {input} to {expected}"), span: Some(span), }, - ShellError::DidYouMean(suggestion, span) => LabeledError { + ShellError::DidYouMean { suggestion, span } => LabeledError { label: "Name not found".into(), msg: format!("did you mean '{suggestion}'?"), span: Some(span), diff --git a/crates/nu-protocol/src/config/helper.rs b/crates/nu-protocol/src/config/helper.rs index 51c11a21df..fee0d599e7 100644 --- a/crates/nu-protocol/src/config/helper.rs +++ b/crates/nu-protocol/src/config/helper.rs @@ -129,5 +129,8 @@ pub fn extract_value<'record>( ) -> Result<&'record Value, ShellError> { record .get(name) - .ok_or_else(|| ShellError::MissingConfigValue(name.to_string(), span)) + .ok_or_else(|| ShellError::MissingConfigValue { + missing_value: name.to_string(), + span, + }) } diff --git a/crates/nu-protocol/src/config/hooks.rs b/crates/nu-protocol/src/config/hooks.rs index 0a576d7cd6..3d28691ca5 100644 --- a/crates/nu-protocol/src/config/hooks.rs +++ b/crates/nu-protocol/src/config/hooks.rs @@ -46,23 +46,22 @@ pub(super) fn create_hooks(value: &Value) -> Result { "display_output" => hooks.display_output = Some(val.clone()), "command_not_found" => hooks.command_not_found = Some(val.clone()), x => { - return Err(ShellError::UnsupportedConfigValue( - "'pre_prompt', 'pre_execution', 'env_change', 'display_output', 'command_not_found'" - .to_string(), - x.to_string(), - span, - )); + return Err(ShellError::UnsupportedConfigValue { + expected: "'pre_prompt', 'pre_execution', 'env_change', 'display_output', 'command_not_found'".into(), + value: x.into(), + span + }); } } } Ok(hooks) } - _ => Err(ShellError::UnsupportedConfigValue( - "record for 'hooks' config".into(), - "non-record value".into(), + _ => Err(ShellError::UnsupportedConfigValue { + expected: "record for 'hooks' config".into(), + value: "non-record value".into(), span, - )), + }), } } diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index f640985060..05e0e1c2ab 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -912,7 +912,11 @@ pub enum ShellError { /// This can be for various reasons, such as your platform or permission flags. Refer to the specific error message for more details. #[error("Not possible to change the access time")] #[diagnostic(code(nu::shell::change_access_time_not_possible))] - ChangeAccessTimeNotPossible(String, #[label("{0}")] Span), + ChangeAccessTimeNotPossible { + msg: String, + #[label("{msg}")] + span: Span, + }, /// Changing the modification time ("mtime") of this file is not possible. /// @@ -921,7 +925,11 @@ pub enum ShellError { /// This can be for various reasons, such as your platform or permission flags. Refer to the specific error message for more details. #[error("Not possible to change the modified time")] #[diagnostic(code(nu::shell::change_modified_time_not_possible))] - ChangeModifiedTimeNotPossible(String, #[label("{0}")] Span), + ChangeModifiedTimeNotPossible { + msg: String, + #[label("{msg}")] + span: Span, + }, /// Unable to remove this item. /// @@ -930,7 +938,11 @@ pub enum ShellError { /// Removal can fail for a number of reasons, such as permissions problems. Refer to the specific error message for more details. #[error("Remove not possible")] #[diagnostic(code(nu::shell::remove_not_possible))] - RemoveNotPossible(String, #[label("{0}")] Span), + RemoveNotPossible { + msg: String, + #[label("{msg}")] + span: Span, + }, // These three are unused. Remove? #[error("No file to be removed")] @@ -947,7 +959,11 @@ pub enum ShellError { /// The error will show the result from a file operation #[error("Error trying to read file")] #[diagnostic(code(nu::shell::error_reading_file))] - ReadingFile(String, #[label("{0}")] Span), + ReadingFile { + msg: String, + #[label("{msg}")] + span: Span, + }, /// A name was not found. Did you mean a different name? /// @@ -956,16 +972,25 @@ pub enum ShellError { /// The error message will suggest a possible match for what you meant. #[error("Name not found")] #[diagnostic(code(nu::shell::name_not_found))] - DidYouMean(String, #[label("did you mean '{0}'?")] Span), + DidYouMean { + suggestion: String, + #[label("did you mean '{suggestion}'?")] + span: Span, + }, /// A name was not found. Did you mean a different name? /// /// ## Resolution /// /// The error message will suggest a possible match for what you meant. - #[error("{0}")] + #[error("{msg}")] #[diagnostic(code(nu::shell::did_you_mean_custom))] - DidYouMeanCustom(String, String, #[label("did you mean '{1}'?")] Span), + DidYouMeanCustom { + msg: String, + suggestion: String, + #[label("did you mean '{suggestion}'?")] + span: Span, + }, /// The given input must be valid UTF-8 for further processing. /// @@ -974,7 +999,10 @@ pub enum ShellError { /// Check your input's encoding. Are there any funny characters/bytes? #[error("Non-UTF8 string")] #[diagnostic(code(nu::parser::non_utf8))] - NonUtf8(#[label = "non-UTF8 string"] Span), + NonUtf8 { + #[label("non-UTF8 string")] + span: Span, + }, /// The given input must be valid UTF-8 for further processing. /// @@ -983,7 +1011,11 @@ pub enum ShellError { /// Check your input's encoding. Are there any funny characters/bytes? #[error("Non-UTF8 string")] #[diagnostic(code(nu::parser::non_utf8_custom))] - NonUtf8Custom(String, #[label = "{0}"] Span), + NonUtf8Custom { + msg: String, + #[label("{msg}")] + span: Span, + }, /// A custom value could not be converted to a Dataframe. /// @@ -992,7 +1024,11 @@ pub enum ShellError { /// Make sure conversion to a Dataframe is possible for this value or convert it to a type that does, first. #[error("Casting error")] #[diagnostic(code(nu::shell::downcast_not_possible))] - DowncastNotPossible(String, #[label("{0}")] Span), + DowncastNotPossible { + msg: String, + #[label("{msg}")] + span: Span, + }, /// The value given for this configuration is not supported. /// @@ -1001,7 +1037,12 @@ pub enum ShellError { /// Refer to the specific error message for details and convert values as needed. #[error("Unsupported config value")] #[diagnostic(code(nu::shell::unsupported_config_value))] - UnsupportedConfigValue(String, String, #[label = "expected {0}, got {1}"] Span), + UnsupportedConfigValue { + expected: String, + value: String, + #[label("expected {expected}, got {value}")] + span: Span, + }, /// An expected configuration value is not present. /// @@ -1010,7 +1051,11 @@ pub enum ShellError { /// Refer to the specific error message and add the configuration value to your config file as needed. #[error("Missing config value")] #[diagnostic(code(nu::shell::missing_config_value))] - MissingConfigValue(String, #[label = "missing {0}"] Span), + MissingConfigValue { + missing_value: String, + #[label("missing {missing_value}")] + span: Span, + }, /// Negative value passed when positive one is required. /// @@ -1019,7 +1064,10 @@ pub enum ShellError { /// Guard against negative values or check your inputs. #[error("Negative value passed when positive one is required")] #[diagnostic(code(nu::shell::needs_positive_value))] - NeedsPositiveValue(#[label = "use a positive value"] Span), + NeedsPositiveValue { + #[label("use a positive value")] + span: Span, + }, /// This is a generic error type used for different situations. #[error("{0}")] diff --git a/crates/nu-protocol/src/value/from_value.rs b/crates/nu-protocol/src/value/from_value.rs index 7e6dcba786..e09008ee44 100644 --- a/crates/nu-protocol/src/value/from_value.rs +++ b/crates/nu-protocol/src/value/from_value.rs @@ -91,7 +91,7 @@ impl FromValue for Spanned { match v { Value::Int { val, .. } => { if val.is_negative() { - Err(ShellError::NeedsPositiveValue(span)) + Err(ShellError::NeedsPositiveValue { span }) } else { Ok(Spanned { item: val as usize, @@ -101,7 +101,7 @@ impl FromValue for Spanned { } Value::Filesize { val, .. } => { if val.is_negative() { - Err(ShellError::NeedsPositiveValue(span)) + Err(ShellError::NeedsPositiveValue { span }) } else { Ok(Spanned { item: val as usize, @@ -111,7 +111,7 @@ impl FromValue for Spanned { } Value::Duration { val, .. } => { if val.is_negative() { - Err(ShellError::NeedsPositiveValue(span)) + Err(ShellError::NeedsPositiveValue { span }) } else { Ok(Spanned { item: val as usize, @@ -136,21 +136,21 @@ impl FromValue for usize { match v { Value::Int { val, .. } => { if val.is_negative() { - Err(ShellError::NeedsPositiveValue(span)) + Err(ShellError::NeedsPositiveValue { span }) } else { Ok(val as usize) } } Value::Filesize { val, .. } => { if val.is_negative() { - Err(ShellError::NeedsPositiveValue(span)) + Err(ShellError::NeedsPositiveValue { span }) } else { Ok(val as usize) } } Value::Duration { val, .. } => { if val.is_negative() { - Err(ShellError::NeedsPositiveValue(span)) + Err(ShellError::NeedsPositiveValue { span }) } else { Ok(val as usize) } @@ -300,7 +300,7 @@ impl FromValue for CellPath { }), Value::Int { val, .. } => { if val.is_negative() { - Err(ShellError::NeedsPositiveValue(span)) + Err(ShellError::NeedsPositiveValue { span }) } else { Ok(CellPath { members: vec![PathMember::Int { diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index fb9fc9b678..4a486fc4c1 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -1009,7 +1009,10 @@ impl Value { } else if let Some(suggestion) = did_you_mean(val.columns(), column_name) { - return Err(ShellError::DidYouMean(suggestion, *origin_span)); + return Err(ShellError::DidYouMean { + suggestion, + span: *origin_span, + }); } else { return Err(ShellError::CantFindColumn { col_name: column_name.clone(), @@ -1032,7 +1035,10 @@ impl Value { } else if *optional { return Ok(Value::nothing(*origin_span)); // short-circuit } else if let Some(suggestion) = did_you_mean(&columns, column_name) { - return Err(ShellError::DidYouMean(suggestion, *origin_span)); + return Err(ShellError::DidYouMean { + suggestion, + span: *origin_span, + }); } else { return Err(ShellError::CantFindColumn { col_name: column_name.clone(), @@ -1064,10 +1070,10 @@ impl Value { } else if let Some(suggestion) = did_you_mean(val.columns(), column_name) { - Err(ShellError::DidYouMean( + Err(ShellError::DidYouMean { suggestion, - *origin_span, - )) + span: *origin_span, + }) } else { Err(ShellError::CantFindColumn { col_name: column_name.clone(),