From efe25e3f58548dc4b776ded181cff558edcc2b07 Mon Sep 17 00:00:00 2001 From: Devyn Cairns Date: Thu, 21 Mar 2024 04:27:21 -0700 Subject: [PATCH] Better generic errors for plugins (and perhaps scripts) (#12236) # Description This makes `LabeledError` much more capable of representing close to everything a `miette::Diagnostic` can, including `ShellError`, and allows plugins to generate multiple error spans, codes, help, etc. `LabeledError` is now embeddable within `ShellError` as a transparent variant. This could also be used to improve `error make` and `try/catch` to reflect `LabeledError` exactly in the future. Also cleaned up some errors in existing plugins. # User-Facing Changes Breaking change for plugins. Nicer errors for users. --- .../src/core_commands/error_make.rs | 14 +- crates/nu-plugin/src/lib.rs | 6 +- crates/nu-plugin/src/plugin/command.rs | 8 +- .../nu-plugin/src/plugin/interface/engine.rs | 4 +- .../src/plugin/interface/engine/tests.rs | 12 +- crates/nu-plugin/src/plugin/mod.rs | 18 +- crates/nu-plugin/src/protocol/mod.rs | 71 +----- crates/nu-plugin/src/serializers/tests.rs | 24 +- .../nu-protocol/src/errors/labeled_error.rs | 241 ++++++++++++++++++ crates/nu-protocol/src/errors/mod.rs | 2 + crates/nu-protocol/src/errors/shell_error.rs | 11 + .../nu_plugin_custom_values/src/drop_check.rs | 5 +- .../nu_plugin_custom_values/src/generate.rs | 4 +- .../nu_plugin_custom_values/src/generate2.rs | 6 +- crates/nu_plugin_custom_values/src/main.rs | 6 +- crates/nu_plugin_custom_values/src/update.rs | 6 +- .../nu_plugin_custom_values/src/update_arg.rs | 4 +- .../src/commands/collect_external.rs | 6 +- .../nu_plugin_example/src/commands/config.rs | 14 +- .../src/commands/disable_gc.rs | 4 +- crates/nu_plugin_example/src/commands/env.rs | 11 +- .../src/commands/for_each.rs | 6 +- .../src/commands/generate.rs | 6 +- crates/nu_plugin_example/src/commands/main.rs | 11 +- crates/nu_plugin_example/src/commands/one.rs | 4 +- crates/nu_plugin_example/src/commands/seq.rs | 5 +- crates/nu_plugin_example/src/commands/sum.rs | 15 +- .../nu_plugin_example/src/commands/three.rs | 11 +- crates/nu_plugin_example/src/commands/two.rs | 4 +- crates/nu_plugin_example/src/example.rs | 4 +- crates/nu_plugin_formats/src/from/eml.rs | 3 +- crates/nu_plugin_formats/src/from/ics.rs | 4 +- crates/nu_plugin_formats/src/from/ini.rs | 4 +- crates/nu_plugin_formats/src/from/vcf.rs | 4 +- crates/nu_plugin_gstat/src/gstat.rs | 48 ++-- crates/nu_plugin_gstat/src/nu/mod.rs | 6 +- crates/nu_plugin_inc/src/inc.rs | 25 +- crates/nu_plugin_inc/src/nu/mod.rs | 6 +- crates/nu_plugin_query/src/query.rs | 4 +- crates/nu_plugin_query/src/query_json.rs | 27 +- crates/nu_plugin_query/src/query_web.rs | 37 +-- crates/nu_plugin_query/src/query_xml.rs | 49 ++-- 42 files changed, 453 insertions(+), 307 deletions(-) create mode 100644 crates/nu-protocol/src/errors/labeled_error.rs diff --git a/crates/nu-cmd-lang/src/core_commands/error_make.rs b/crates/nu-cmd-lang/src/core_commands/error_make.rs index bd68392c5c..cb1ab9e91f 100644 --- a/crates/nu-cmd-lang/src/core_commands/error_make.rs +++ b/crates/nu-cmd-lang/src/core_commands/error_make.rs @@ -2,7 +2,8 @@ use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{ - Category, Example, PipelineData, Record, ShellError, Signature, Span, SyntaxShape, Type, Value, + Category, Example, LabeledError, PipelineData, Record, ShellError, Signature, Span, + SyntaxShape, Type, Value, }; #[derive(Clone)] @@ -258,13 +259,10 @@ fn make_other_error(value: &Value, throw_span: Option) -> ShellError { } // correct return: everything present - ShellError::GenericError { - error: msg, - msg: text, - span: Some(Span::new(span_start as usize, span_end as usize)), - help, - inner: vec![], - } + let mut error = + LabeledError::new(msg).with_label(text, Span::new(span_start as usize, span_end as usize)); + error.help = help; + error.into() } fn get_span_sides(span: &Record, span_span: Span, side: &str) -> Result { diff --git a/crates/nu-plugin/src/lib.rs b/crates/nu-plugin/src/lib.rs index 6bd689d4d4..df139529f6 100644 --- a/crates/nu-plugin/src/lib.rs +++ b/crates/nu-plugin/src/lib.rs @@ -16,9 +16,9 @@ //! invoked by Nushell. //! //! ```rust,no_run -//! use nu_plugin::{EvaluatedCall, LabeledError, MsgPackSerializer, serve_plugin}; +//! use nu_plugin::{EvaluatedCall, MsgPackSerializer, serve_plugin}; //! use nu_plugin::{Plugin, PluginCommand, SimplePluginCommand, EngineInterface}; -//! use nu_protocol::{PluginSignature, Value}; +//! use nu_protocol::{PluginSignature, LabeledError, Value}; //! //! struct MyPlugin; //! struct MyCommand; @@ -64,7 +64,7 @@ mod util; pub use plugin::{ serve_plugin, EngineInterface, Plugin, PluginCommand, PluginEncoder, SimplePluginCommand, }; -pub use protocol::{EvaluatedCall, LabeledError}; +pub use protocol::EvaluatedCall; pub use serializers::{json::JsonSerializer, msgpack::MsgPackSerializer}; // Used by other nu crates. diff --git a/crates/nu-plugin/src/plugin/command.rs b/crates/nu-plugin/src/plugin/command.rs index 93e8ecdefe..06014877d6 100644 --- a/crates/nu-plugin/src/plugin/command.rs +++ b/crates/nu-plugin/src/plugin/command.rs @@ -1,6 +1,6 @@ -use nu_protocol::{PipelineData, PluginSignature, Value}; +use nu_protocol::{LabeledError, PipelineData, PluginSignature, Value}; -use crate::{EngineInterface, EvaluatedCall, LabeledError, Plugin}; +use crate::{EngineInterface, EvaluatedCall, Plugin}; /// The API for a Nushell plugin command /// @@ -18,7 +18,7 @@ use crate::{EngineInterface, EvaluatedCall, LabeledError, Plugin}; /// Basic usage: /// ``` /// # use nu_plugin::*; -/// # use nu_protocol::{PluginSignature, PipelineData, Type, Value}; +/// # use nu_protocol::{PluginSignature, PipelineData, Type, Value, LabeledError}; /// struct LowercasePlugin; /// struct Lowercase; /// @@ -108,7 +108,7 @@ pub trait PluginCommand: Sync { /// Basic usage: /// ``` /// # use nu_plugin::*; -/// # use nu_protocol::{PluginSignature, Type, Value}; +/// # use nu_protocol::{PluginSignature, Type, Value, LabeledError}; /// struct HelloPlugin; /// struct Hello; /// diff --git a/crates/nu-plugin/src/plugin/interface/engine.rs b/crates/nu-plugin/src/plugin/interface/engine.rs index 2cceecbda3..6a477b8dd8 100644 --- a/crates/nu-plugin/src/plugin/interface/engine.rs +++ b/crates/nu-plugin/src/plugin/interface/engine.rs @@ -6,7 +6,7 @@ use std::{ }; use nu_protocol::{ - engine::Closure, Config, IntoInterruptiblePipelineData, ListStream, PipelineData, + engine::Closure, Config, IntoInterruptiblePipelineData, LabeledError, ListStream, PipelineData, PluginSignature, ShellError, Spanned, Value, }; @@ -16,7 +16,7 @@ use crate::{ PluginCall, PluginCallId, PluginCallResponse, PluginCustomValue, PluginInput, PluginOption, ProtocolInfo, }, - LabeledError, PluginOutput, + PluginOutput, }; use super::{ diff --git a/crates/nu-plugin/src/plugin/interface/engine/tests.rs b/crates/nu-plugin/src/plugin/interface/engine/tests.rs index e3a03896aa..521a95dc58 100644 --- a/crates/nu-plugin/src/plugin/interface/engine/tests.rs +++ b/crates/nu-plugin/src/plugin/interface/engine/tests.rs @@ -4,8 +4,8 @@ use std::{ }; use nu_protocol::{ - engine::Closure, Config, CustomValue, IntoInterruptiblePipelineData, PipelineData, - PluginExample, PluginSignature, ShellError, Span, Spanned, Value, + engine::Closure, Config, CustomValue, IntoInterruptiblePipelineData, LabeledError, + PipelineData, PluginExample, PluginSignature, ShellError, Span, Spanned, Value, }; use crate::{ @@ -16,7 +16,7 @@ use crate::{ ListStreamInfo, PipelineDataHeader, PluginCall, PluginCustomValue, PluginInput, Protocol, ProtocolInfo, RawStreamInfo, StreamData, StreamMessage, }, - EvaluatedCall, LabeledError, PluginCallResponse, PluginOutput, + EvaluatedCall, PluginCallResponse, PluginOutput, }; use super::{EngineInterfaceManager, ReceivedPluginCall}; @@ -738,11 +738,7 @@ fn interface_write_response_with_stream() -> Result<(), ShellError> { fn interface_write_response_with_error() -> Result<(), ShellError> { let test = TestCase::new(); let interface = test.engine().interface_for_context(35); - let labeled_error = LabeledError { - label: "this is an error".into(), - msg: "a test error".into(), - span: None, - }; + let labeled_error = LabeledError::new("this is an error").with_help("a test error"); interface .write_response(Err(labeled_error.clone()))? .write()?; diff --git a/crates/nu-plugin/src/plugin/mod.rs b/crates/nu-plugin/src/plugin/mod.rs index 4fe01debf4..acb92a9016 100644 --- a/crates/nu-plugin/src/plugin/mod.rs +++ b/crates/nu-plugin/src/plugin/mod.rs @@ -1,4 +1,5 @@ use nu_engine::documentation::get_flags_section; +use nu_protocol::LabeledError; use std::cmp::Ordering; use std::collections::HashMap; @@ -13,9 +14,7 @@ use std::sync::mpsc::TrySendError; use std::sync::{mpsc, Arc, Mutex}; use crate::plugin::interface::{EngineInterfaceManager, ReceivedPluginCall}; -use crate::protocol::{ - CallInfo, CustomValueOp, LabeledError, PluginCustomValue, PluginInput, PluginOutput, -}; +use crate::protocol::{CallInfo, CustomValueOp, PluginCustomValue, PluginInput, PluginOutput}; use crate::EncodingType; #[cfg(unix)] @@ -230,7 +229,7 @@ where /// Basic usage: /// ``` /// # use nu_plugin::*; -/// # use nu_protocol::{PluginSignature, Type, Value}; +/// # use nu_protocol::{PluginSignature, LabeledError, Type, Value}; /// struct HelloPlugin; /// struct Hello; /// @@ -537,11 +536,12 @@ pub fn serve_plugin(plugin: &impl Plugin, encoder: impl PluginEncoder + 'static) let result = if let Some(command) = commands.get(&name) { command.run(plugin, &engine, &call, input) } else { - Err(LabeledError { - label: format!("Plugin command not found: `{name}`"), - msg: format!("plugin `{plugin_name}` doesn't have this command"), - span: Some(call.head), - }) + Err( + LabeledError::new(format!("Plugin command not found: `{name}`")).with_label( + format!("plugin `{plugin_name}` doesn't have this command"), + call.head, + ), + ) }; let write_result = engine .write_response(result) diff --git a/crates/nu-plugin/src/protocol/mod.rs b/crates/nu-plugin/src/protocol/mod.rs index 6a636f268a..9ae3fe80d9 100644 --- a/crates/nu-plugin/src/protocol/mod.rs +++ b/crates/nu-plugin/src/protocol/mod.rs @@ -12,8 +12,8 @@ use std::collections::HashMap; pub use evaluated_call::EvaluatedCall; use nu_protocol::{ - ast::Operator, engine::Closure, Config, PipelineData, PluginSignature, RawStream, ShellError, - Span, Spanned, Value, + ast::Operator, engine::Closure, Config, LabeledError, PipelineData, PluginSignature, RawStream, + ShellError, Span, Spanned, Value, }; pub use plugin_custom_value::PluginCustomValue; #[cfg(test)] @@ -289,73 +289,6 @@ pub enum StreamMessage { Ack(StreamId), } -/// An error message with debugging information that can be passed to Nushell from the plugin -/// -/// The `LabeledError` struct is a structured error message that can be returned from -/// a [Plugin](crate::Plugin)'s [`run`](crate::Plugin::run()) method. It contains -/// the error message along with optional [Span] data to support highlighting in the -/// shell. -#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] -pub struct LabeledError { - /// The name of the error - pub label: String, - /// A detailed error description - pub msg: String, - /// The [Span] in which the error occurred - pub span: Option, -} - -impl From for ShellError { - fn from(error: LabeledError) -> Self { - if error.span.is_some() { - ShellError::GenericError { - error: error.label, - msg: error.msg, - span: error.span, - help: None, - inner: vec![], - } - } else { - ShellError::GenericError { - error: error.label, - msg: "".into(), - span: None, - help: (!error.msg.is_empty()).then_some(error.msg), - inner: vec![], - } - } - } -} - -impl From for LabeledError { - fn from(error: ShellError) -> Self { - use miette::Diagnostic; - // This is not perfect - we can only take the first labeled span as that's all we have - // space for. - if let Some(labeled_span) = error.labels().and_then(|mut iter| iter.nth(0)) { - let offset = labeled_span.offset(); - let span = Span::new(offset, offset + labeled_span.len()); - LabeledError { - label: error.to_string(), - msg: labeled_span - .label() - .map(|label| label.to_owned()) - .unwrap_or_else(|| "".into()), - span: Some(span), - } - } else { - LabeledError { - label: error.to_string(), - msg: error - .help() - .map(|help| help.to_string()) - .unwrap_or_else(|| "".into()), - span: None, - } - } - } -} - /// Response to a [`PluginCall`]. The type parameter determines the output type for pipeline data. /// /// Note: exported for internal use, not public. diff --git a/crates/nu-plugin/src/serializers/tests.rs b/crates/nu-plugin/src/serializers/tests.rs index 1eb601128a..7d69c02025 100644 --- a/crates/nu-plugin/src/serializers/tests.rs +++ b/crates/nu-plugin/src/serializers/tests.rs @@ -1,11 +1,11 @@ macro_rules! generate_tests { ($encoder:expr) => { use crate::protocol::{ - CallInfo, CustomValueOp, EvaluatedCall, LabeledError, PipelineDataHeader, PluginCall, + CallInfo, CustomValueOp, EvaluatedCall, PipelineDataHeader, PluginCall, PluginCallResponse, PluginCustomValue, PluginInput, PluginOption, PluginOutput, StreamData, StreamMessage, }; - use nu_protocol::{PluginSignature, Span, Spanned, SyntaxShape, Value}; + use nu_protocol::{LabeledError, PluginSignature, Span, Spanned, SyntaxShape, Value}; #[test] fn decode_eof() { @@ -364,11 +364,15 @@ macro_rules! generate_tests { #[test] fn response_round_trip_error() { - let error = LabeledError { - label: "label".into(), - msg: "msg".into(), - span: Some(Span::new(2, 30)), - }; + let error = LabeledError::new("label") + .with_code("test::error") + .with_url("https://example.org/test/error") + .with_help("some help") + .with_label("msg", Span::new(2, 30)) + .with_inner(ShellError::IOError { + msg: "io error".into(), + }); + let response = PluginCallResponse::Error(error.clone()); let output = PluginOutput::CallResponse(6, response); @@ -392,11 +396,7 @@ macro_rules! generate_tests { #[test] fn response_round_trip_error_none() { - let error = LabeledError { - label: "label".into(), - msg: "msg".into(), - span: None, - }; + let error = LabeledError::new("error"); let response = PluginCallResponse::Error(error.clone()); let output = PluginOutput::CallResponse(7, response); diff --git a/crates/nu-protocol/src/errors/labeled_error.rs b/crates/nu-protocol/src/errors/labeled_error.rs new file mode 100644 index 0000000000..d6c09acb3f --- /dev/null +++ b/crates/nu-protocol/src/errors/labeled_error.rs @@ -0,0 +1,241 @@ +use std::fmt; + +use miette::Diagnostic; +use serde::{Deserialize, Serialize}; + +use crate::Span; + +use super::ShellError; + +/// A very generic type of error used for interfacing with external code, such as scripts and +/// plugins. +/// +/// This generally covers most of the interface of [`miette::Diagnostic`], but with types that are +/// well-defined for our protocol. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct LabeledError { + /// The main message for the error. + pub msg: String, + /// Labeled spans attached to the error, demonstrating to the user where the problem is. + #[serde(default)] + pub labels: Vec, + /// A unique machine- and search-friendly error code to associate to the error. (e.g. + /// `nu::shell::missing_config_value`) + #[serde(default)] + pub code: Option, + /// A link to documentation about the error, used in conjunction with `code` + #[serde(default)] + pub url: Option, + /// Additional help for the error, usually a hint about what the user might try + #[serde(default)] + pub help: Option, + /// Errors that are related to or caused this error + #[serde(default)] + pub inner: Vec, +} + +impl LabeledError { + /// Create a new plain [`LabeledError`] with the given message. + /// + /// This is usually used builder-style with methods like [`.with_label()`] to build an error. + /// + /// # Example + /// + /// ```rust + /// # use nu_protocol::LabeledError; + /// let error = LabeledError::new("Something bad happened"); + /// assert_eq!("Something bad happened", error.to_string()); + /// ``` + pub fn new(msg: impl Into) -> LabeledError { + LabeledError { + msg: msg.into(), + labels: vec![], + code: None, + url: None, + help: None, + inner: vec![], + } + } + + /// Add a labeled span to the error to demonstrate to the user where the problem is. + /// + /// # Example + /// + /// ```rust + /// # use nu_protocol::{LabeledError, Span}; + /// # let span = Span::test_data(); + /// let error = LabeledError::new("An error") + /// .with_label("happened here", span); + /// assert_eq!("happened here", &error.labels[0].text); + /// assert_eq!(span, error.labels[0].span); + /// ``` + pub fn with_label(mut self, text: impl Into, span: Span) -> Self { + self.labels.push(ErrorLabel { + text: text.into(), + span, + }); + self + } + + /// Add a unique machine- and search-friendly error code to associate to the error. (e.g. + /// `nu::shell::missing_config_value`) + /// + /// # Example + /// + /// ```rust + /// # use nu_protocol::LabeledError; + /// let error = LabeledError::new("An error") + /// .with_code("my_product::error"); + /// assert_eq!(Some("my_product::error"), error.code.as_deref()); + /// ``` + pub fn with_code(mut self, code: impl Into) -> Self { + self.code = Some(code.into()); + self + } + + /// Add a link to documentation about the error, used in conjunction with `code`. + /// + /// # Example + /// + /// ```rust + /// # use nu_protocol::LabeledError; + /// let error = LabeledError::new("An error") + /// .with_url("https://example.org/"); + /// assert_eq!(Some("https://example.org/"), error.url.as_deref()); + /// ``` + pub fn with_url(mut self, url: impl Into) -> Self { + self.url = Some(url.into()); + self + } + + /// Add additional help for the error, usually a hint about what the user might try. + /// + /// # Example + /// + /// ```rust + /// # use nu_protocol::LabeledError; + /// let error = LabeledError::new("An error") + /// .with_help("did you try turning it off and back on again?"); + /// assert_eq!(Some("did you try turning it off and back on again?"), error.help.as_deref()); + /// ``` + pub fn with_help(mut self, help: impl Into) -> Self { + self.help = Some(help.into()); + self + } + + /// Add an error that is related to or caused this error. + /// + /// # Example + /// + /// ```rust + /// # use nu_protocol::LabeledError; + /// let error = LabeledError::new("An error") + /// .with_inner(LabeledError::new("out of coolant")); + /// assert_eq!(LabeledError::new("out of coolant"), error.inner[0]); + /// ``` + pub fn with_inner(mut self, inner: impl Into) -> Self { + self.inner.push(inner.into()); + self + } + + /// Create a [`LabeledError`] from a type that implements [`miette::Diagnostic`]. + /// + /// # Example + /// + /// [`ShellError`] implements `miette::Diagnostic`: + /// + /// ```rust + /// # use nu_protocol::{ShellError, LabeledError}; + /// let error = LabeledError::from_diagnostic(&ShellError::IOError { msg: "error".into() }); + /// assert!(error.to_string().contains("I/O error")); + /// ``` + pub fn from_diagnostic(diag: &(impl miette::Diagnostic + ?Sized)) -> LabeledError { + LabeledError { + msg: diag.to_string(), + labels: diag + .labels() + .into_iter() + .flatten() + .map(|label| ErrorLabel { + text: label.label().unwrap_or("").into(), + span: Span::new(label.offset(), label.offset() + label.len()), + }) + .collect(), + code: diag.code().map(|s| s.to_string()), + url: diag.url().map(|s| s.to_string()), + help: diag.help().map(|s| s.to_string()), + inner: diag + .related() + .into_iter() + .flatten() + .map(Self::from_diagnostic) + .collect(), + } + } +} + +/// A labeled span within a [`LabeledError`]. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct ErrorLabel { + /// Text to show together with the span + pub text: String, + /// Span pointing at where the text references in the source + pub span: Span, +} + +impl fmt::Display for LabeledError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.msg) + } +} + +impl std::error::Error for LabeledError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.inner.get(0).map(|r| r as _) + } +} + +impl Diagnostic for LabeledError { + fn code<'a>(&'a self) -> Option> { + self.code.as_ref().map(Box::new).map(|b| b as _) + } + + fn severity(&self) -> Option { + None + } + + fn help<'a>(&'a self) -> Option> { + self.help.as_ref().map(Box::new).map(|b| b as _) + } + + fn url<'a>(&'a self) -> Option> { + self.url.as_ref().map(Box::new).map(|b| b as _) + } + + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + None + } + + fn labels(&self) -> Option + '_>> { + Some(Box::new(self.labels.iter().map(|label| { + miette::LabeledSpan::new_with_span( + Some(label.text.clone()).filter(|s| !s.is_empty()), + label.span, + ) + }))) + } + + fn related<'a>(&'a self) -> Option + 'a>> { + Some(Box::new(self.inner.iter().map(|r| r as _))) + } + + fn diagnostic_source(&self) -> Option<&dyn Diagnostic> { + None + } +} + +impl From for LabeledError { + fn from(err: ShellError) -> Self { + LabeledError::from_diagnostic(&err) + } +} diff --git a/crates/nu-protocol/src/errors/mod.rs b/crates/nu-protocol/src/errors/mod.rs index ad0e740d29..23006ab684 100644 --- a/crates/nu-protocol/src/errors/mod.rs +++ b/crates/nu-protocol/src/errors/mod.rs @@ -1,9 +1,11 @@ pub mod cli_error; +mod labeled_error; mod parse_error; mod parse_warning; mod shell_error; pub use cli_error::{format_error, report_error, report_error_new}; +pub use labeled_error::{ErrorLabel, LabeledError}; pub use parse_error::{DidYouMean, ParseError}; pub use parse_warning::ParseWarning; pub use shell_error::*; diff --git a/crates/nu-protocol/src/errors/shell_error.rs b/crates/nu-protocol/src/errors/shell_error.rs index cf365947ed..f7e9e16ca8 100644 --- a/crates/nu-protocol/src/errors/shell_error.rs +++ b/crates/nu-protocol/src/errors/shell_error.rs @@ -1097,6 +1097,11 @@ pub enum ShellError { span: Span, }, + /// This is a generic error type used for user and plugin-generated errors. + #[error(transparent)] + #[diagnostic(transparent)] + LabeledError(#[from] Box), + /// Attempted to use a command that has been removed from Nushell. /// /// ## Resolution @@ -1396,6 +1401,12 @@ impl From> for ShellError { } } +impl From for ShellError { + fn from(value: super::LabeledError) -> Self { + ShellError::LabeledError(Box::new(value)) + } +} + pub fn into_code(err: &ShellError) -> Option { err.code().map(|code| code.to_string()) } diff --git a/crates/nu_plugin_custom_values/src/drop_check.rs b/crates/nu_plugin_custom_values/src/drop_check.rs index cca511dc00..7bf005a233 100644 --- a/crates/nu_plugin_custom_values/src/drop_check.rs +++ b/crates/nu_plugin_custom_values/src/drop_check.rs @@ -1,6 +1,7 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; use nu_protocol::{ - record, Category, CustomValue, PluginSignature, ShellError, Span, SyntaxShape, Value, + record, Category, CustomValue, LabeledError, PluginSignature, ShellError, Span, SyntaxShape, + Value, }; use serde::{Deserialize, Serialize}; diff --git a/crates/nu_plugin_custom_values/src/generate.rs b/crates/nu_plugin_custom_values/src/generate.rs index 072af434a6..814551ec51 100644 --- a/crates/nu_plugin_custom_values/src/generate.rs +++ b/crates/nu_plugin_custom_values/src/generate.rs @@ -1,7 +1,7 @@ use crate::{cool_custom_value::CoolCustomValue, CustomValuePlugin}; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginExample, PluginSignature, Span, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginExample, PluginSignature, Span, Value}; pub struct Generate; diff --git a/crates/nu_plugin_custom_values/src/generate2.rs b/crates/nu_plugin_custom_values/src/generate2.rs index a29e91b4a8..951de152bc 100644 --- a/crates/nu_plugin_custom_values/src/generate2.rs +++ b/crates/nu_plugin_custom_values/src/generate2.rs @@ -1,7 +1,9 @@ use crate::{second_custom_value::SecondCustomValue, CustomValuePlugin}; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginExample, PluginSignature, Span, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{ + Category, LabeledError, PluginExample, PluginSignature, Span, SyntaxShape, Value, +}; pub struct Generate2; diff --git a/crates/nu_plugin_custom_values/src/main.rs b/crates/nu_plugin_custom_values/src/main.rs index c91ff709b2..d29bbc3dee 100644 --- a/crates/nu_plugin_custom_values/src/main.rs +++ b/crates/nu_plugin_custom_values/src/main.rs @@ -1,6 +1,4 @@ -use nu_plugin::{ - serve_plugin, EngineInterface, LabeledError, MsgPackSerializer, Plugin, PluginCommand, -}; +use nu_plugin::{serve_plugin, EngineInterface, MsgPackSerializer, Plugin, PluginCommand}; mod cool_custom_value; mod second_custom_value; @@ -14,7 +12,7 @@ mod update_arg; use drop_check::{DropCheck, DropCheckValue}; use generate::Generate; use generate2::Generate2; -use nu_protocol::CustomValue; +use nu_protocol::{CustomValue, LabeledError}; use update::Update; use update_arg::UpdateArg; diff --git a/crates/nu_plugin_custom_values/src/update.rs b/crates/nu_plugin_custom_values/src/update.rs index a6d2e5e4bf..7344a97d87 100644 --- a/crates/nu_plugin_custom_values/src/update.rs +++ b/crates/nu_plugin_custom_values/src/update.rs @@ -2,8 +2,10 @@ use crate::{ cool_custom_value::CoolCustomValue, second_custom_value::SecondCustomValue, CustomValuePlugin, }; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginExample, PluginSignature, ShellError, Span, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{ + Category, LabeledError, PluginExample, PluginSignature, ShellError, Span, Value, +}; pub struct Update; diff --git a/crates/nu_plugin_custom_values/src/update_arg.rs b/crates/nu_plugin_custom_values/src/update_arg.rs index f406e11ad8..a3f5930800 100644 --- a/crates/nu_plugin_custom_values/src/update_arg.rs +++ b/crates/nu_plugin_custom_values/src/update_arg.rs @@ -1,7 +1,7 @@ use crate::{update::Update, CustomValuePlugin}; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, SyntaxShape, Value}; pub struct UpdateArg; diff --git a/crates/nu_plugin_example/src/commands/collect_external.rs b/crates/nu_plugin_example/src/commands/collect_external.rs index 999f39bc42..b1fd7b4b1f 100644 --- a/crates/nu_plugin_example/src/commands/collect_external.rs +++ b/crates/nu_plugin_example/src/commands/collect_external.rs @@ -1,5 +1,7 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, PluginCommand}; -use nu_protocol::{Category, PipelineData, PluginExample, PluginSignature, RawStream, Type, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand}; +use nu_protocol::{ + Category, LabeledError, PipelineData, PluginExample, PluginSignature, RawStream, Type, Value, +}; use crate::Example; diff --git a/crates/nu_plugin_example/src/commands/config.rs b/crates/nu_plugin_example/src/commands/config.rs index 5e7ffd571f..7e63d82710 100644 --- a/crates/nu_plugin_example/src/commands/config.rs +++ b/crates/nu_plugin_example/src/commands/config.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, Type, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, Type, Value}; use crate::Example; @@ -27,12 +27,10 @@ impl SimplePluginCommand for Config { let config = engine.get_plugin_config()?; match config { Some(config) => Ok(config.clone()), - None => Err(LabeledError { - label: "No config sent".into(), - msg: "Configuration for this plugin was not found in `$env.config.plugins.example`" - .into(), - span: Some(call.head), - }), + None => Err(LabeledError::new("No config sent").with_label( + "configuration for this plugin was not found in `$env.config.plugins.example`", + call.head, + )), } } } diff --git a/crates/nu_plugin_example/src/commands/disable_gc.rs b/crates/nu_plugin_example/src/commands/disable_gc.rs index 98ca12387e..55ab256955 100644 --- a/crates/nu_plugin_example/src/commands/disable_gc.rs +++ b/crates/nu_plugin_example/src/commands/disable_gc.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, Value}; use crate::Example; diff --git a/crates/nu_plugin_example/src/commands/env.rs b/crates/nu_plugin_example/src/commands/env.rs index 85d5276da4..c84934698b 100644 --- a/crates/nu_plugin_example/src/commands/env.rs +++ b/crates/nu_plugin_example/src/commands/env.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, SyntaxShape, Type, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, SyntaxShape, Type, Value}; use crate::Example; @@ -42,11 +42,8 @@ impl SimplePluginCommand for Env { // Get working directory Ok(Value::string(engine.get_current_dir()?, call.head)) } - Some(value) => Err(LabeledError { - label: "Invalid arguments".into(), - msg: "--cwd can't be used with --set".into(), - span: Some(value.span()), - }), + Some(value) => Err(LabeledError::new("Invalid arguments") + .with_label("--cwd can't be used with --set", value.span())), } } else if let Some(value) = call.get_flag_value("set") { // Set single env var diff --git a/crates/nu_plugin_example/src/commands/for_each.rs b/crates/nu_plugin_example/src/commands/for_each.rs index 9b9feeadee..6e289613b9 100644 --- a/crates/nu_plugin_example/src/commands/for_each.rs +++ b/crates/nu_plugin_example/src/commands/for_each.rs @@ -1,5 +1,7 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, PluginCommand}; -use nu_protocol::{Category, PipelineData, PluginExample, PluginSignature, SyntaxShape, Type}; +use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand}; +use nu_protocol::{ + Category, LabeledError, PipelineData, PluginExample, PluginSignature, SyntaxShape, Type, +}; use crate::Example; diff --git a/crates/nu_plugin_example/src/commands/generate.rs b/crates/nu_plugin_example/src/commands/generate.rs index f40fb7ae9e..5b7495dda2 100644 --- a/crates/nu_plugin_example/src/commands/generate.rs +++ b/crates/nu_plugin_example/src/commands/generate.rs @@ -1,7 +1,7 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, PluginCommand}; +use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand}; use nu_protocol::{ - Category, IntoInterruptiblePipelineData, PipelineData, PluginExample, PluginSignature, - SyntaxShape, Type, Value, + Category, IntoInterruptiblePipelineData, LabeledError, PipelineData, PluginExample, + PluginSignature, SyntaxShape, Type, Value, }; use crate::Example; diff --git a/crates/nu_plugin_example/src/commands/main.rs b/crates/nu_plugin_example/src/commands/main.rs index dcce189891..319eecce92 100644 --- a/crates/nu_plugin_example/src/commands/main.rs +++ b/crates/nu_plugin_example/src/commands/main.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, Value}; use crate::Example; @@ -32,10 +32,7 @@ particularly useful. call: &EvaluatedCall, _input: &Value, ) -> Result { - Err(LabeledError { - label: "No subcommand provided".into(), - msg: "add --help to see a list of subcommands".into(), - span: Some(call.head), - }) + Err(LabeledError::new("No subcommand provided") + .with_label("add --help to see a list of subcommands", call.head)) } } diff --git a/crates/nu_plugin_example/src/commands/one.rs b/crates/nu_plugin_example/src/commands/one.rs index bb6900c65a..27a35914db 100644 --- a/crates/nu_plugin_example/src/commands/one.rs +++ b/crates/nu_plugin_example/src/commands/one.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginExample, PluginSignature, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginExample, PluginSignature, SyntaxShape, Value}; use crate::Example; diff --git a/crates/nu_plugin_example/src/commands/seq.rs b/crates/nu_plugin_example/src/commands/seq.rs index f7dc7160f2..1b90ef7ba0 100644 --- a/crates/nu_plugin_example/src/commands/seq.rs +++ b/crates/nu_plugin_example/src/commands/seq.rs @@ -1,6 +1,7 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, PluginCommand}; +use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand}; use nu_protocol::{ - Category, ListStream, PipelineData, PluginExample, PluginSignature, SyntaxShape, Type, Value, + Category, LabeledError, ListStream, PipelineData, PluginExample, PluginSignature, SyntaxShape, + Type, Value, }; use crate::Example; diff --git a/crates/nu_plugin_example/src/commands/sum.rs b/crates/nu_plugin_example/src/commands/sum.rs index 4652c76ed7..dafce1edfc 100644 --- a/crates/nu_plugin_example/src/commands/sum.rs +++ b/crates/nu_plugin_example/src/commands/sum.rs @@ -1,5 +1,7 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, PluginCommand}; -use nu_protocol::{Category, PipelineData, PluginExample, PluginSignature, Span, Type, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand}; +use nu_protocol::{ + Category, LabeledError, PipelineData, PluginExample, PluginSignature, Span, Type, Value, +}; use crate::Example; @@ -33,18 +35,15 @@ impl PluginCommand for Sum { input: PipelineData, ) -> Result { let mut acc = IntOrFloat::Int(0); - let span = input.span(); for value in input { if let Ok(n) = value.as_i64() { acc.add_i64(n); } else if let Ok(n) = value.as_f64() { acc.add_f64(n); } else { - return Err(LabeledError { - label: "Stream only accepts ints and floats".into(), - msg: format!("found {}", value.get_type()), - span, - }); + return Err(LabeledError::new("Sum only accepts ints and floats") + .with_label(format!("found {} in input", value.get_type()), value.span()) + .with_label("can't be used here", call.head)); } } Ok(PipelineData::Value(acc.to_value(call.head), None)) diff --git a/crates/nu_plugin_example/src/commands/three.rs b/crates/nu_plugin_example/src/commands/three.rs index 69e702f7f1..5c0c5192e1 100644 --- a/crates/nu_plugin_example/src/commands/three.rs +++ b/crates/nu_plugin_example/src/commands/three.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, SyntaxShape, Value}; use crate::Example; @@ -31,10 +31,7 @@ impl SimplePluginCommand for Three { ) -> Result { plugin.print_values(3, call, input)?; - Err(LabeledError { - label: "ERROR from plugin".into(), - msg: "error message pointing to call head span".into(), - span: Some(call.head), - }) + Err(LabeledError::new("ERROR from plugin") + .with_label("error message pointing to call head span", call.head)) } } diff --git a/crates/nu_plugin_example/src/commands/two.rs b/crates/nu_plugin_example/src/commands/two.rs index 6c315338ad..5b60f62fc6 100644 --- a/crates/nu_plugin_example/src/commands/two.rs +++ b/crates/nu_plugin_example/src/commands/two.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{record, Category, PluginSignature, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{record, Category, LabeledError, PluginSignature, SyntaxShape, Value}; use crate::Example; diff --git a/crates/nu_plugin_example/src/example.rs b/crates/nu_plugin_example/src/example.rs index b9e053946d..19d23cc5da 100644 --- a/crates/nu_plugin_example/src/example.rs +++ b/crates/nu_plugin_example/src/example.rs @@ -1,5 +1,5 @@ -use nu_plugin::{EvaluatedCall, LabeledError}; -use nu_protocol::Value; +use nu_plugin::EvaluatedCall; +use nu_protocol::{LabeledError, Value}; pub struct Example; diff --git a/crates/nu_plugin_formats/src/from/eml.rs b/crates/nu_plugin_formats/src/from/eml.rs index ed92bf105f..427be71ecc 100644 --- a/crates/nu_plugin_formats/src/from/eml.rs +++ b/crates/nu_plugin_formats/src/from/eml.rs @@ -1,7 +1,8 @@ use eml_parser::eml::*; use eml_parser::EmlParser; use indexmap::map::IndexMap; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::LabeledError; use nu_protocol::{ record, Category, PluginExample, PluginSignature, ShellError, Span, SyntaxShape, Type, Value, }; diff --git a/crates/nu_plugin_formats/src/from/ics.rs b/crates/nu_plugin_formats/src/from/ics.rs index df20c33d28..d0b77daaf3 100644 --- a/crates/nu_plugin_formats/src/from/ics.rs +++ b/crates/nu_plugin_formats/src/from/ics.rs @@ -1,9 +1,9 @@ use ical::parser::ical::component::*; use ical::property::Property; use indexmap::map::IndexMap; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; use nu_protocol::{ - record, Category, PluginExample, PluginSignature, ShellError, Span, Type, Value, + record, Category, LabeledError, PluginExample, PluginSignature, ShellError, Span, Type, Value, }; use std::io::BufReader; diff --git a/crates/nu_plugin_formats/src/from/ini.rs b/crates/nu_plugin_formats/src/from/ini.rs index 18a7d511aa..1f7957bb9a 100644 --- a/crates/nu_plugin_formats/src/from/ini.rs +++ b/crates/nu_plugin_formats/src/from/ini.rs @@ -1,6 +1,6 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; use nu_protocol::{ - record, Category, PluginExample, PluginSignature, Record, ShellError, Type, Value, + record, Category, LabeledError, PluginExample, PluginSignature, Record, ShellError, Type, Value, }; use crate::FromCmds; diff --git a/crates/nu_plugin_formats/src/from/vcf.rs b/crates/nu_plugin_formats/src/from/vcf.rs index e3f3008234..41851878fc 100644 --- a/crates/nu_plugin_formats/src/from/vcf.rs +++ b/crates/nu_plugin_formats/src/from/vcf.rs @@ -1,9 +1,9 @@ use ical::parser::vcard::component::*; use ical::property::Property; use indexmap::map::IndexMap; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; use nu_protocol::{ - record, Category, PluginExample, PluginSignature, ShellError, Span, Type, Value, + record, Category, LabeledError, PluginExample, PluginSignature, ShellError, Span, Type, Value, }; use crate::FromCmds; diff --git a/crates/nu_plugin_gstat/src/gstat.rs b/crates/nu_plugin_gstat/src/gstat.rs index fb7009bdad..6248de673d 100644 --- a/crates/nu_plugin_gstat/src/gstat.rs +++ b/crates/nu_plugin_gstat/src/gstat.rs @@ -1,6 +1,5 @@ use git2::{Branch, BranchType, DescribeOptions, Repository}; -use nu_plugin::LabeledError; -use nu_protocol::{record, IntoSpanned, Span, Spanned, Value}; +use nu_protocol::{record, IntoSpanned, LabeledError, Span, Spanned, Value}; use std::fmt::Write; use std::ops::BitAnd; use std::path::Path; @@ -51,39 +50,38 @@ impl GStat { // This path has to exist if !absolute_path.exists() { - return Err(LabeledError { - label: "error with path".to_string(), - msg: format!("path does not exist [{}]", absolute_path.display()), - span: Some(path.span), - }); + return Err(LabeledError::new("error with path").with_label( + format!("path does not exist [{}]", absolute_path.display()), + path.span, + )); } - let metadata = std::fs::metadata(&absolute_path).map_err(|e| LabeledError { - label: "error with metadata".to_string(), - msg: format!( - "unable to get metadata for [{}], error: {}", - absolute_path.display(), - e - ), - span: Some(path.span), + let metadata = std::fs::metadata(&absolute_path).map_err(|e| { + LabeledError::new("error with metadata").with_label( + format!( + "unable to get metadata for [{}], error: {}", + absolute_path.display(), + e + ), + path.span, + ) })?; // This path has to be a directory if !metadata.is_dir() { - return Err(LabeledError { - label: "error with directory".to_string(), - msg: format!("path is not a directory [{}]", absolute_path.display()), - span: Some(path.span), - }); + return Err(LabeledError::new("error with directory").with_label( + format!("path is not a directory [{}]", absolute_path.display()), + path.span, + )); } let repo_path = match absolute_path.canonicalize() { Ok(p) => p, Err(e) => { - return Err(LabeledError { - label: format!("error canonicalizing [{}]", absolute_path.display()), - msg: e.to_string(), - span: Some(path.span), - }); + return Err(LabeledError::new(format!( + "error canonicalizing [{}]", + absolute_path.display() + )) + .with_label(e.to_string(), path.span)); } }; diff --git a/crates/nu_plugin_gstat/src/nu/mod.rs b/crates/nu_plugin_gstat/src/nu/mod.rs index 9092c99af1..c170e61870 100644 --- a/crates/nu_plugin_gstat/src/nu/mod.rs +++ b/crates/nu_plugin_gstat/src/nu/mod.rs @@ -1,8 +1,6 @@ use crate::GStat; -use nu_plugin::{ - EngineInterface, EvaluatedCall, LabeledError, Plugin, PluginCommand, SimplePluginCommand, -}; -use nu_protocol::{Category, PluginSignature, Spanned, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, Spanned, SyntaxShape, Value}; pub struct GStatPlugin; diff --git a/crates/nu_plugin_inc/src/inc.rs b/crates/nu_plugin_inc/src/inc.rs index 1aa9e59481..6510cbd6a6 100644 --- a/crates/nu_plugin_inc/src/inc.rs +++ b/crates/nu_plugin_inc/src/inc.rs @@ -1,5 +1,4 @@ -use nu_plugin::LabeledError; -use nu_protocol::{ast::CellPath, Span, Value}; +use nu_protocol::{ast::CellPath, LabeledError, Span, Value}; use semver::{BuildMetadata, Prerelease, Version}; #[derive(Debug, Eq, PartialEq, Clone, Copy)] @@ -102,12 +101,7 @@ impl Inc { let cell_value = self.inc_value(head, &cell_value)?; let mut value = value.clone(); - value - .update_data_at_cell_path(&cell_path.members, cell_value) - .map_err(|x| { - let error: LabeledError = x.into(); - error - })?; + value.update_data_at_cell_path(&cell_path.members, cell_value)?; Ok(value) } else { self.inc_value(head, value) @@ -119,17 +113,14 @@ impl Inc { Value::Int { val, .. } => Ok(Value::int(val + 1, head)), Value::String { val, .. } => Ok(self.apply(val, head)), x => { - let msg = x.coerce_string().map_err(|e| LabeledError { - label: "Unable to extract string".into(), - msg: format!("value cannot be converted to string {x:?} - {e}"), - span: Some(head), + let msg = x.coerce_string().map_err(|e| { + LabeledError::new("Unable to extract string").with_label( + format!("value cannot be converted to string {x:?} - {e}"), + head, + ) })?; - Err(LabeledError { - label: "Incorrect value".into(), - msg, - span: Some(head), - }) + Err(LabeledError::new("Incorrect value").with_label(msg, head)) } } } diff --git a/crates/nu_plugin_inc/src/nu/mod.rs b/crates/nu_plugin_inc/src/nu/mod.rs index ea75b7246b..4d2de993b2 100644 --- a/crates/nu_plugin_inc/src/nu/mod.rs +++ b/crates/nu_plugin_inc/src/nu/mod.rs @@ -1,9 +1,7 @@ use crate::inc::SemVerAction; use crate::Inc; -use nu_plugin::{ - EngineInterface, EvaluatedCall, LabeledError, Plugin, PluginCommand, SimplePluginCommand, -}; -use nu_protocol::{ast::CellPath, PluginSignature, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand}; +use nu_protocol::{ast::CellPath, LabeledError, PluginSignature, SyntaxShape, Value}; pub struct IncPlugin; diff --git a/crates/nu_plugin_query/src/query.rs b/crates/nu_plugin_query/src/query.rs index bc38a26d14..8d58662b26 100644 --- a/crates/nu_plugin_query/src/query.rs +++ b/crates/nu_plugin_query/src/query.rs @@ -3,8 +3,8 @@ use crate::query_web::QueryWeb; use crate::query_xml::QueryXml; use nu_engine::documentation::get_flags_section; -use nu_plugin::{EvaluatedCall, LabeledError, Plugin, PluginCommand, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, Value}; +use nu_plugin::{EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand}; +use nu_protocol::{Category, LabeledError, PluginSignature, Value}; use std::fmt::Write; #[derive(Default)] diff --git a/crates/nu_plugin_query/src/query_json.rs b/crates/nu_plugin_query/src/query_json.rs index b4960f7875..bbef6ebfdb 100644 --- a/crates/nu_plugin_query/src/query_json.rs +++ b/crates/nu_plugin_query/src/query_json.rs @@ -1,6 +1,8 @@ use gjson::Value as gjValue; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginSignature, Record, Span, Spanned, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{ + Category, LabeledError, PluginSignature, Record, Span, Spanned, SyntaxShape, Value, +}; use crate::Query; @@ -39,22 +41,15 @@ pub fn execute_json_query( let input_string = match input.coerce_str() { Ok(s) => s, Err(e) => { - return Err(LabeledError { - span: Some(call.head), - msg: e.to_string(), - label: "problem with input data".to_string(), - }) + return Err(LabeledError::new("Problem with input data").with_inner(e)); } }; let query_string = match &query { Some(v) => &v.item, None => { - return Err(LabeledError { - msg: "problem with input data".to_string(), - label: "problem with input data".to_string(), - span: Some(call.head), - }) + return Err(LabeledError::new("Problem with input data") + .with_label("query string missing", call.head)); } }; @@ -62,11 +57,9 @@ pub fn execute_json_query( let is_valid_json = gjson::valid(&input_string); if !is_valid_json { - return Err(LabeledError { - msg: "invalid json".to_string(), - label: "invalid json".to_string(), - span: Some(call.head), - }); + return Err( + LabeledError::new("Invalid JSON").with_label("this is not valid JSON", call.head) + ); } let val: gjValue = gjson::get(&input_string, query_string); diff --git a/crates/nu_plugin_query/src/query_web.rs b/crates/nu_plugin_query/src/query_web.rs index ce6d5247e2..b4e59b681b 100644 --- a/crates/nu_plugin_query/src/query_web.rs +++ b/crates/nu_plugin_query/src/query_web.rs @@ -1,6 +1,9 @@ use crate::{web_tables::WebTable, Query}; -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{Category, PluginExample, PluginSignature, Record, Span, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{ + Category, LabeledError, PluginExample, PluginSignature, Record, Span, Spanned, SyntaxShape, + Value, +}; use scraper::{Html, Selector as ScraperSelector}; pub struct QueryWeb; @@ -99,10 +102,7 @@ impl Default for Selector { pub fn parse_selector_params(call: &EvaluatedCall, input: &Value) -> Result { let head = call.head; - let query: String = match call.get_flag("query")? { - Some(q2) => q2, - None => "".to_string(), - }; + let query: Option> = call.get_flag("query")?; let as_html = call.has_flag("as-html")?; let attribute = call.get_flag("attribute")?.unwrap_or_default(); let as_table: Value = call @@ -111,16 +111,20 @@ pub fn parse_selector_params(call: &EvaluatedCall, input: &Value) -> Result Result Ok(begin_selector_query(val.to_string(), selector, span)), - _ => Err(LabeledError { - label: "requires text input".to_string(), - msg: "Expected text from pipeline".to_string(), - span: Some(span), - }), + _ => Err(LabeledError::new("Requires text input") + .with_label("expected text from pipeline", span)), } } diff --git a/crates/nu_plugin_query/src/query_xml.rs b/crates/nu_plugin_query/src/query_xml.rs index fe65d47fda..387e0bdd63 100644 --- a/crates/nu_plugin_query/src/query_xml.rs +++ b/crates/nu_plugin_query/src/query_xml.rs @@ -1,5 +1,7 @@ -use nu_plugin::{EngineInterface, EvaluatedCall, LabeledError, SimplePluginCommand}; -use nu_protocol::{record, Category, PluginSignature, Record, Span, Spanned, SyntaxShape, Value}; +use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; +use nu_protocol::{ + record, Category, LabeledError, PluginSignature, Record, Span, Spanned, SyntaxShape, Value, +}; use sxd_document::parser; use sxd_xpath::{Context, Factory}; @@ -38,11 +40,9 @@ pub fn execute_xpath_query( let (query_string, span) = match &query { Some(v) => (&v.item, v.span), None => { - return Err(LabeledError { - msg: "problem with input data".to_string(), - label: "problem with input data".to_string(), - span: Some(call.head), - }) + return Err( + LabeledError::new("problem with input data").with_label("query missing", call.head) + ) } }; @@ -50,12 +50,10 @@ pub fn execute_xpath_query( let input_string = input.coerce_str()?; let package = parser::parse(&input_string); - if package.is_err() { - return Err(LabeledError { - label: "invalid xml document".to_string(), - msg: "invalid xml document".to_string(), - span: Some(call.head), - }); + if let Err(err) = package { + return Err( + LabeledError::new("Invalid XML document").with_label(err.to_string(), input.span()) + ); } let package = package.expect("invalid xml document"); @@ -107,29 +105,20 @@ pub fn execute_xpath_query( Ok(Value::list(records, call.head)) } - Err(_) => Err(LabeledError { - label: "xpath query error".to_string(), - msg: "xpath query error".to_string(), - span: Some(call.head), - }), + Err(err) => { + Err(LabeledError::new("xpath query error").with_label(err.to_string(), call.head)) + } } } fn build_xpath(xpath_str: &str, span: Span) -> Result { let factory = Factory::new(); - if let Ok(xpath) = factory.build(xpath_str) { - xpath.ok_or_else(|| LabeledError { - label: "invalid xpath query".to_string(), - msg: "invalid xpath query".to_string(), - span: Some(span), - }) - } else { - Err(LabeledError { - label: "expected valid xpath query".to_string(), - msg: "expected valid xpath query".to_string(), - span: Some(span), - }) + match factory.build(xpath_str) { + Ok(xpath) => xpath.ok_or_else(|| { + LabeledError::new("invalid xpath query").with_label("the query must not be empty", span) + }), + Err(err) => Err(LabeledError::new("invalid xpath query").with_label(err.to_string(), span)), } }