Document and critically review ShellError variants - Ep. 3 (#8340)

Continuation of #8229 and #8326

# 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.

# Call to action

**Everyone:** Feel free to add review comments if you spot inconsistent
use of `ShellError` variants.

# User-Facing Changes

(None now, end goal more explicit and consistent error messages)

# Tests + Formatting

(No additional tests needed so far)

# Commits (so far)

- Remove `ShellError::FeatureNotEnabled`
- Name fields on `SE::ExternalNotSupported`
- Name field on `SE::InvalidProbability`
- Name fields on `SE::NushellFailed` variants
- Remove unused `SE::NushellFailedSpannedHelp`
- Name field on `SE::VariableNotFoundAtRuntime`
- Name fields on `SE::EnvVarNotFoundAtRuntime`
- Name fields on `SE::ModuleNotFoundAtRuntime`
- Remove usused `ModuleOrOverlayNotFoundAtRuntime`
- Name fields on `SE::OverlayNotFoundAtRuntime`
- Name field on `SE::NotFound`
This commit is contained in:
Stefan Holderbach 2023-03-06 18:33:09 +01:00 committed by GitHub
parent 4898750fc1
commit 62575c9a4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 1193 additions and 1048 deletions

View File

@ -60,11 +60,11 @@ impl Command for Const {
Ok(PipelineData::empty()) Ok(PipelineData::empty())
} else { } else {
Err(ShellError::NushellFailedSpanned( Err(ShellError::NushellFailedSpanned {
"Missing Constant".to_string(), msg: "Missing Constant".to_string(),
"constant not added by the parser".to_string(), label: "constant not added by the parser".to_string(),
call.head, span: call.head,
)) })
} }
} }

View File

@ -161,11 +161,12 @@ impl Command for Do {
let stdout = if let Some(handle) = stdout_handler { let stdout = if let Some(handle) = stdout_handler {
match handle.join() { match handle.join() {
Err(err) => { Err(err) => {
return Err(ShellError::ExternalCommand( return Err(ShellError::ExternalCommand {
"Fail to receive external commands stdout message".to_string(), label: "Fail to receive external commands stdout message"
format!("{err:?}"), .to_string(),
help: format!("{err:?}"),
span, span,
)); });
} }
Ok(res) => Some(res), Ok(res) => Some(res),
} }
@ -183,11 +184,11 @@ impl Command for Do {
}; };
if let Some(Value::Int { val: code, .. }) = exit_code.last() { if let Some(Value::Int { val: code, .. }) = exit_code.last() {
if *code != 0 { if *code != 0 {
return Err(ShellError::ExternalCommand( return Err(ShellError::ExternalCommand {
"External command failed".to_string(), label: "External command failed".to_string(),
stderr_msg, help: stderr_msg,
span, span,
)); });
} }
} }

View File

@ -100,9 +100,15 @@ You can also learn more at https://www.nushell.sh/book/"#;
result result
}; };
if let Err(ShellError::ModuleNotFoundAtRuntime(_, _)) = result { if let Err(ShellError::ModuleNotFoundAtRuntime {
mod_name: _,
span: _,
}) = result
{
let rest_spans: Vec<Span> = rest.iter().map(|arg| arg.span).collect(); let rest_spans: Vec<Span> = rest.iter().map(|arg| arg.span).collect();
Err(ShellError::NotFound(span(&rest_spans))) Err(ShellError::NotFound {
span: span(&rest_spans),
})
} else { } else {
result result
} }
@ -144,11 +150,11 @@ pub fn highlight_search_in_table(
let (cols, mut vals, record_span) = if let Value::Record { cols, vals, span } = record { let (cols, mut vals, record_span) = if let Value::Record { cols, vals, span } = record {
(cols, vals, span) (cols, vals, span)
} else { } else {
return Err(ShellError::NushellFailedSpanned( return Err(ShellError::NushellFailedSpanned {
"Expected record".to_string(), msg: "Expected record".to_string(),
format!("got {}", record.get_type()), label: format!("got {}", record.get_type()),
record.span()?, span: record.span()?,
)); });
}; };
let has_match = cols.iter().zip(vals.iter_mut()).fold( let has_match = cols.iter().zip(vals.iter_mut()).fold(

View File

@ -120,10 +120,10 @@ pub fn help_modules(
let module_id = if let Some(id) = engine_state.find_module(name.as_bytes(), &[]) { let module_id = if let Some(id) = engine_state.find_module(name.as_bytes(), &[]) {
id id
} else { } else {
return Err(ShellError::ModuleNotFoundAtRuntime( return Err(ShellError::ModuleNotFoundAtRuntime {
name, mod_name: name,
span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()), span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
)); });
}; };
let module = engine_state.get_module(module_id); let module = engine_state.get_module(module_id);

View File

@ -58,7 +58,10 @@ impl Command for HideEnv {
name.span, name.span,
)); ));
} else { } else {
return Err(ShellError::EnvVarNotFoundAtRuntime(name.item, name.span)); return Err(ShellError::EnvVarNotFoundAtRuntime {
envvar_name: name.item,
span: name.span,
});
} }
} }
} }

View File

@ -111,12 +111,12 @@ impl Command for If {
Ok(PipelineData::empty()) Ok(PipelineData::empty())
} }
} }
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"bool".into(), to_type: "bool".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
result.span()?, span: result.span()?,
None, help: None,
)), }),
} }
} }

View File

@ -61,10 +61,10 @@ impl Command for OverlayHide {
}; };
if !stack.is_overlay_active(&overlay_name.item) { if !stack.is_overlay_active(&overlay_name.item) {
return Err(ShellError::OverlayNotFoundAtRuntime( return Err(ShellError::OverlayNotFoundAtRuntime {
overlay_name.item, overlay_name: overlay_name.item,
overlay_name.span, span: overlay_name.span,
)); });
} }
let keep_env: Option<Vec<Spanned<String>>> = let keep_env: Option<Vec<Spanned<String>>> =
@ -76,7 +76,12 @@ impl Command for OverlayHide {
for name in env_var_names_to_keep.into_iter() { for name in env_var_names_to_keep.into_iter() {
match stack.get_env_var(engine_state, &name.item) { match stack.get_env_var(engine_state, &name.item) {
Some(val) => env_vars_to_keep.push((name.item, val.clone())), Some(val) => env_vars_to_keep.push((name.item, val.clone())),
None => return Err(ShellError::EnvVarNotFoundAtRuntime(name.item, name.span)), None => {
return Err(ShellError::EnvVarNotFoundAtRuntime {
envvar_name: name.item,
span: name.span,
})
}
} }
} }

View File

@ -70,18 +70,18 @@ impl Command for OverlayUse {
if let Expr::Overlay(module_id) = overlay_expr.expr { if let Expr::Overlay(module_id) = overlay_expr.expr {
module_id module_id
} else { } else {
return Err(ShellError::NushellFailedSpanned( return Err(ShellError::NushellFailedSpanned {
"Not an overlay".to_string(), msg: "Not an overlay".to_string(),
"requires an overlay (path or a string)".to_string(), label: "requires an overlay (path or a string)".to_string(),
overlay_expr.span, span: overlay_expr.span,
)); });
} }
} else { } else {
return Err(ShellError::NushellFailedSpanned( return Err(ShellError::NushellFailedSpanned {
"Missing positional".to_string(), msg: "Missing positional".to_string(),
"missing required overlay".to_string(), label: "missing required overlay".to_string(),
call.head, span: call.head,
)); });
}; };
let overlay_name = if let Some(name) = call.opt(engine_state, caller_stack, 1)? { let overlay_name = if let Some(name) = call.opt(engine_state, caller_stack, 1)? {
@ -98,10 +98,10 @@ impl Command for OverlayUse {
return Err(ShellError::NonUtf8(name_arg.span)); return Err(ShellError::NonUtf8(name_arg.span));
} }
} else { } else {
return Err(ShellError::OverlayNotFoundAtRuntime( return Err(ShellError::OverlayNotFoundAtRuntime {
name_arg.item, overlay_name: name_arg.item,
name_arg.span, span: name_arg.span,
)); });
}; };
if let Some(module_id) = maybe_origin_module_id { if let Some(module_id) = maybe_origin_module_id {

View File

@ -89,12 +89,12 @@ impl Command for While {
} }
} }
x => { x => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"bool".into(), to_type: "bool".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
result.span()?, span: result.span()?,
None, help: None,
)) })
} }
} }
} }

View File

@ -204,11 +204,11 @@ fn run_histogram(
} }
if inputs.is_empty() { if inputs.is_empty() {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.clone(), col_name: col_name.clone(),
head_span, span: head_span,
list_span, src_span: list_span,
)); });
} }
} }
} }

View File

@ -134,15 +134,15 @@ fn string_to_boolean(s: &str, span: Span) -> Result<bool, ShellError> {
let val = o.parse::<f64>(); let val = o.parse::<f64>();
match val { match val {
Ok(f) => Ok(f.abs() >= f64::EPSILON), Ok(f) => Ok(f.abs() >= f64::EPSILON),
Err(_) => Err(ShellError::CantConvert( Err(_) => Err(ShellError::CantConvert {
"boolean".to_string(), to_type: "boolean".to_string(),
"string".to_string(), from_type: "string".to_string(),
span, span,
Some( help: Some(
r#"the strings "true" and "false" can be converted into a bool"# r#"the strings "true" and "false" can be converted into a bool"#
.to_string(), .to_string(),
), ),
)), }),
} }
} }
} }

View File

@ -307,12 +307,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
Ok(d) => Value::Date { val: d, span: head }, Ok(d) => Value::Date { val: d, span: head },
Err(reason) => { Err(reason) => {
Value::Error { Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) },
format!("could not parse as datetime using format '{}'", dt.0),
reason.to_string(),
head,
Some("you can use `into datetime` without a format string to enable flexible parsing".to_string())
),
} }
} }
}, },

View File

@ -88,12 +88,12 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
match other.parse::<f64>() { match other.parse::<f64>() {
Ok(x) => Value::float(x, head), Ok(x) => Value::float(x, head),
Err(reason) => Value::Error { Err(reason) => Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
"float".to_string(), to_type: "float".to_string(),
reason.to_string(), from_type: reason.to_string(),
*span, span: *span,
None, help: None,
), },
}, },
} }
} }

View File

@ -315,17 +315,17 @@ fn convert_str_from_unit_to_unit(
("yr", "yr") => Ok(val as f64), ("yr", "yr") => Ok(val as f64),
("yr", "dec") => Ok(val as f64 / 10.0), ("yr", "dec") => Ok(val as f64 / 10.0),
_ => Err(ShellError::CantConvertWithValue( _ => Err(ShellError::CantConvertWithValue {
"string duration".to_string(), to_type: "string duration".to_string(),
"string duration".to_string(), from_type: "string duration".to_string(),
to_unit.to_string(), details: to_unit.to_string(),
span, dst_span: span,
value_span, src_span: value_span,
Some( help: Some(
"supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec" "supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec"
.to_string(), .to_string(),
), ),
)), }),
} }
} }
@ -348,16 +348,16 @@ fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, Shel
} }
} }
Err(ShellError::CantConvertWithValue( Err(ShellError::CantConvertWithValue {
"duration".to_string(), to_type: "duration".to_string(),
"string".to_string(), from_type: "string".to_string(),
s.to_string(), details: s.to_string(),
span, dst_span: span,
value_span, src_span: value_span,
Some( help: Some(
"supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec".to_string(), "supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec".to_string(),
), ),
)) })
} }
fn string_to_unit_duration( fn string_to_unit_duration(
@ -384,16 +384,16 @@ fn string_to_unit_duration(
} }
} }
Err(ShellError::CantConvertWithValue( Err(ShellError::CantConvertWithValue {
"duration".to_string(), to_type: "duration".to_string(),
"string".to_string(), from_type: "string".to_string(),
s.to_string(), details: s.to_string(),
span, dst_span: span,
value_span, src_span: value_span,
Some( help: Some(
"supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec".to_string(), "supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec".to_string(),
), ),
)) })
} }
fn action( fn action(
@ -468,12 +468,12 @@ fn action(
} }
} else { } else {
Value::Error { Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
"string".into(), to_type: "string".into(),
"duration".into(), from_type: "duration".into(),
span, span,
None, help: None,
), },
} }
} }
} else { } else {

View File

@ -133,12 +133,12 @@ pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> { fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
match a_string.trim().parse::<bytesize::ByteSize>() { match a_string.trim().parse::<bytesize::ByteSize>() {
Ok(n) => Ok(n.0 as i64), Ok(n) => Ok(n.0 as i64),
Err(_) => Err(ShellError::CantConvert( Err(_) => Err(ShellError::CantConvert {
"int".into(), to_type: "int".into(),
"string".into(), from_type: "string".into(),
span, span,
None, help: None,
)), }),
} }
} }

View File

@ -187,12 +187,12 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
Ok(v) => v, Ok(v) => v,
_ => { _ => {
return Value::Error { return Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
"float".to_string(), to_type: "float".to_string(),
"integer".to_string(), from_type: "integer".to_string(),
span, span,
None, help: None,
), },
} }
} }
} }
@ -277,12 +277,12 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
Ok(n) => return Value::int(n, head), Ok(n) => return Value::int(n, head),
Err(e) => { Err(e) => {
return Value::Error { return Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
"string".to_string(), to_type: "string".to_string(),
"int".to_string(), from_type: "int".to_string(),
head, span: head,
Some(e.to_string()), help: Some(e.to_string()),
), },
} }
} }
} }
@ -305,7 +305,12 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
match i64::from_str_radix(i.trim(), radix) { match i64::from_str_radix(i.trim(), radix) {
Ok(n) => Value::int(n, head), Ok(n) => Value::int(n, head),
Err(_reason) => Value::Error { Err(_reason) => Value::Error {
error: ShellError::CantConvert("string".to_string(), "int".to_string(), head, None), error: ShellError::CantConvert {
to_type: "string".to_string(),
from_type: "int".to_string(),
span: head,
help: None,
},
}, },
} }
} }
@ -317,12 +322,12 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
let num = match i64::from_str_radix(b.trim_start_matches("0b"), 2) { let num = match i64::from_str_radix(b.trim_start_matches("0b"), 2) {
Ok(n) => n, Ok(n) => n,
Err(_reason) => { Err(_reason) => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"int".to_string(), to_type: "int".to_string(),
"string".to_string(), from_type: "string".to_string(),
span, span,
Some(r#"digits following "0b" can only be 0 or 1"#.to_string()), help: Some(r#"digits following "0b" can only be 0 or 1"#.to_string()),
)) })
} }
}; };
Ok(num) Ok(num)
@ -331,15 +336,15 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
let num = let num =
match i64::from_str_radix(h.trim_start_matches("0x"), 16) { match i64::from_str_radix(h.trim_start_matches("0x"), 16) {
Ok(n) => n, Ok(n) => n,
Err(_reason) => return Err(ShellError::CantConvert( Err(_reason) => return Err(ShellError::CantConvert {
"int".to_string(), to_type: "int".to_string(),
"string".to_string(), from_type: "string".to_string(),
span, span,
Some( help: Some(
r#"hexadecimal digits following "0x" should be in 0-9, a-f, or A-F"# r#"hexadecimal digits following "0x" should be in 0-9, a-f, or A-F"#
.to_string(), .to_string(),
), ),
)), }),
}; };
Ok(num) Ok(num)
} }
@ -347,12 +352,12 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
let num = match i64::from_str_radix(o.trim_start_matches("0o"), 8) { let num = match i64::from_str_radix(o.trim_start_matches("0o"), 8) {
Ok(n) => n, Ok(n) => n,
Err(_reason) => { Err(_reason) => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"int".to_string(), to_type: "int".to_string(),
"string".to_string(), from_type: "string".to_string(),
span, span,
Some(r#"octal digits following "0o" should be in 0-7"#.to_string()), help: Some(r#"octal digits following "0o" should be in 0-7"#.to_string()),
)) })
} }
}; };
Ok(num) Ok(num)
@ -361,14 +366,14 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
Ok(n) => Ok(n), Ok(n) => Ok(n),
Err(_) => match a_string.parse::<f64>() { Err(_) => match a_string.parse::<f64>() {
Ok(f) => Ok(f as i64), Ok(f) => Ok(f as i64),
_ => Err(ShellError::CantConvert( _ => Err(ShellError::CantConvert {
"int".to_string(), to_type: "int".to_string(),
"string".to_string(), from_type: "string".to_string(),
span, span,
Some(format!( help: Some(format!(
r#"string "{trimmed}" does not represent a valid integer"# r#"string "{trimmed}" does not represent a valid integer"#
)), )),
)), }),
}, },
}, },
} }

View File

@ -247,28 +247,28 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
span: _, span: _,
} => Value::Error { } => Value::Error {
// Watch out for CantConvert's argument order // Watch out for CantConvert's argument order
error: ShellError::CantConvert( error: ShellError::CantConvert {
"string".into(), to_type: "string".into(),
"record".into(), from_type: "record".into(),
span, span,
Some("try using the `to nuon` command".into()), help: Some("try using the `to nuon` command".into()),
), },
}, },
Value::Binary { .. } => Value::Error { Value::Binary { .. } => Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
"string".into(), to_type: "string".into(),
"binary".into(), from_type: "binary".into(),
span, span,
Some("try using the `decode` command".into()), help: Some("try using the `decode` command".into()),
), },
}, },
x => Value::Error { x => Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
String::from("string"), to_type: String::from("string"),
x.get_type().to_string(), from_type: x.get_type().to_string(),
span, span,
None, help: None,
), },
}, },
} }
} }

View File

@ -62,19 +62,19 @@ impl SQLiteDatabase {
path: db.path.clone(), path: db.path.clone(),
ctrlc: db.ctrlc.clone(), ctrlc: db.ctrlc.clone(),
}), }),
None => Err(ShellError::CantConvert( None => Err(ShellError::CantConvert {
"database".into(), to_type: "database".into(),
"non-database".into(), from_type: "non-database".into(),
span, span,
None, help: None,
)), }),
}, },
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"database".into(), to_type: "database".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }
@ -309,7 +309,7 @@ impl CustomValue for SQLiteDatabase {
fn follow_path_int(&self, _count: usize, span: Span) -> Result<Value, ShellError> { fn follow_path_int(&self, _count: usize, span: Span) -> Result<Value, ShellError> {
// In theory we could support this, but tables don't have an especially well-defined order // In theory we could support this, but tables don't have an especially well-defined order
Err(ShellError::IncompatiblePathAccess("SQLite databases do not support integer-indexed access. Try specifying a table name instead".into(), span)) Err(ShellError::IncompatiblePathAccess { type_name: "SQLite databases do not support integer-indexed access. Try specifying a table name instead".into(), span })
} }
fn follow_path_string(&self, _column_name: String, span: Span) -> Result<Value, ShellError> { fn follow_path_string(&self, _column_name: String, span: Span) -> Result<Value, ShellError> {

View File

@ -109,12 +109,12 @@ impl Command for WithColumn {
let df = NuDataFrame::try_from_value(value)?; let df = NuDataFrame::try_from_value(value)?;
command_eager(engine_state, stack, call, df) command_eager(engine_state, stack, call, df)
} else { } else {
Err(ShellError::CantConvert( Err(ShellError::CantConvert {
"lazy or eager dataframe".into(), to_type: "lazy or eager dataframe".into(),
value.get_type().to_string(), from_type: value.get_type().to_string(),
value.span()?, span: value.span()?,
None, help: None,
)) })
} }
} }
} }

View File

@ -270,14 +270,14 @@ pub(super) fn compute_series_single_value(
Operator::Math(Math::Divide) => match &right { Operator::Math(Math::Divide) => match &right {
Value::Int { val, span } => { Value::Int { val, span } => {
if *val == 0 { if *val == 0 {
Err(ShellError::DivisionByZero(*span)) Err(ShellError::DivisionByZero { span: *span })
} else { } else {
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span) compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span)
} }
} }
Value::Float { val, span } => { Value::Float { val, span } => {
if val.is_zero() { if val.is_zero() {
Err(ShellError::DivisionByZero(*span)) Err(ShellError::DivisionByZero { span: *span })
} else { } else {
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span) compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span)
} }

View File

@ -240,12 +240,12 @@ impl NuDataFrame {
let df = lazy.collect(span)?; let df = lazy.collect(span)?;
Ok(df) Ok(df)
} else { } else {
Err(ShellError::CantConvert( Err(ShellError::CantConvert {
"lazy or eager dataframe".into(), to_type: "lazy or eager dataframe".into(),
value.get_type().to_string(), from_type: value.get_type().to_string(),
value.span()?, span: value.span()?,
None, help: None,
)) })
} }
} }
@ -256,19 +256,19 @@ impl NuDataFrame {
df: df.df.clone(), df: df.df.clone(),
from_lazy: false, from_lazy: false,
}), }),
None => Err(ShellError::CantConvert( None => Err(ShellError::CantConvert {
"dataframe".into(), to_type: "dataframe".into(),
"non-dataframe".into(), from_type: "non-dataframe".into(),
span, span,
None, help: None,
)), }),
}, },
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"dataframe".into(), to_type: "dataframe".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }
@ -343,7 +343,7 @@ impl NuDataFrame {
let column = conversion::create_column(&series, row, row + 1, span)?; let column = conversion::create_column(&series, row, row + 1, span)?;
if column.len() == 0 { if column.len() == 0 {
Err(ShellError::AccessEmptyContent(span)) Err(ShellError::AccessEmptyContent { span })
} else { } else {
let value = column let value = column
.into_iter() .into_iter()

View File

@ -72,23 +72,23 @@ impl NuExpression {
match value { match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() { Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(NuExpression(expr.0.clone())), Some(expr) => Ok(NuExpression(expr.0.clone())),
None => Err(ShellError::CantConvert( None => Err(ShellError::CantConvert {
"lazy expression".into(), to_type: "lazy expression".into(),
"non-dataframe".into(), from_type: "non-dataframe".into(),
span, span,
None, help: None,
)), }),
}, },
Value::String { val, .. } => Ok(val.lit().into()), Value::String { val, .. } => Ok(val.lit().into()),
Value::Int { val, .. } => Ok(val.lit().into()), Value::Int { val, .. } => Ok(val.lit().into()),
Value::Bool { val, .. } => Ok(val.lit().into()), Value::Bool { val, .. } => Ok(val.lit().into()),
Value::Float { val, .. } => Ok(val.lit().into()), Value::Float { val, .. } => Ok(val.lit().into()),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"lazy expression".into(), to_type: "lazy expression".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }
@ -160,12 +160,12 @@ impl ExtractedExpr {
.map(Self::extract_exprs) .map(Self::extract_exprs)
.collect::<Result<Vec<ExtractedExpr>, ShellError>>() .collect::<Result<Vec<ExtractedExpr>, ShellError>>()
.map(ExtractedExpr::List), .map(ExtractedExpr::List),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"expression".into(), to_type: "expression".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }
} }

View File

@ -132,12 +132,12 @@ impl NuLazyFrame {
let df = NuDataFrame::try_from_value(value)?; let df = NuDataFrame::try_from_value(value)?;
Ok(NuLazyFrame::from_dataframe(df)) Ok(NuLazyFrame::from_dataframe(df))
} else { } else {
Err(ShellError::CantConvert( Err(ShellError::CantConvert {
"lazy or eager dataframe".into(), to_type: "lazy or eager dataframe".into(),
value.get_type().to_string(), from_type: value.get_type().to_string(),
value.span()?, span: value.span()?,
None, help: None,
)) })
} }
} }
@ -154,19 +154,19 @@ impl NuLazyFrame {
from_eager: false, from_eager: false,
schema: None, schema: None,
}), }),
None => Err(ShellError::CantConvert( None => Err(ShellError::CantConvert {
"lazy frame".into(), to_type: "lazy frame".into(),
"non-dataframe".into(), from_type: "non-dataframe".into(),
span, span,
None, help: None,
)), }),
}, },
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"lazy frame".into(), to_type: "lazy frame".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }

View File

@ -93,20 +93,20 @@ impl NuLazyGroupBy {
schema: group.schema.clone(), schema: group.schema.clone(),
from_eager: group.from_eager, from_eager: group.from_eager,
}), }),
None => Err(ShellError::CantConvert( None => Err(ShellError::CantConvert {
"lazy groupby".into(), to_type: "lazy groupby".into(),
"custom value".into(), from_type: "custom value".into(),
span, span,
None, help: None,
)), }),
} }
} }
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"lazy groupby".into(), to_type: "lazy groupby".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }

View File

@ -61,19 +61,19 @@ impl NuWhen {
match value { match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() { Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(expr.clone()), Some(expr) => Ok(expr.clone()),
None => Err(ShellError::CantConvert( None => Err(ShellError::CantConvert {
"when expression".into(), to_type: "when expression".into(),
"non when expression".into(), from_type: "non when expression".into(),
span, span,
None, help: None,
)), }),
}, },
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"when expression".into(), to_type: "when expression".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }
} }

View File

@ -52,10 +52,10 @@ impl Command for LetEnv {
.into_value(call.head); .into_value(call.head);
if env_var.item == "FILE_PWD" || env_var.item == "PWD" { if env_var.item == "FILE_PWD" || env_var.item == "PWD" {
return Err(ShellError::AutomaticEnvVarSetManually( return Err(ShellError::AutomaticEnvVarSetManually {
env_var.item, envvar_name: env_var.item,
env_var.span, span: env_var.span,
)); });
} else { } else {
stack.add_env_var(env_var.item, rhs); stack.add_env_var(env_var.item, rhs);
} }

View File

@ -43,11 +43,17 @@ impl Command for LoadEnv {
Some((cols, vals)) => { Some((cols, vals)) => {
for (env_var, rhs) in cols.into_iter().zip(vals) { for (env_var, rhs) in cols.into_iter().zip(vals) {
if env_var == "FILE_PWD" { if env_var == "FILE_PWD" {
return Err(ShellError::AutomaticEnvVarSetManually(env_var, call.head)); return Err(ShellError::AutomaticEnvVarSetManually {
envvar_name: env_var,
span: call.head,
});
} }
if env_var == "PWD" { if env_var == "PWD" {
return Err(ShellError::AutomaticEnvVarSetManually(env_var, call.head)); return Err(ShellError::AutomaticEnvVarSetManually {
envvar_name: env_var,
span: call.head,
});
} else { } else {
stack.add_env_var(env_var, rhs); stack.add_env_var(env_var, rhs);
} }
@ -58,7 +64,10 @@ impl Command for LoadEnv {
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => { PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
for (env_var, rhs) in cols.into_iter().zip(vals) { for (env_var, rhs) in cols.into_iter().zip(vals) {
if env_var == "FILE_PWD" { if env_var == "FILE_PWD" {
return Err(ShellError::AutomaticEnvVarSetManually(env_var, call.head)); return Err(ShellError::AutomaticEnvVarSetManually {
envvar_name: env_var,
span: call.head,
});
} }
if env_var == "PWD" { if env_var == "PWD" {

View File

@ -100,14 +100,15 @@ fn with_env(
} }
} }
x => { x => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"string list or single row".into(), to_type: "string list or single row".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
call.positional_nth(1) span: call
.positional_nth(1)
.expect("already checked through .req") .expect("already checked through .req")
.span, .span,
None, help: None,
)); });
} }
} }
} else { } else {
@ -127,14 +128,15 @@ fn with_env(
} }
} }
x => { x => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"string list or single row".into(), to_type: "string list or single row".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
call.positional_nth(1) span: call
.positional_nth(1)
.expect("already checked through .req") .expect("already checked through .req")
.span, .span,
None, help: None,
)); });
} }
}; };

View File

@ -101,12 +101,10 @@ impl Command for Save {
let res = stream_to_file(stream, file, span, progress); let res = stream_to_file(stream, file, span, progress);
if let Some(h) = handler { if let Some(h) = handler {
h.join().map_err(|err| { h.join().map_err(|err| ShellError::ExternalCommand {
ShellError::ExternalCommand( label: "Fail to receive external commands stderr message".to_string(),
"Fail to receive external commands stderr message".to_string(), help: format!("{err:?}"),
format!("{err:?}"),
span, span,
)
})??; })??;
res res
} else { } else {

View File

@ -110,7 +110,7 @@ fn first_helper(
Value::List { vals, .. } => { Value::List { vals, .. } => {
if return_single_element { if return_single_element {
if vals.is_empty() { if vals.is_empty() {
Err(ShellError::AccessEmptyContent(head)) Err(ShellError::AccessEmptyContent { span: head })
} else { } else {
Ok(vals[0].clone().into_pipeline_data()) Ok(vals[0].clone().into_pipeline_data())
} }
@ -154,7 +154,7 @@ fn first_helper(
if let Some(v) = ls.next() { if let Some(v) = ls.next() {
Ok(v.into_pipeline_data()) Ok(v.into_pipeline_data())
} else { } else {
Err(ShellError::AccessEmptyContent(head)) Err(ShellError::AccessEmptyContent { span: head })
} }
} else { } else {
Ok(ls Ok(ls

View File

@ -248,11 +248,11 @@ pub fn group(
}; };
match row.get_data_by_key(&column_name.item) { match row.get_data_by_key(&column_name.item) {
Some(group_key) => Ok(group_key.as_string()?), Some(group_key) => Ok(group_key.as_string()?),
None => Err(ShellError::CantFindColumn( None => Err(ShellError::CantFindColumn {
column_name.item.to_string(), col_name: column_name.item.to_string(),
column_name.span, span: column_name.span,
row.expect_span(), src_span: row.expect_span(),
)), }),
} }
}); });
@ -263,9 +263,9 @@ pub fn group(
data_group(values, &Some(block), name) data_group(values, &Some(block), name)
} }
Grouper::ByBlock => Err(ShellError::NushellFailed( Grouper::ByBlock => Err(ShellError::NushellFailed {
"Block not implemented: This should never happen.".into(), msg: "Block not implemented: This should never happen.".into(),
)), }),
} }
} }

View File

@ -262,11 +262,11 @@ fn move_record_columns(
out_cols.push(col.into()); out_cols.push(col.into());
out_vals.push(val.clone()); out_vals.push(val.clone());
} else { } else {
return Err(ShellError::NushellFailedSpanned( return Err(ShellError::NushellFailedSpanned {
"Error indexing input columns".to_string(), msg: "Error indexing input columns".to_string(),
"originates from here".to_string(), label: "originates from here".to_string(),
span, span,
)); });
} }
} }
} }
@ -276,11 +276,11 @@ fn move_record_columns(
out_cols.push(col.into()); out_cols.push(col.into());
out_vals.push(val.clone()); out_vals.push(val.clone());
} else { } else {
return Err(ShellError::NushellFailedSpanned( return Err(ShellError::NushellFailedSpanned {
"Error indexing input columns".to_string(), msg: "Error indexing input columns".to_string(),
"originates from here".to_string(), label: "originates from here".to_string(),
span, span,
)); });
} }
} }

View File

@ -164,11 +164,11 @@ pub fn split(
Box::new( Box::new(
move |_, row: &Value| match row.get_data_by_key(&column_name.item) { move |_, row: &Value| match row.get_data_by_key(&column_name.item) {
Some(group_key) => Ok(group_key.as_string()?), Some(group_key) => Ok(group_key.as_string()?),
None => Err(ShellError::CantFindColumn( None => Err(ShellError::CantFindColumn {
column_name.item.to_string(), col_name: column_name.item.to_string(),
column_name.span, span: column_name.span,
row.span().unwrap_or(column_name.span), src_span: row.span().unwrap_or(column_name.span),
)), }),
}, },
); );

View File

@ -135,7 +135,11 @@ fn validate(vec: Vec<Value>, columns: &Vec<String>, span: Span) -> Result<(), Sh
} }
if let Some(nonexistent) = nonexistent_column(columns.clone(), cols.to_vec()) { if let Some(nonexistent) = nonexistent_column(columns.clone(), cols.to_vec()) {
return Err(ShellError::CantFindColumn(nonexistent, span, *val_span)); return Err(ShellError::CantFindColumn {
col_name: nonexistent,
span,
src_span: *val_span,
});
} }
} }

View File

@ -151,9 +151,12 @@ fn update(
if let Some(v) = input.next() { if let Some(v) = input.next() {
pre_elems.push(v); pre_elems.push(v);
} else if idx == 0 { } else if idx == 0 {
return Err(ShellError::AccessEmptyContent(*span)); return Err(ShellError::AccessEmptyContent { span: *span });
} else { } else {
return Err(ShellError::AccessBeyondEnd(idx - 1, *span)); return Err(ShellError::AccessBeyondEnd {
max_idx: idx - 1,
span: *span,
});
} }
} }

View File

@ -173,7 +173,10 @@ fn upsert(
if let Some(v) = input.next() { if let Some(v) = input.next() {
pre_elems.push(v); pre_elems.push(v);
} else { } else {
return Err(ShellError::AccessBeyondEnd(idx, *span)); return Err(ShellError::AccessBeyondEnd {
max_idx: idx,
span: *span,
});
} }
} }

View File

@ -119,12 +119,12 @@ fn convert_nujson_to_value(value: &nu_json::Value, span: Span) -> Value {
nu_json::Value::U64(u) => { nu_json::Value::U64(u) => {
if *u > i64::MAX as u64 { if *u > i64::MAX as u64 {
Value::Error { Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
"i64 sized integer".into(), to_type: "i64 sized integer".into(),
"value larger than i64".into(), from_type: "value larger than i64".into(),
span, span,
None, help: None,
), },
} }
} else { } else {
Value::Int { Value::Int {
@ -182,12 +182,12 @@ fn convert_string_to_value(string_input: String, span: Span) -> Result<Value, Sh
)], )],
)) ))
} }
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
format!("structured json data ({x})"), to_type: format!("structured json data ({x})"),
"string".into(), from_type: "string".into(),
span, span,
None, help: None,
)), }),
}, },
} }
} }

View File

@ -106,12 +106,12 @@ pub fn convert_string_to_value(string_input: String, span: Span) -> Result<Value
match result { match result {
Ok(value) => Ok(convert_toml_to_value(&value, span)), Ok(value) => Ok(convert_toml_to_value(&value, span)),
Err(err) => Err(ShellError::CantConvert( Err(err) => Err(ShellError::CantConvert {
"structured toml data".into(), to_type: "structured toml data".into(),
"string".into(), from_type: "string".into(),
span, span,
Some(err.to_string()), help: Some(err.to_string()),
)), }),
} }
} }

View File

@ -95,7 +95,12 @@ fn writer_to_string(writer: Writer<Vec<u8>>) -> Result<String, Box<dyn Error>> {
} }
fn make_conversion_error(type_from: &str, span: &Span) -> ShellError { fn make_conversion_error(type_from: &str, span: &Span) -> ShellError {
ShellError::CantConvert(type_from.to_string(), "string".to_string(), *span, None) ShellError::CantConvert {
to_type: type_from.to_string(),
from_type: "string".to_string(),
span: *span,
help: None,
}
} }
fn to_string_tagged_value( fn to_string_tagged_value(
@ -174,12 +179,12 @@ pub fn to_delimited_data(
} }
Ok(x) Ok(x)
} }
Err(_) => Err(ShellError::CantConvert( Err(_) => Err(ShellError::CantConvert {
format_name.into(), to_type: format_name.into(),
value.get_type().to_string(), from_type: value.get_type().to_string(),
value.span().unwrap_or(span), span: value.span().unwrap_or(span),
None, help: None,
)), }),
}?; }?;
Ok(Value::string(output, span).into_pipeline_data()) Ok(Value::string(output, span).into_pipeline_data())
} }

View File

@ -70,12 +70,12 @@ impl Command for ToJson {
} }
.into_pipeline_data()), .into_pipeline_data()),
_ => Ok(Value::Error { _ => Ok(Value::Error {
error: ShellError::CantConvert( error: ShellError::CantConvert {
"JSON".into(), to_type: "JSON".into(),
value.get_type().to_string(), from_type: value.get_type().to_string(),
span, span,
None, help: None,
), },
} }
.into_pipeline_data()), .into_pipeline_data()),
} }

View File

@ -118,7 +118,12 @@ fn toml_into_pipeline_data(
} }
.into_pipeline_data()), .into_pipeline_data()),
_ => Ok(Value::Error { _ => Ok(Value::Error {
error: ShellError::CantConvert("TOML".into(), value_type.to_string(), span, None), error: ShellError::CantConvert {
to_type: "TOML".into(),
from_type: value_type.to_string(),
span,
help: None,
},
} }
.into_pipeline_data()), .into_pipeline_data()),
} }

View File

@ -185,12 +185,12 @@ fn to_xml(
}; };
Ok(Value::string(s, head).into_pipeline_data()) Ok(Value::string(s, head).into_pipeline_data())
} }
Err(_) => Err(ShellError::CantConvert( Err(_) => Err(ShellError::CantConvert {
"XML".into(), to_type: "XML".into(),
value_type.to_string(), from_type: value_type.to_string(),
head, span: head,
None, help: None,
)), }),
} }
} }

View File

@ -111,7 +111,12 @@ fn to_yaml(input: PipelineData, head: Span) -> Result<PipelineData, ShellError>
} }
.into_pipeline_data()), .into_pipeline_data()),
_ => Ok(Value::Error { _ => Ok(Value::Error {
error: ShellError::CantConvert("YAML".into(), value.get_type().to_string(), head, None), error: ShellError::CantConvert {
to_type: "YAML".into(),
from_type: value.get_type().to_string(),
span: head,
help: None,
},
} }
.into_pipeline_data()), .into_pipeline_data()),
} }

View File

@ -241,12 +241,12 @@ pub fn request_add_custom_headers(
} }
x => { x => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"string list or single row".into(), to_type: "string list or single row".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
headers.span().unwrap_or_else(|_| Span::new(0, 0)), span: headers.span().unwrap_or_else(|_| Span::new(0, 0)),
None, help: None,
)); });
} }
} }
} else { } else {
@ -260,12 +260,12 @@ pub fn request_add_custom_headers(
} }
x => { x => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"string list or single row".into(), to_type: "string list or single row".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
headers.span().unwrap_or_else(|_| Span::new(0, 0)), span: headers.span().unwrap_or_else(|_| Span::new(0, 0)),
None, help: None,
)); });
} }
}; };

View File

@ -89,12 +89,12 @@ fn to_url(input: PipelineData, head: Span) -> Result<PipelineData, ShellError> {
match serde_urlencoded::to_string(row_vec) { match serde_urlencoded::to_string(row_vec) {
Ok(s) => Ok(s), Ok(s) => Ok(s),
_ => Err(ShellError::CantConvert( _ => Err(ShellError::CantConvert {
"URL".into(), to_type: "URL".into(),
value.get_type().to_string(), from_type: value.get_type().to_string(),
head, span: head,
None, help: None,
)), }),
} }
} }
// Propagate existing errors // Propagate existing errors

View File

@ -128,7 +128,12 @@ fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value {
match lhs.strip_prefix(&rhs) { match lhs.strip_prefix(&rhs) {
Ok(p) => Value::string(p.to_string_lossy(), span), Ok(p) => Value::string(p.to_string_lossy(), span),
Err(e) => Value::Error { Err(e) => Value::Error {
error: ShellError::CantConvert(e.to_string(), "string".into(), span, None), error: ShellError::CantConvert {
to_type: e.to_string(),
from_type: "string".into(),
span,
help: None,
},
}, },
} }
} }

View File

@ -77,7 +77,7 @@ fn bool(
let probability_is_valid = (0.0..=1.0).contains(&probability); let probability_is_valid = (0.0..=1.0).contains(&probability);
if !probability_is_valid { if !probability_is_valid {
return Err(ShellError::InvalidProbability(prob.span)); return Err(ShellError::InvalidProbability { span: prob.span });
} }
} }

View File

@ -50,7 +50,9 @@ impl Command for GotoShell {
let n = shell_span let n = shell_span
.item .item
.parse::<usize>() .parse::<usize>()
.map_err(|_| ShellError::NotFound(shell_span.span))?; .map_err(|_| ShellError::NotFound {
span: shell_span.span,
})?;
switch_shell(engine_state, stack, call, shell_span.span, SwitchTo::Nth(n)) switch_shell(engine_state, stack, call, shell_span.span, SwitchTo::Nth(n))
} }

View File

@ -89,7 +89,7 @@ fn switch_shell(
let new_path = shells let new_path = shells
.get(new_shell) .get(new_shell)
.ok_or(ShellError::NotFound(span))? .ok_or(ShellError::NotFound { span })?
.to_owned(); .to_owned();
stack.add_env_var( stack.add_env_var(

View File

@ -89,7 +89,11 @@ pub fn sort(
} }
if let Some(nonexistent) = nonexistent_column(sort_columns.clone(), cols.to_vec()) { if let Some(nonexistent) = nonexistent_column(sort_columns.clone(), cols.to_vec()) {
return Err(ShellError::CantFindColumn(nonexistent, span, *val_span)); return Err(ShellError::CantFindColumn {
col_name: nonexistent,
span,
src_span: *val_span,
});
} }
// check to make sure each value in each column in the record // check to make sure each value in each column in the record

View File

@ -95,12 +95,10 @@ impl Command for Complete {
if let Some((handler, stderr_span)) = stderr_handler { if let Some((handler, stderr_span)) = stderr_handler {
cols.push("stderr".to_string()); cols.push("stderr".to_string());
let res = handler.join().map_err(|err| { let res = handler.join().map_err(|err| ShellError::ExternalCommand {
ShellError::ExternalCommand( label: "Fail to receive external commands stderr message".to_string(),
"Fail to receive external commands stderr message".to_string(), help: format!("{err:?}"),
format!("{err:?}"), span: stderr_span,
stderr_span,
)
})??; })??;
vals.push(res) vals.push(res)
}; };

View File

@ -291,7 +291,7 @@ fn heuristic_parse_file(
Err(ShellError::IOError("Can not read input".to_string())) Err(ShellError::IOError("Can not read input".to_string()))
} }
} else { } else {
Err(ShellError::NotFound(call.head)) Err(ShellError::NotFound { span: call.head })
} }
} }
@ -378,7 +378,7 @@ fn parse_file_script(
Err(ShellError::IOError("Can not read path".to_string())) Err(ShellError::IOError("Can not read path".to_string()))
} }
} else { } else {
Err(ShellError::NotFound(call.head)) Err(ShellError::NotFound { span: call.head })
} }
} }
@ -396,6 +396,6 @@ fn parse_file_module(
Err(ShellError::IOError("Can not read path".to_string())) Err(ShellError::IOError("Can not read path".to_string()))
} }
} else { } else {
Err(ShellError::NotFound(call.head)) Err(ShellError::NotFound { span: call.head })
} }
} }

View File

@ -106,12 +106,10 @@ pub fn create_external_command(
value value
.as_string() .as_string()
.map(|item| Spanned { item, span }) .map(|item| Spanned { item, span })
.map_err(|_| { .map_err(|_| ShellError::ExternalCommand {
ShellError::ExternalCommand( label: format!("Cannot convert {} to a string", value.get_type()),
format!("Cannot convert {} to a string", value.get_type()), help: "All arguments to an external command need to be string-compatible".into(),
"All arguments to an external command need to be string-compatible".into(),
span, span,
)
}) })
} }
@ -326,18 +324,18 @@ impl ExternalCommand {
} }
}; };
Err(ShellError::ExternalCommand( Err(ShellError::ExternalCommand {
label, label,
err.to_string(), help: err.to_string(),
self.name.span, span: self.name.span,
)) })
} }
// otherwise, a default error message // otherwise, a default error message
_ => Err(ShellError::ExternalCommand( _ => Err(ShellError::ExternalCommand {
"can't run executable".into(), label: "can't run executable".into(),
err.to_string(), help: err.to_string(),
self.name.span, span: self.name.span,
)), }),
} }
} }
Ok(mut child) => { Ok(mut child) => {
@ -408,23 +406,15 @@ impl ExternalCommand {
.spawn(move || { .spawn(move || {
if redirect_stdout { if redirect_stdout {
let stdout = stdout.ok_or_else(|| { let stdout = stdout.ok_or_else(|| {
ShellError::ExternalCommand( ShellError::ExternalCommand { label: "Error taking stdout from external".to_string(), help: "Redirects need access to stdout of an external command"
"Error taking stdout from external".to_string(), .to_string(), span }
"Redirects need access to stdout of an external command"
.to_string(),
span,
)
})?; })?;
read_and_redirect_message(stdout, stdout_tx, ctrlc) read_and_redirect_message(stdout, stdout_tx, ctrlc)
} }
match child.as_mut().wait() { match child.as_mut().wait() {
Err(err) => Err(ShellError::ExternalCommand( Err(err) => Err(ShellError::ExternalCommand { label: "External command exited with error".into(), help: err.to_string(), span }),
"External command exited with error".into(),
err.to_string(),
span,
)),
Ok(x) => { Ok(x) => {
#[cfg(unix)] #[cfg(unix)]
{ {
@ -455,11 +445,7 @@ impl ExternalCommand {
)) ))
); );
let _ = exit_code_tx.send(Value::Error { let _ = exit_code_tx.send(Value::Error {
error: ShellError::ExternalCommand( error: ShellError::ExternalCommand { label: "core dumped".to_string(), help: format!("{cause}: child process '{commandname}' core dumped"), span: head },
"core dumped".to_string(),
format!("{cause}: child process '{commandname}' core dumped"),
head,
),
}); });
return Ok(()); return Ok(());
} }
@ -481,13 +467,11 @@ impl ExternalCommand {
thread::Builder::new() thread::Builder::new()
.name("stderr redirector".to_string()) .name("stderr redirector".to_string())
.spawn(move || { .spawn(move || {
let stderr = stderr.ok_or_else(|| { let stderr = stderr.ok_or_else(|| ShellError::ExternalCommand {
ShellError::ExternalCommand( label: "Error taking stderr from external".to_string(),
"Error taking stderr from external".to_string(), help: "Redirects need access to stderr of an external command"
"Redirects need access to stderr of an external command"
.to_string(), .to_string(),
span, span,
)
})?; })?;
read_and_redirect_message(stderr, stderr_tx, stderr_ctrlc); read_and_redirect_message(stderr, stderr_tx, stderr_ctrlc);

View File

@ -98,12 +98,12 @@ impl CallExt for Call {
let result = eval_expression(engine_state, stack, expr)?; let result = eval_expression(engine_state, stack, expr)?;
FromValue::from_value(&result) FromValue::from_value(&result)
} else if self.positional_len() == 0 { } else if self.positional_len() == 0 {
Err(ShellError::AccessEmptyContent(self.head)) Err(ShellError::AccessEmptyContent { span: self.head })
} else { } else {
Err(ShellError::AccessBeyondEnd( Err(ShellError::AccessBeyondEnd {
self.positional_len() - 1, max_idx: self.positional_len() - 1,
self.head, span: self.head,
)) })
} }
} }
@ -117,12 +117,12 @@ impl CallExt for Call {
let result = eval_expression(engine_state, stack, expr)?; let result = eval_expression(engine_state, stack, expr)?;
FromValue::from_value(&result) FromValue::from_value(&result)
} else if self.parser_info.is_empty() { } else if self.parser_info.is_empty() {
Err(ShellError::AccessEmptyContent(self.head)) Err(ShellError::AccessEmptyContent { span: self.head })
} else { } else {
Err(ShellError::AccessBeyondEnd( Err(ShellError::AccessBeyondEnd {
self.parser_info.len() - 1, max_idx: self.parser_info.len() - 1,
self.head, span: self.head,
)) })
} }
} }
} }

View File

@ -77,18 +77,12 @@ pub fn convert_env_values(engine_state: &mut EngineState, stack: &Stack) -> Opti
} }
} else { } else {
error = error.or_else(|| { error = error.or_else(|| {
Some(ShellError::NushellFailedHelp( Some(ShellError::NushellFailedHelp { msg: "Last active overlay not found in permanent state.".into(), help: "This error happened during the conversion of environment variables from strings to Nushell values.".into() })
"Last active overlay not found in permanent state.".into(),
"This error happened during the conversion of environment variables from strings to Nushell values.".into(),
))
}); });
} }
} else { } else {
error = error.or_else(|| { error = error.or_else(|| {
Some(ShellError::NushellFailedHelp( Some(ShellError::NushellFailedHelp { msg: "Last active overlay not found in stack.".into(), help: "This error happened during the conversion of environment variables from strings to Nushell values.".into() })
"Last active overlay not found in stack.".into(),
"This error happened during the conversion of environment variables from strings to Nushell values.".into(),
))
}); });
} }
@ -122,22 +116,22 @@ pub fn env_to_string(
match std::env::join_paths(paths) { match std::env::join_paths(paths) {
Ok(p) => Ok(p.to_string_lossy().to_string()), Ok(p) => Ok(p.to_string_lossy().to_string()),
Err(_) => Err(ShellError::EnvVarNotAString( Err(_) => Err(ShellError::EnvVarNotAString {
env_name.to_string(), envvar_name: env_name.to_string(),
value.span()?, span: value.span()?,
)), }),
} }
} }
_ => Err(ShellError::EnvVarNotAString( _ => Err(ShellError::EnvVarNotAString {
env_name.to_string(), envvar_name: env_name.to_string(),
value.span()?, span: value.span()?,
)), }),
} }
} else { } else {
Err(ShellError::EnvVarNotAString( Err(ShellError::EnvVarNotAString {
env_name.to_string(), envvar_name: env_name.to_string(),
value.span()?, span: value.span()?,
)) })
} }
} }
}, },
@ -156,7 +150,7 @@ pub fn env_to_strings(
Ok(val_str) => { Ok(val_str) => {
env_vars_str.insert(env_name, val_str); env_vars_str.insert(env_name, val_str);
} }
Err(ShellError::EnvVarNotAString(..)) => {} // ignore non-string values Err(ShellError::EnvVarNotAString { .. }) => {} // ignore non-string values
Err(e) => return Err(e), Err(e) => return Err(e),
} }
} }
@ -214,16 +208,16 @@ pub fn path_str(
#[cfg(windows)] #[cfg(windows)]
match stack.get_env_var(engine_state, ENV_PATH_NAME_SECONDARY) { match stack.get_env_var(engine_state, ENV_PATH_NAME_SECONDARY) {
Some(v) => Ok((ENV_PATH_NAME_SECONDARY, v)), Some(v) => Ok((ENV_PATH_NAME_SECONDARY, v)),
None => Err(ShellError::EnvVarNotFoundAtRuntime( None => Err(ShellError::EnvVarNotFoundAtRuntime {
ENV_PATH_NAME_SECONDARY.to_string(), envvar_name: ENV_PATH_NAME_SECONDARY.to_string(),
span, span,
)), }),
} }
#[cfg(not(windows))] #[cfg(not(windows))]
Err(ShellError::EnvVarNotFoundAtRuntime( Err(ShellError::EnvVarNotFoundAtRuntime {
ENV_PATH_NAME.to_string(), envvar_name: ENV_PATH_NAME.to_string(),
span, span,
)) })
} }
}?; }?;

View File

@ -197,7 +197,7 @@ fn eval_external(
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let decl_id = engine_state let decl_id = engine_state
.find_decl("run-external".as_bytes(), &[]) .find_decl("run-external".as_bytes(), &[])
.ok_or(ShellError::ExternalNotSupported(head.span))?; .ok_or(ShellError::ExternalNotSupported { span: head.span })?;
let command = engine_state.get_decl(decl_id); let command = engine_state.get_decl(decl_id);
@ -260,12 +260,12 @@ pub fn eval_expression(
}), }),
Expr::ValueWithUnit(e, unit) => match eval_expression(engine_state, stack, e)? { Expr::ValueWithUnit(e, unit) => match eval_expression(engine_state, stack, e)? {
Value::Int { val, .. } => Ok(compute(val, unit.item, unit.span)), Value::Int { val, .. } => Ok(compute(val, unit.item, unit.span)),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"unit value".into(), to_type: "unit value".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
e.span, span: e.span,
None, help: None,
)), }),
}, },
Expr::Range(from, next, to, operator) => { Expr::Range(from, next, to, operator) => {
let from = if let Some(f) = from { let from = if let Some(f) = from {
@ -473,9 +473,9 @@ pub fn eval_expression(
lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?; lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?;
if is_env { if is_env {
if cell_path.tail.is_empty() { if cell_path.tail.is_empty() {
return Err(ShellError::CannotReplaceEnv( return Err(ShellError::CannotReplaceEnv {
cell_path.head.span, span: cell_path.head.span,
)); });
} }
// The special $env treatment: for something like $env.config.history.max_size = 2000, // The special $env treatment: for something like $env.config.history.max_size = 2000,
@ -1251,11 +1251,11 @@ fn check_subexp_substitution(mut input: PipelineData) -> Result<PipelineData, Sh
Some(stderr_stream) => stderr_stream.into_string().map(|s| s.item)?, Some(stderr_stream) => stderr_stream.into_string().map(|s| s.item)?,
}; };
if failed_to_run { if failed_to_run {
Err(ShellError::ExternalCommand( Err(ShellError::ExternalCommand {
"External command failed".to_string(), label: "External command failed".to_string(),
stderr_msg, help: stderr_msg,
span, span,
)) })
} else { } else {
// we've captured stderr message, but it's running success. // we've captured stderr message, but it's running success.
// So we need to re-print stderr message out. // So we need to re-print stderr message out.

View File

@ -45,7 +45,7 @@ impl Command for KnownExternal {
let head_span = call.head; let head_span = call.head;
let decl_id = engine_state let decl_id = engine_state
.find_decl("run-external".as_bytes(), &[]) .find_decl("run-external".as_bytes(), &[])
.ok_or(ShellError::ExternalNotSupported(head_span))?; .ok_or(ShellError::ExternalNotSupported { span: head_span })?;
let command = engine_state.get_decl(decl_id); let command = engine_state.get_decl(decl_id);
@ -54,11 +54,11 @@ impl Command for KnownExternal {
let extern_name = if let Some(name_bytes) = engine_state.find_decl_name(call.decl_id, &[]) { let extern_name = if let Some(name_bytes) = engine_state.find_decl_name(call.decl_id, &[]) {
String::from_utf8_lossy(name_bytes) String::from_utf8_lossy(name_bytes)
} else { } else {
return Err(ShellError::NushellFailedSpanned( return Err(ShellError::NushellFailedSpanned {
"known external name not found".to_string(), msg: "known external name not found".to_string(),
"could not find name for this command".to_string(), label: "could not find name for this command".to_string(),
call.head, span: call.head,
)); });
}; };
let extern_name: Vec<_> = extern_name.split(' ').collect(); let extern_name: Vec<_> = extern_name.split(' ').collect();

View File

@ -97,12 +97,12 @@ impl EvaluatedCall {
if let Some(value) = self.nth(pos) { if let Some(value) = self.nth(pos) {
FromValue::from_value(&value) FromValue::from_value(&value)
} else if self.positional.is_empty() { } else if self.positional.is_empty() {
Err(ShellError::AccessEmptyContent(self.head)) Err(ShellError::AccessEmptyContent { span: self.head })
} else { } else {
Err(ShellError::AccessBeyondEnd( Err(ShellError::AccessBeyondEnd {
self.positional.len() - 1, max_idx: self.positional.len() - 1,
self.head, span: self.head,
)) })
} }
} }
} }

View File

@ -59,7 +59,12 @@ impl From<ShellError> for LabeledError {
ShellError::GenericError(label, msg, span, _help, _related) => { ShellError::GenericError(label, msg, span, _help, _related) => {
LabeledError { label, msg, span } LabeledError { label, msg, span }
} }
ShellError::CantConvert(expected, input, span, _help) => LabeledError { ShellError::CantConvert {
to_type: expected,
from_type: input,
span,
help: _help,
} => LabeledError {
label: format!("Can't convert to {expected}"), label: format!("Can't convert to {expected}"),
msg: format!("can't convert {expected} to {input}"), msg: format!("can't convert {expected} to {input}"),
span: Some(span), span: Some(span),

View File

@ -50,11 +50,11 @@ impl Command for Alias {
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
Err(ShellError::NushellFailedSpanned( Err(ShellError::NushellFailedSpanned {
"Can't run alias directly. Unwrap it first".to_string(), msg: "Can't run alias directly. Unwrap it first".to_string(),
"originates from here".to_string(), label: "originates from here".to_string(),
call.head, span: call.head,
)) })
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {

View File

@ -108,7 +108,7 @@ impl Stack {
return Ok(v.clone().with_span(span)); return Ok(v.clone().with_span(span));
} }
Err(ShellError::VariableNotFoundAtRuntime(span)) Err(ShellError::VariableNotFoundAtRuntime { span })
} }
pub fn get_var_with_origin(&self, var_id: VarId, span: Span) -> Result<Value, ShellError> { pub fn get_var_with_origin(&self, var_id: VarId, span: Span) -> Result<Value, ShellError> {
@ -116,7 +116,7 @@ impl Stack {
return Ok(v.clone()); return Ok(v.clone());
} }
Err(ShellError::VariableNotFoundAtRuntime(span)) Err(ShellError::VariableNotFoundAtRuntime { span })
} }
pub fn add_var(&mut self, var_id: VarId, value: Value) { pub fn add_var(&mut self, var_id: VarId, value: Value) {
@ -152,7 +152,9 @@ impl Stack {
self.active_overlays self.active_overlays
.last() .last()
.cloned() .cloned()
.ok_or_else(|| ShellError::NushellFailed("No active overlay".into())) .ok_or_else(|| ShellError::NushellFailed {
msg: "No active overlay".into(),
})
} }
pub fn captures_to_stack(&self, captures: &HashMap<VarId, Value>) -> Stack { pub fn captures_to_stack(&self, captures: &HashMap<VarId, Value>) -> Stack {

View File

@ -587,12 +587,10 @@ impl PipelineData {
let stderr = stderr_handler.map(|(handler, stderr_span, stderr_ctrlc)| { let stderr = stderr_handler.map(|(handler, stderr_span, stderr_ctrlc)| {
let stderr_bytes = handler let stderr_bytes = handler
.join() .join()
.map_err(|err| { .map_err(|err| ShellError::ExternalCommand {
ShellError::ExternalCommand( label: "Fail to receive external commands stderr message".to_string(),
"Fail to receive external commands stderr message".to_string(), help: format!("{err:?}"),
format!("{err:?}"), span: stderr_span,
stderr_span,
)
}) })
.unwrap_or_default(); .unwrap_or_default();
RawStream::new( RawStream::new(

View File

@ -226,15 +226,6 @@ pub enum ShellError {
span: Span, span: Span,
}, },
/// This build of nushell implements this feature, but it has not been enabled.
///
/// ## Resolution
///
/// Rebuild nushell with the appropriate feature enabled.
#[error("Feature not enabled.")]
#[diagnostic(code(nu::shell::feature_not_enabled))]
FeatureNotEnabled(#[label = "feature not enabled"] Span),
/// You're trying to run an unsupported external command. /// You're trying to run an unsupported external command.
/// ///
/// ## Resolution /// ## Resolution
@ -242,8 +233,12 @@ pub enum ShellError {
/// Make sure there's an appropriate `run-external` declaration for this external command. /// Make sure there's an appropriate `run-external` declaration for this external command.
#[error("Running external commands not supported")] #[error("Running external commands not supported")]
#[diagnostic(code(nu::shell::external_commands))] #[diagnostic(code(nu::shell::external_commands))]
ExternalNotSupported(#[label = "external not supported"] Span), ExternalNotSupported {
#[label = "external not supported"]
span: Span,
},
// TODO: consider moving to a more generic error variant for invalid values
/// The given probability input is invalid. The probability must be between 0 and 1. /// The given probability input is invalid. The probability must be between 0 and 1.
/// ///
/// ## Resolution /// ## Resolution
@ -251,7 +246,10 @@ pub enum ShellError {
/// Make sure the probability is between 0 and 1 and try again. /// Make sure the probability is between 0 and 1 and try again.
#[error("Invalid Probability.")] #[error("Invalid Probability.")]
#[diagnostic(code(nu::shell::invalid_probability))] #[diagnostic(code(nu::shell::invalid_probability))]
InvalidProbability(#[label = "invalid probability"] Span), InvalidProbability {
#[label = "invalid probability: must be between 0 and 1"]
span: Span,
},
/// The first value in a `..` range must be compatible with the second one. /// The first value in a `..` range must be compatible with the second one.
/// ///
@ -272,40 +270,47 @@ pub enum ShellError {
/// ## Resolution /// ## Resolution
/// ///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information. /// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
#[error("Nushell failed: {0}.")] #[error("Nushell failed: {msg}.")]
#[diagnostic(code(nu::shell::nushell_failed))] #[diagnostic(
code(nu::shell::nushell_failed),
help(
"This shouldn't happen. Please file an issue: https://github.com/nushell/nushell/issues"
))]
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable // Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
NushellFailed(String), NushellFailed { msg: String },
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error. /// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information. /// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
#[error("Nushell failed: {0}.")] #[error("Nushell failed: {msg}.")]
#[diagnostic(code(nu::shell::nushell_failed_spanned))] #[diagnostic(
code(nu::shell::nushell_failed_spanned),
help(
"This shouldn't happen. Please file an issue: https://github.com/nushell/nushell/issues"
))]
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable // Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
NushellFailedSpanned(String, String, #[label = "{1}"] Span), NushellFailedSpanned {
msg: String,
label: String,
#[label = "{label}"]
span: Span,
},
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error. /// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information. /// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
#[error("Nushell failed: {0}.")] #[error("Nushell failed: {msg}.")]
#[diagnostic(code(nu::shell::nushell_failed_help))] #[diagnostic(code(nu::shell::nushell_failed_help))]
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable // Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
NushellFailedHelp(String, #[help] String), NushellFailedHelp {
msg: String,
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error. #[help]
/// help: String,
/// ## Resolution },
///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
#[error("Nushell failed: {0}.")]
#[diagnostic(code(nu::shell::nushell_failed_spanned_help))]
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
NushellFailedSpannedHelp(String, String, #[label = "{1}"] Span, #[help] String),
/// A referenced variable was not found at runtime. /// A referenced variable was not found at runtime.
/// ///
@ -314,43 +319,49 @@ pub enum ShellError {
/// Check the variable name. Did you typo it? Did you forget to declare it? Is the casing right? /// Check the variable name. Did you typo it? Did you forget to declare it? Is the casing right?
#[error("Variable not found")] #[error("Variable not found")]
#[diagnostic(code(nu::shell::variable_not_found))] #[diagnostic(code(nu::shell::variable_not_found))]
VariableNotFoundAtRuntime(#[label = "variable not found"] Span), VariableNotFoundAtRuntime {
#[label = "variable not found"]
span: Span,
},
/// A referenced environment variable was not found at runtime. /// A referenced environment variable was not found at runtime.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// Check the environment variable name. Did you typo it? Did you forget to declare it? Is the casing right? /// Check the environment variable name. Did you typo it? Did you forget to declare it? Is the casing right?
#[error("Environment variable '{0}' not found")] #[error("Environment variable '{envvar_name}' not found")]
#[diagnostic(code(nu::shell::env_variable_not_found))] #[diagnostic(code(nu::shell::env_variable_not_found))]
EnvVarNotFoundAtRuntime(String, #[label = "environment variable not found"] Span), EnvVarNotFoundAtRuntime {
envvar_name: String,
#[label = "environment variable not found"]
span: Span,
},
/// A referenced module was not found at runtime. /// A referenced module was not found at runtime.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// Check the module name. Did you typo it? Did you forget to declare it? Is the casing right? /// Check the module name. Did you typo it? Did you forget to declare it? Is the casing right?
#[error("Module '{0}' not found")] #[error("Module '{mod_name}' not found")]
#[diagnostic(code(nu::shell::module_not_found))] #[diagnostic(code(nu::shell::module_not_found))]
ModuleNotFoundAtRuntime(String, #[label = "module not found"] Span), ModuleNotFoundAtRuntime {
mod_name: String,
/// A referenced module or overlay was not found at runtime. #[label = "module not found"]
/// span: Span,
/// ## Resolution },
///
/// Check the module name. Did you typo it? Did you forget to declare it? Is the casing right?
#[error("Module or overlay'{0}' not found")]
#[diagnostic(code(nu::shell::module_or_overlay_not_found))]
ModuleOrOverlayNotFoundAtRuntime(String, #[label = "not a module or overlay"] Span),
/// A referenced overlay was not found at runtime. /// A referenced overlay was not found at runtime.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// Check the overlay name. Did you typo it? Did you forget to declare it? Is the casing right? /// Check the overlay name. Did you typo it? Did you forget to declare it? Is the casing right?
#[error("Overlay '{0}' not found")] #[error("Overlay '{overlay_name}' not found")]
#[diagnostic(code(nu::shell::overlay_not_found))] #[diagnostic(code(nu::shell::overlay_not_found))]
OverlayNotFoundAtRuntime(String, #[label = "overlay not found"] Span), OverlayNotFoundAtRuntime {
overlay_name: String,
#[label = "overlay not found"]
span: Span,
},
/// The given item was not found. This is a fairly generic error that depends on context. /// The given item was not found. This is a fairly generic error that depends on context.
/// ///
@ -359,66 +370,82 @@ pub enum ShellError {
/// This error is triggered in various places, and simply signals that "something" was not found. Refer to the specific error message for further details. /// This error is triggered in various places, and simply signals that "something" was not found. Refer to the specific error message for further details.
#[error("Not found.")] #[error("Not found.")]
#[diagnostic(code(nu::parser::not_found))] #[diagnostic(code(nu::parser::not_found))]
NotFound(#[label = "did not find anything under this name"] Span), NotFound {
#[label = "did not find anything under this name"]
span: Span,
},
/// Failed to convert a value of one type into a different type. /// Failed to convert a value of one type into a different type.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// Not all values can be coerced this way. Check the supported type(s) and try again. /// Not all values can be coerced this way. Check the supported type(s) and try again.
#[error("Can't convert to {0}.")] #[error("Can't convert to {to_type}.")]
#[diagnostic(code(nu::shell::cant_convert))] #[diagnostic(code(nu::shell::cant_convert))]
CantConvert( CantConvert {
String, to_type: String,
String, from_type: String,
#[label("can't convert {1} to {0}")] Span, #[label("can't convert {from_type} to {to_type}")]
#[help] Option<String>, span: Span,
), #[help]
help: Option<String>,
},
/// Failed to convert a value of one type into a different type. Includes hint for what the first value is. /// Failed to convert a value of one type into a different type. Includes hint for what the first value is.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// Not all values can be coerced this way. Check the supported type(s) and try again. /// Not all values can be coerced this way. Check the supported type(s) and try again.
#[error("Can't convert {1} `{2}` to {0}.")] #[error("Can't convert {from_type} `{details}` to {to_type}.")]
#[diagnostic(code(nu::shell::cant_convert_with_value))] #[diagnostic(code(nu::shell::cant_convert_with_value))]
CantConvertWithValue( CantConvertWithValue {
String, to_type: String,
String, from_type: String,
String, details: String,
#[label("can't be converted to {0}")] Span, #[label("can't be converted to {to_type}")]
#[label("this {1} value...")] Span, dst_span: Span,
#[help] Option<String>, #[label("this {from_type} value...")]
), src_span: Span,
#[help]
help: Option<String>,
},
/// An environment variable cannot be represented as a string. /// An environment variable cannot be represented as a string.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// Not all types can be converted to environment variable values, which must be strings. Check the input type and try again. /// Not all types can be converted to environment variable values, which must be strings. Check the input type and try again.
#[error("{0} is not representable as a string.")] #[error("'{envvar_name}' is not representable as a string.")]
#[diagnostic( #[diagnostic(
code(nu::shell::env_var_not_a_string), code(nu::shell::env_var_not_a_string),
help( help(
r#"The '{0}' environment variable must be a string or be convertible to a string. r#"The '{envvar_name}' environment variable must be a string or be convertible to a string.
Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVERSIONS."# Either make sure '{envvar_name}' is a string, or add a 'to_string' entry for it in ENV_CONVERSIONS."#
) )
)] )]
EnvVarNotAString(String, #[label("value not representable as a string")] Span), EnvVarNotAString {
envvar_name: String,
#[label("value not representable as a string")]
span: Span,
},
/// This environment variable cannot be set manually. /// This environment variable cannot be set manually.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// This environment variable is set automatically by Nushell and cannot not be set manually. /// This environment variable is set automatically by Nushell and cannot not be set manually.
#[error("{0} cannot be set manually.")] #[error("{envvar_name} cannot be set manually.")]
#[diagnostic( #[diagnostic(
code(nu::shell::automatic_env_var_set_manually), code(nu::shell::automatic_env_var_set_manually),
help( help(
r#"The environment variable '{0}' is set automatically by Nushell and cannot not be set manually."# r#"The environment variable '{envvar_name}' is set automatically by Nushell and cannot not be set manually."#
) )
)] )]
AutomaticEnvVarSetManually(String, #[label("cannot set '{0}' manually")] Span), AutomaticEnvVarSetManually {
envvar_name: String,
#[label("cannot set '{envvar_name}' manually")]
span: Span,
},
/// It is not possible to replace the entire environment at once /// It is not possible to replace the entire environment at once
/// ///
@ -429,9 +456,12 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
#[error("Cannot replace environment.")] #[error("Cannot replace environment.")]
#[diagnostic( #[diagnostic(
code(nu::shell::cannot_replace_env), code(nu::shell::cannot_replace_env),
help(r#"Assigning a value to $env is not allowed."#) help(r#"Assigning a value to '$env' is not allowed."#)
)] )]
CannotReplaceEnv(#[label("setting $env not allowed")] Span), CannotReplaceEnv {
#[label("setting '$env' not allowed")]
span: Span,
},
/// Division by zero is not a thing. /// Division by zero is not a thing.
/// ///
@ -440,7 +470,10 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Add a guard of some sort to check whether a denominator input to this division is zero, and branch off if that's the case. /// Add a guard of some sort to check whether a denominator input to this division is zero, and branch off if that's the case.
#[error("Division by zero.")] #[error("Division by zero.")]
#[diagnostic(code(nu::shell::division_by_zero))] #[diagnostic(code(nu::shell::division_by_zero))]
DivisionByZero(#[label("division by zero")] Span), DivisionByZero {
#[label("division by zero")]
span: Span,
},
/// An error happened while tryin to create a range. /// An error happened while tryin to create a range.
/// ///
@ -451,28 +484,36 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Check your range values to make sure they're countable and would not loop forever. /// Check your range values to make sure they're countable and would not loop forever.
#[error("Can't convert range to countable values")] #[error("Can't convert range to countable values")]
#[diagnostic(code(nu::shell::range_to_countable))] #[diagnostic(code(nu::shell::range_to_countable))]
CannotCreateRange(#[label = "can't convert to countable values"] Span), CannotCreateRange {
#[label = "can't convert to countable values"]
span: Span,
},
/// You attempted to access an index beyond the available length of a value. /// You attempted to access an index beyond the available length of a value.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// Check your lengths and try again. /// Check your lengths and try again.
#[error("Row number too large (max: {0}).")] #[error("Row number too large (max: {max_idx}).")]
#[diagnostic(code(nu::shell::access_beyond_end))] #[diagnostic(code(nu::shell::access_beyond_end))]
AccessBeyondEnd(usize, #[label = "index too large (max: {0})"] Span), AccessBeyondEnd {
max_idx: usize,
#[label = "index too large (max: {max_idx})"]
span: Span,
},
/// You attempted to insert data at a list position higher than the end. /// You attempted to insert data at a list position higher than the end.
/// ///
/// ## Resolution /// ## Resolution
/// ///
/// To insert data into a list, assign to the last used index + 1. /// To insert data into a list, assign to the last used index + 1.
#[error("Inserted at wrong row number (should be {0}).")] #[error("Inserted at wrong row number (should be {available_idx}).")]
#[diagnostic(code(nu::shell::access_beyond_end))] #[diagnostic(code(nu::shell::access_beyond_end))]
InsertAfterNextFreeIndex( InsertAfterNextFreeIndex {
usize, available_idx: usize,
#[label = "can't insert at index (the next available index is {0})"] Span, #[label = "can't insert at index (the next available index is {available_idx})"]
), span: Span,
},
/// You attempted to access an index when it's empty. /// You attempted to access an index when it's empty.
/// ///
@ -481,8 +522,12 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Check your lengths and try again. /// Check your lengths and try again.
#[error("Row number too large (empty content).")] #[error("Row number too large (empty content).")]
#[diagnostic(code(nu::shell::access_beyond_end))] #[diagnostic(code(nu::shell::access_beyond_end))]
AccessEmptyContent(#[label = "index too large (empty content)"] Span), AccessEmptyContent {
#[label = "index too large (empty content)"]
span: Span,
},
// TODO: check to be taken over by `AccessBeyondEnd`
/// You attempted to access an index beyond the available length of a stream. /// You attempted to access an index beyond the available length of a stream.
/// ///
/// ## Resolution /// ## Resolution
@ -490,7 +535,10 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Check your lengths and try again. /// Check your lengths and try again.
#[error("Row number too large.")] #[error("Row number too large.")]
#[diagnostic(code(nu::shell::access_beyond_end_of_stream))] #[diagnostic(code(nu::shell::access_beyond_end_of_stream))]
AccessBeyondEndOfStream(#[label = "index too large"] Span), AccessBeyondEndOfStream {
#[label = "index too large"]
span: Span,
},
/// Tried to index into a type that does not support pathed access. /// Tried to index into a type that does not support pathed access.
/// ///
@ -499,7 +547,11 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Check your types. Only composite types can be pathed into. /// Check your types. Only composite types can be pathed into.
#[error("Data cannot be accessed with a cell path")] #[error("Data cannot be accessed with a cell path")]
#[diagnostic(code(nu::shell::incompatible_path_access))] #[diagnostic(code(nu::shell::incompatible_path_access))]
IncompatiblePathAccess(String, #[label("{0} doesn't support cell paths")] Span), IncompatiblePathAccess {
type_name: String,
#[label("{type_name} doesn't support cell paths")]
span: Span,
},
/// The requested column does not exist. /// The requested column does not exist.
/// ///
@ -508,11 +560,13 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Check the spelling of your column name. Did you forget to rename a column somewhere? /// Check the spelling of your column name. Did you forget to rename a column somewhere?
#[error("Cannot find column")] #[error("Cannot find column")]
#[diagnostic(code(nu::shell::column_not_found))] #[diagnostic(code(nu::shell::column_not_found))]
CantFindColumn( CantFindColumn {
String, col_name: String,
#[label = "cannot find column '{0}'"] Span, #[label = "cannot find column '{col_name}'"]
#[label = "value originates here"] Span, span: Span,
), #[label = "value originates here"]
src_span: Span,
},
/// Attempted to insert a column into a table, but a column with that name already exists. /// Attempted to insert a column into a table, but a column with that name already exists.
/// ///
@ -521,11 +575,13 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Drop or rename the existing column (check `rename -h`) and try again. /// Drop or rename the existing column (check `rename -h`) and try again.
#[error("Column already exists")] #[error("Column already exists")]
#[diagnostic(code(nu::shell::column_already_exists))] #[diagnostic(code(nu::shell::column_already_exists))]
ColumnAlreadyExists( ColumnAlreadyExists {
String, col_name: String,
#[label = "column '{0}' already exists"] Span, #[label = "column '{col_name}' already exists"]
#[label = "value originates here"] Span, span: Span,
), #[label = "value originates here"]
src_span: Span,
},
/// The given operation can only be performed on lists. /// The given operation can only be performed on lists.
/// ///
@ -534,10 +590,12 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// Check the input type to this command. Are you sure it's a list? /// Check the input type to this command. Are you sure it's a list?
#[error("Not a list value")] #[error("Not a list value")]
#[diagnostic(code(nu::shell::not_a_list))] #[diagnostic(code(nu::shell::not_a_list))]
NotAList( NotAList {
#[label = "value not a list"] Span, #[label = "value not a list"]
#[label = "value originates here"] Span, dst_span: Span,
), #[label = "value originates here"]
src_span: Span,
},
/// An error happened while performing an external command. /// An error happened while performing an external command.
/// ///
@ -545,8 +603,13 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
/// ///
/// This error is fairly generic. Refer to the specific error message for further details. /// This error is fairly generic. Refer to the specific error message for further details.
#[error("External command failed")] #[error("External command failed")]
#[diagnostic(code(nu::shell::external_command), help("{1}"))] #[diagnostic(code(nu::shell::external_command), help("{help}"))]
ExternalCommand(String, String, #[label("{0}")] Span), ExternalCommand {
label: String,
help: String,
#[label("{label}")]
span: Span,
},
/// An operation was attempted with an input unsupported for some reason. /// An operation was attempted with an input unsupported for some reason.
/// ///

View File

@ -27,17 +27,17 @@ pub trait CustomValue: fmt::Debug + Send + Sync {
// Follow cell path functions // Follow cell path functions
fn follow_path_int(&self, _count: usize, span: Span) -> Result<Value, ShellError> { fn follow_path_int(&self, _count: usize, span: Span) -> Result<Value, ShellError> {
Err(ShellError::IncompatiblePathAccess( Err(ShellError::IncompatiblePathAccess {
format!("{} doesn't support path access", self.value_string()), type_name: self.value_string(),
span, span,
)) })
} }
fn follow_path_string(&self, _column_name: String, span: Span) -> Result<Value, ShellError> { fn follow_path_string(&self, _column_name: String, span: Span) -> Result<Value, ShellError> {
Err(ShellError::IncompatiblePathAccess( Err(ShellError::IncompatiblePathAccess {
format!("{} doesn't support path access", self.value_string()), type_name: self.value_string(),
span, span,
)) })
} }
// ordering with other value // ordering with other value

View File

@ -4,12 +4,12 @@ impl Value {
pub fn as_f64(&self) -> Result<f64, ShellError> { pub fn as_f64(&self) -> Result<f64, ShellError> {
match self { match self {
Value::Float { val, .. } => Ok(*val), Value::Float { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"f64".into(), to_type: "f64".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
@ -18,12 +18,12 @@ impl Value {
Value::Int { val, .. } => Ok(*val), Value::Int { val, .. } => Ok(*val),
Value::Filesize { val, .. } => Ok(*val), Value::Filesize { val, .. } => Ok(*val),
Value::Duration { val, .. } => Ok(*val), Value::Duration { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"i64".into(), to_type: "i64".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
} }

View File

@ -34,12 +34,12 @@ impl FromValue for Spanned<i64> {
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"integer".into(), to_type: "integer".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -51,12 +51,12 @@ impl FromValue for i64 {
Value::Filesize { val, .. } => Ok(*val), Value::Filesize { val, .. } => Ok(*val),
Value::Duration { val, .. } => Ok(*val), Value::Duration { val, .. } => Ok(*val),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"integer".into(), to_type: "integer".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -73,12 +73,12 @@ impl FromValue for Spanned<f64> {
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"float".into(), to_type: "float".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -88,12 +88,12 @@ impl FromValue for f64 {
match v { match v {
Value::Float { val, .. } => Ok(*val), Value::Float { val, .. } => Ok(*val),
Value::Int { val, .. } => Ok(*val as f64), Value::Int { val, .. } => Ok(*val as f64),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"float".into(), to_type: "float".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -132,12 +132,12 @@ impl FromValue for Spanned<usize> {
} }
} }
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"non-negative integer".into(), to_type: "non-negative integer".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -167,12 +167,12 @@ impl FromValue for usize {
} }
} }
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"non-negative integer".into(), to_type: "non-negative integer".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -183,12 +183,12 @@ impl FromValue for String {
match v { match v {
Value::CellPath { val, .. } => Ok(val.into_string()), Value::CellPath { val, .. } => Ok(val.into_string()),
Value::String { val, .. } => Ok(val.clone()), Value::String { val, .. } => Ok(val.clone()),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -200,12 +200,12 @@ impl FromValue for Spanned<String> {
Value::CellPath { val, .. } => val.into_string(), Value::CellPath { val, .. } => val.into_string(),
Value::String { val, .. } => val.clone(), Value::String { val, .. } => val.clone(),
v => { v => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)) })
} }
}, },
span: v.span()?, span: v.span()?,
@ -221,20 +221,20 @@ impl FromValue for Vec<String> {
.iter() .iter()
.map(|val| match val { .map(|val| match val {
Value::String { val, .. } => Ok(val.clone()), Value::String { val, .. } => Ok(val.clone()),
c => Err(ShellError::CantConvert( c => Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
c.get_type().to_string(), from_type: c.get_type().to_string(),
c.span()?, span: c.span()?,
None, help: None,
)), }),
}) })
.collect::<Result<Vec<String>, ShellError>>(), .collect::<Result<Vec<String>, ShellError>>(),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -250,20 +250,20 @@ impl FromValue for Vec<Spanned<String>> {
item: val.clone(), item: val.clone(),
span: *span, span: *span,
}), }),
c => Err(ShellError::CantConvert( c => Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
c.get_type().to_string(), from_type: c.get_type().to_string(),
c.span()?, span: c.span()?,
None, help: None,
)), }),
}) })
.collect::<Result<Vec<Spanned<String>>, ShellError>>(), .collect::<Result<Vec<Spanned<String>>, ShellError>>(),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -275,20 +275,20 @@ impl FromValue for Vec<bool> {
.iter() .iter()
.map(|val| match val { .map(|val| match val {
Value::Bool { val, .. } => Ok(*val), Value::Bool { val, .. } => Ok(*val),
c => Err(ShellError::CantConvert( c => Err(ShellError::CantConvert {
"bool".into(), to_type: "bool".into(),
c.get_type().to_string(), from_type: c.get_type().to_string(),
c.span()?, span: c.span()?,
None, help: None,
)), }),
}) })
.collect::<Result<Vec<bool>, ShellError>>(), .collect::<Result<Vec<bool>, ShellError>>(),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"bool".into(), to_type: "bool".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -316,12 +316,12 @@ impl FromValue for CellPath {
}) })
} }
} }
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"cell path".into(), to_type: "cell path".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
span, span,
None, help: None,
)), }),
} }
} }
} }
@ -330,12 +330,12 @@ impl FromValue for bool {
fn from_value(v: &Value) -> Result<Self, ShellError> { fn from_value(v: &Value) -> Result<Self, ShellError> {
match v { match v {
Value::Bool { val, .. } => Ok(*val), Value::Bool { val, .. } => Ok(*val),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"bool".into(), to_type: "bool".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -347,12 +347,12 @@ impl FromValue for Spanned<bool> {
item: *val, item: *val,
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"bool".into(), to_type: "bool".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -361,12 +361,12 @@ impl FromValue for DateTime<FixedOffset> {
fn from_value(v: &Value) -> Result<Self, ShellError> { fn from_value(v: &Value) -> Result<Self, ShellError> {
match v { match v {
Value::Date { val, .. } => Ok(*val), Value::Date { val, .. } => Ok(*val),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"date".into(), to_type: "date".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -378,12 +378,12 @@ impl FromValue for Spanned<DateTime<FixedOffset>> {
item: *val, item: *val,
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"date".into(), to_type: "date".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -392,12 +392,12 @@ impl FromValue for Range {
fn from_value(v: &Value) -> Result<Self, ShellError> { fn from_value(v: &Value) -> Result<Self, ShellError> {
match v { match v {
Value::Range { val, .. } => Ok((**val).clone()), Value::Range { val, .. } => Ok((**val).clone()),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"range".into(), to_type: "range".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -409,12 +409,12 @@ impl FromValue for Spanned<Range> {
item: (**val).clone(), item: (**val).clone(),
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"range".into(), to_type: "range".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -424,12 +424,12 @@ impl FromValue for Vec<u8> {
match v { match v {
Value::Binary { val, .. } => Ok(val.clone()), Value::Binary { val, .. } => Ok(val.clone()),
Value::String { val, .. } => Ok(val.bytes().collect()), Value::String { val, .. } => Ok(val.bytes().collect()),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"binary data".into(), to_type: "binary data".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -445,12 +445,12 @@ impl FromValue for Spanned<Vec<u8>> {
item: val.bytes().collect(), item: val.bytes().collect(),
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"binary data".into(), to_type: "binary data".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -463,12 +463,12 @@ impl FromValue for Spanned<PathBuf> {
.map_err(|err| ShellError::FileNotFoundCustom(err.to_string(), *span))?, .map_err(|err| ShellError::FileNotFoundCustom(err.to_string(), *span))?,
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"range".into(), to_type: "range".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -478,12 +478,12 @@ impl FromValue for Vec<Value> {
// FIXME: we may want to fail a little nicer here // FIXME: we may want to fail a little nicer here
match v { match v {
Value::List { vals, .. } => Ok(vals.clone()), Value::List { vals, .. } => Ok(vals.clone()),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"Vector of values".into(), to_type: "Vector of values".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -493,12 +493,12 @@ impl FromValue for (Vec<String>, Vec<Value>) {
fn from_value(v: &Value) -> Result<Self, ShellError> { fn from_value(v: &Value) -> Result<Self, ShellError> {
match v { match v {
Value::Record { cols, vals, .. } => Ok((cols.clone(), vals.clone())), Value::Record { cols, vals, .. } => Ok((cols.clone(), vals.clone())),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"Record".into(), to_type: "Record".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -514,12 +514,12 @@ impl FromValue for Closure {
block_id: *val, block_id: *val,
captures: HashMap::new(), captures: HashMap::new(),
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"Closure".into(), to_type: "Closure".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -528,12 +528,12 @@ impl FromValue for Block {
fn from_value(v: &Value) -> Result<Self, ShellError> { fn from_value(v: &Value) -> Result<Self, ShellError> {
match v { match v {
Value::Block { val, .. } => Ok(Block { block_id: *val }), Value::Block { val, .. } => Ok(Block { block_id: *val }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"Block".into(), to_type: "Block".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }
@ -552,12 +552,12 @@ impl FromValue for Spanned<Closure> {
}, },
span: *span, span: *span,
}), }),
v => Err(ShellError::CantConvert( v => Err(ShellError::CantConvert {
"Closure".into(), to_type: "Closure".into(),
v.get_type().to_string(), from_type: v.get_type().to_string(),
v.span()?, span: v.span()?,
None, help: None,
)), }),
} }
} }
} }

View File

@ -197,21 +197,21 @@ impl Value {
Value::Binary { val, .. } => Ok(match std::str::from_utf8(val) { Value::Binary { val, .. } => Ok(match std::str::from_utf8(val) {
Ok(s) => s.to_string(), Ok(s) => s.to_string(),
Err(_) => { Err(_) => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
"binary".into(), from_type: "binary".into(),
self.span()?, span: self.span()?,
None, help: None,
)); });
} }
}), }),
Value::Date { val, .. } => Ok(val.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)), Value::Date { val, .. } => Ok(val.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
@ -227,32 +227,32 @@ impl Value {
span: *span, span: *span,
}, },
Err(_) => { Err(_) => {
return Err(ShellError::CantConvert( return Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
"binary".into(), from_type: "binary".into(),
self.span()?, span: self.span()?,
None, help: None,
)) })
} }
}), }),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"string".into(), to_type: "string".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
pub fn as_path(&self) -> Result<PathBuf, ShellError> { pub fn as_path(&self) -> Result<PathBuf, ShellError> {
match self { match self {
Value::String { val, .. } => Ok(PathBuf::from(val)), Value::String { val, .. } => Ok(PathBuf::from(val)),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"path".into(), to_type: "path".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
@ -260,12 +260,12 @@ impl Value {
match self { match self {
Value::Block { val, .. } => Ok(*val), Value::Block { val, .. } => Ok(*val),
Value::Closure { val, .. } => Ok(*val), Value::Closure { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"block".into(), to_type: "block".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
@ -273,48 +273,48 @@ impl Value {
match self { match self {
Value::Binary { val, .. } => Ok(val), Value::Binary { val, .. } => Ok(val),
Value::String { val, .. } => Ok(val.as_bytes()), Value::String { val, .. } => Ok(val.as_bytes()),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"binary".into(), to_type: "binary".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
pub fn as_record(&self) -> Result<(&[String], &[Value]), ShellError> { pub fn as_record(&self) -> Result<(&[String], &[Value]), ShellError> {
match self { match self {
Value::Record { cols, vals, .. } => Ok((cols, vals)), Value::Record { cols, vals, .. } => Ok((cols, vals)),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"record".into(), to_type: "record".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
pub fn as_list(&self) -> Result<&[Value], ShellError> { pub fn as_list(&self) -> Result<&[Value], ShellError> {
match self { match self {
Value::List { vals, .. } => Ok(vals), Value::List { vals, .. } => Ok(vals),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"list".into(), to_type: "list".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
pub fn as_bool(&self) -> Result<bool, ShellError> { pub fn as_bool(&self) -> Result<bool, ShellError> {
match self { match self {
Value::Bool { val, .. } => Ok(*val), Value::Bool { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"boolean".into(), to_type: "boolean".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
@ -322,24 +322,24 @@ impl Value {
match self { match self {
Value::Float { val, .. } => Ok(*val), Value::Float { val, .. } => Ok(*val),
Value::Int { val, .. } => Ok(*val as f64), Value::Int { val, .. } => Ok(*val as f64),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"float".into(), to_type: "float".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
pub fn as_integer(&self) -> Result<i64, ShellError> { pub fn as_integer(&self) -> Result<i64, ShellError> {
match self { match self {
Value::Int { val, .. } => Ok(*val), Value::Int { val, .. } => Ok(*val),
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"integer".into(), to_type: "integer".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
self.span()?, span: self.span()?,
None, help: None,
)), }),
} }
} }
@ -722,12 +722,15 @@ impl Value {
current = item.clone(); current = item.clone();
} else if val.is_empty() { } else if val.is_empty() {
err_or_null!( err_or_null!(
ShellError::AccessEmptyContent(*origin_span), ShellError::AccessEmptyContent { span: *origin_span },
*origin_span *origin_span
) )
} else { } else {
err_or_null!( err_or_null!(
ShellError::AccessBeyondEnd(val.len() - 1, *origin_span), ShellError::AccessBeyondEnd {
max_idx: val.len() - 1,
span: *origin_span
},
*origin_span *origin_span
); );
} }
@ -737,12 +740,15 @@ impl Value {
current = Value::int(*item as i64, *origin_span); current = Value::int(*item as i64, *origin_span);
} else if val.is_empty() { } else if val.is_empty() {
err_or_null!( err_or_null!(
ShellError::AccessEmptyContent(*origin_span), ShellError::AccessEmptyContent { span: *origin_span },
*origin_span *origin_span
) )
} else { } else {
err_or_null!( err_or_null!(
ShellError::AccessBeyondEnd(val.len() - 1, *origin_span), ShellError::AccessBeyondEnd {
max_idx: val.len() - 1,
span: *origin_span
},
*origin_span *origin_span
); );
} }
@ -752,7 +758,7 @@ impl Value {
current = item.clone(); current = item.clone();
} else { } else {
err_or_null!( err_or_null!(
ShellError::AccessBeyondEndOfStream(*origin_span), ShellError::AccessBeyondEndOfStream { span: *origin_span },
*origin_span *origin_span
); );
} }
@ -770,10 +776,10 @@ impl Value {
Value::Error { error } => return Err(error.to_owned()), Value::Error { error } => return Err(error.to_owned()),
x => { x => {
err_or_null!( err_or_null!(
ShellError::IncompatiblePathAccess( ShellError::IncompatiblePathAccess {
format!("{}", x.get_type()), type_name: format!("{}", x.get_type()),
*origin_span, span: *origin_span
), },
*origin_span *origin_span
) )
} }
@ -806,11 +812,11 @@ impl Value {
} }
} }
err_or_null!( err_or_null!(
ShellError::CantFindColumn( ShellError::CantFindColumn {
column_name.to_string(), col_name: column_name.to_string(),
*origin_span, span: *origin_span,
span, src_span: span
), },
*origin_span *origin_span
); );
} }
@ -830,11 +836,11 @@ impl Value {
} }
} }
err_or_null!( err_or_null!(
ShellError::CantFindColumn( ShellError::CantFindColumn {
column_name.to_string(), col_name: column_name.to_string(),
*origin_span, span: *origin_span,
*span, src_span: *span
), },
*origin_span *origin_span
); );
} }
@ -874,13 +880,11 @@ impl Value {
Value::nothing(*origin_span) Value::nothing(*origin_span)
} else { } else {
Value::Error { Value::Error {
error: ShellError::CantFindColumn( error: ShellError::CantFindColumn {
column_name.to_string(), col_name: column_name.to_string(),
*origin_span, span: *origin_span,
// Get the exact span of the value, falling back to src_span: val.span().unwrap_or(*span),
// the list's span if it's a Value::Empty },
val.span().unwrap_or(*span),
),
} }
}); });
} }
@ -890,13 +894,11 @@ impl Value {
Value::nothing(*origin_span) Value::nothing(*origin_span)
} else { } else {
Value::Error { Value::Error {
error: ShellError::CantFindColumn( error: ShellError::CantFindColumn {
column_name.to_string(), col_name: column_name.to_string(),
*origin_span, span: *origin_span,
// Get the exact span of the value, falling back to src_span: val.span().unwrap_or(*span),
// the list's span if it's a Value::Empty },
val.span().unwrap_or(*span),
),
} }
}); });
} }
@ -908,11 +910,11 @@ impl Value {
}; };
} else { } else {
err_or_null!( err_or_null!(
ShellError::CantFindColumn( ShellError::CantFindColumn {
column_name.to_string(), col_name: column_name.to_string(),
*origin_span, span: *origin_span,
*span, src_span: *span
), },
*origin_span *origin_span
); );
} }
@ -923,10 +925,10 @@ impl Value {
Value::Error { error } => err_or_null!(error.to_owned(), *origin_span), Value::Error { error } => err_or_null!(error.to_owned(), *origin_span),
x => { x => {
err_or_null!( err_or_null!(
ShellError::IncompatiblePathAccess( ShellError::IncompatiblePathAccess {
format!("{}", x.get_type()), type_name: format!("{}", x.get_type()),
*origin_span, span: *origin_span
), },
*origin_span *origin_span
) )
} }
@ -1005,11 +1007,11 @@ impl Value {
} }
Value::Error { error } => return Err(error.to_owned()), Value::Error { error } => return Err(error.to_owned()),
v => { v => {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)) })
} }
} }
} }
@ -1042,11 +1044,11 @@ impl Value {
} }
Value::Error { error } => return Err(error.to_owned()), Value::Error { error } => return Err(error.to_owned()),
v => { v => {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)) })
} }
}, },
PathMember::Int { val: row_num, span } => match self { PathMember::Int { val: row_num, span } => match self {
@ -1058,11 +1060,19 @@ impl Value {
// Otherwise, it's prohibited. // Otherwise, it's prohibited.
vals.push(new_val); vals.push(new_val);
} else { } else {
return Err(ShellError::InsertAfterNextFreeIndex(vals.len(), *span)); return Err(ShellError::InsertAfterNextFreeIndex {
available_idx: vals.len(),
span: *span,
});
} }
} }
Value::Error { error } => return Err(error.to_owned()), Value::Error { error } => return Err(error.to_owned()),
v => return Err(ShellError::NotAList(*span, v.span()?)), v => {
return Err(ShellError::NotAList {
dst_span: *span,
src_span: v.span()?,
})
}
}, },
}, },
None => { None => {
@ -1118,20 +1128,20 @@ impl Value {
} }
} }
if !found { if !found {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} }
} }
Value::Error { error } => return Err(error.to_owned()), Value::Error { error } => return Err(error.to_owned()),
v => { v => {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)) })
} }
} }
} }
@ -1152,20 +1162,20 @@ impl Value {
} }
} }
if !found { if !found {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} }
} }
Value::Error { error } => return Err(error.to_owned()), Value::Error { error } => return Err(error.to_owned()),
v => { v => {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)) })
} }
}, },
PathMember::Int { val: row_num, span } => match self { PathMember::Int { val: row_num, span } => match self {
@ -1173,13 +1183,21 @@ impl Value {
if let Some(v) = vals.get_mut(*row_num) { if let Some(v) = vals.get_mut(*row_num) {
v.update_data_at_cell_path(&cell_path[1..], new_val)? v.update_data_at_cell_path(&cell_path[1..], new_val)?
} else if vals.is_empty() { } else if vals.is_empty() {
return Err(ShellError::AccessEmptyContent(*span)); return Err(ShellError::AccessEmptyContent { span: *span });
} else { } else {
return Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)); return Err(ShellError::AccessBeyondEnd {
max_idx: vals.len() - 1,
span: *span,
});
} }
} }
Value::Error { error } => return Err(error.to_owned()), Value::Error { error } => return Err(error.to_owned()),
v => return Err(ShellError::NotAList(*span, v.span()?)), v => {
return Err(ShellError::NotAList {
dst_span: *span,
src_span: v.span()?,
})
}
}, },
}, },
None => { None => {
@ -1216,19 +1234,19 @@ impl Value {
} }
} }
if !found { if !found {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} }
} }
v => { v => {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)) })
} }
} }
} }
@ -1248,19 +1266,19 @@ impl Value {
} }
} }
if !found { if !found {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} }
Ok(()) Ok(())
} }
v => Err(ShellError::CantFindColumn( v => Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)), }),
}, },
PathMember::Int { val: row_num, span } => match self { PathMember::Int { val: row_num, span } => match self {
Value::List { vals, .. } => { Value::List { vals, .. } => {
@ -1268,12 +1286,18 @@ impl Value {
vals.remove(*row_num); vals.remove(*row_num);
Ok(()) Ok(())
} else if vals.is_empty() { } else if vals.is_empty() {
Err(ShellError::AccessEmptyContent(*span)) Err(ShellError::AccessEmptyContent { span: *span })
} else { } else {
Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)) Err(ShellError::AccessBeyondEnd {
max_idx: vals.len() - 1,
span: *span,
})
} }
} }
v => Err(ShellError::NotAList(*span, v.span()?)), v => Err(ShellError::NotAList {
dst_span: *span,
src_span: v.span()?,
}),
}, },
} }
} }
@ -1300,19 +1324,19 @@ impl Value {
} }
} }
if !found { if !found {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} }
} }
v => { v => {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)) })
} }
} }
} }
@ -1333,31 +1357,37 @@ impl Value {
} }
} }
if !found { if !found {
return Err(ShellError::CantFindColumn( return Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} }
Ok(()) Ok(())
} }
v => Err(ShellError::CantFindColumn( v => Err(ShellError::CantFindColumn {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
v.span()?, src_span: v.span()?,
)), }),
}, },
PathMember::Int { val: row_num, span } => match self { PathMember::Int { val: row_num, span } => match self {
Value::List { vals, .. } => { Value::List { vals, .. } => {
if let Some(v) = vals.get_mut(*row_num) { if let Some(v) = vals.get_mut(*row_num) {
v.remove_data_at_cell_path(&cell_path[1..]) v.remove_data_at_cell_path(&cell_path[1..])
} else if vals.is_empty() { } else if vals.is_empty() {
Err(ShellError::AccessEmptyContent(*span)) Err(ShellError::AccessEmptyContent { span: *span })
} else { } else {
Err(ShellError::AccessBeyondEnd(vals.len() - 1, *span)) Err(ShellError::AccessBeyondEnd {
max_idx: vals.len() - 1,
span: *span,
})
} }
} }
v => Err(ShellError::NotAList(*span, v.span()?)), v => Err(ShellError::NotAList {
dst_span: *span,
src_span: v.span()?,
}),
}, },
} }
} }
@ -1387,11 +1417,11 @@ impl Value {
for col in cols.iter().zip(vals.iter_mut()) { for col in cols.iter().zip(vals.iter_mut()) {
if col.0 == col_name { if col.0 == col_name {
if cell_path.len() == 1 { if cell_path.len() == 1 {
return Err(ShellError::ColumnAlreadyExists( return Err(ShellError::ColumnAlreadyExists {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} else { } else {
return col.1.insert_data_at_cell_path( return col.1.insert_data_at_cell_path(
&cell_path[1..], &cell_path[1..],
@ -1426,11 +1456,11 @@ impl Value {
for col in cols.iter().zip(vals.iter_mut()) { for col in cols.iter().zip(vals.iter_mut()) {
if col.0 == col_name { if col.0 == col_name {
if cell_path.len() == 1 { if cell_path.len() == 1 {
return Err(ShellError::ColumnAlreadyExists( return Err(ShellError::ColumnAlreadyExists {
col_name.to_string(), col_name: col_name.to_string(),
*span, span: *span,
*v_span, src_span: *v_span,
)); });
} else { } else {
return col.1.insert_data_at_cell_path( return col.1.insert_data_at_cell_path(
&cell_path[1..], &cell_path[1..],
@ -1462,10 +1492,18 @@ impl Value {
// Otherwise, it's prohibited. // Otherwise, it's prohibited.
vals.push(new_val); vals.push(new_val);
} else { } else {
return Err(ShellError::InsertAfterNextFreeIndex(vals.len(), *span)); return Err(ShellError::InsertAfterNextFreeIndex {
available_idx: vals.len(),
span: *span,
});
} }
} }
v => return Err(ShellError::NotAList(*span, v.span()?)), v => {
return Err(ShellError::NotAList {
dst_span: *span,
src_span: v.span()?,
})
}
}, },
}, },
None => { None => {
@ -2307,7 +2345,7 @@ impl Value {
}) })
} }
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2317,7 +2355,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -2327,7 +2365,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2337,7 +2375,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Filesize { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => { (Value::Filesize { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => {
@ -2354,7 +2392,7 @@ impl Value {
}) })
} }
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -2364,7 +2402,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2374,7 +2412,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { (Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => {
@ -2391,7 +2429,7 @@ impl Value {
}) })
} }
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -2401,7 +2439,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2411,7 +2449,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::CustomValue { val: lhs, span }, rhs) => { (Value::CustomValue { val: lhs, span }, rhs) => {
@ -2439,7 +2477,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2451,7 +2489,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -2463,7 +2501,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2475,7 +2513,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Filesize { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => { (Value::Filesize { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => {
@ -2487,7 +2525,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -2499,7 +2537,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2511,7 +2549,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { (Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => {
@ -2523,7 +2561,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -2535,7 +2573,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -2547,7 +2585,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::CustomValue { val: lhs, span }, rhs) => { (Value::CustomValue { val: lhs, span }, rhs) => {
@ -3082,7 +3120,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -3092,7 +3130,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
@ -3102,7 +3140,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => { (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
@ -3112,7 +3150,7 @@ impl Value {
span, span,
}) })
} else { } else {
Err(ShellError::DivisionByZero(op)) Err(ShellError::DivisionByZero { span: op })
} }
} }
(Value::CustomValue { val: lhs, span }, rhs) => { (Value::CustomValue { val: lhs, span }, rhs) => {

View File

@ -68,7 +68,7 @@ impl Range {
incr.eq(expr_span, &zero, expr_span), incr.eq(expr_span, &zero, expr_span),
Ok(Value::Bool { val: true, .. }) Ok(Value::Bool { val: true, .. })
) { ) {
return Err(ShellError::CannotCreateRange(expr_span)); return Err(ShellError::CannotCreateRange { span: expr_span });
} }
// If to > from, then incr > 0, otherwise we iterate forever // If to > from, then incr > 0, otherwise we iterate forever
@ -76,7 +76,7 @@ impl Range {
to.gt(operator.span, &from, expr_span)?, to.gt(operator.span, &from, expr_span)?,
incr.gt(operator.next_op_span, &zero, expr_span)?, incr.gt(operator.next_op_span, &zero, expr_span)?,
) { ) {
return Err(ShellError::CannotCreateRange(expr_span)); return Err(ShellError::CannotCreateRange { span: expr_span });
} }
// If to < from, then incr < 0, otherwise we iterate forever // If to < from, then incr < 0, otherwise we iterate forever
@ -84,7 +84,7 @@ impl Range {
to.lt(operator.span, &from, expr_span)?, to.lt(operator.span, &from, expr_span)?,
incr.lt(operator.next_op_span, &zero, expr_span)?, incr.lt(operator.next_op_span, &zero, expr_span)?,
) { ) {
return Err(ShellError::CannotCreateRange(expr_span)); return Err(ShellError::CannotCreateRange { span: expr_span });
} }
Ok(Range { Ok(Range {
@ -218,7 +218,7 @@ impl Iterator for RangeIterator {
} else { } else {
self.done = true; self.done = true;
return Some(Value::Error { return Some(Value::Error {
error: ShellError::CannotCreateRange(self.span), error: ShellError::CannotCreateRange { span: self.span },
}); });
}; };

View File

@ -26,20 +26,20 @@ impl CoolCustomValue {
if let Some(cool) = val.as_any().downcast_ref::<Self>() { if let Some(cool) = val.as_any().downcast_ref::<Self>() {
Ok(cool.clone()) Ok(cool.clone())
} else { } else {
Err(ShellError::CantConvert( Err(ShellError::CantConvert {
"cool".into(), to_type: "cool".into(),
"non-cool".into(), from_type: "non-cool".into(),
*span, span: *span,
None, help: None,
)) })
} }
} }
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"cool".into(), to_type: "cool".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }
} }

View File

@ -63,12 +63,12 @@ impl CustomValuePlugin {
return Ok(value.into_value(call.head)); return Ok(value.into_value(call.head));
} }
Err(ShellError::CantConvert( Err(ShellError::CantConvert {
"cool or second".into(), to_type: "cool or second".into(),
"non-cool and non-second".into(), from_type: "non-cool and non-second".into(),
call.head, span: call.head,
None, help: None,
) }
.into()) .into())
} }
} }

View File

@ -24,19 +24,19 @@ impl SecondCustomValue {
match value { match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() { Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Some(value) => Ok(value.clone()), Some(value) => Ok(value.clone()),
None => Err(ShellError::CantConvert( None => Err(ShellError::CantConvert {
"cool".into(), to_type: "cool".into(),
"non-cool".into(), from_type: "non-cool".into(),
*span, span: *span,
None, help: None,
)), }),
}, },
x => Err(ShellError::CantConvert( x => Err(ShellError::CantConvert {
"cool".into(), to_type: "cool".into(),
x.get_type().to_string(), from_type: x.get_type().to_string(),
x.span()?, span: x.span()?,
None, help: None,
)), }),
} }
} }
} }

View File

@ -145,8 +145,11 @@ fn from_eml(input: &Value, body_preview: usize, head: Span) -> Result<Value, Lab
let eml = EmlParser::from_string(value) let eml = EmlParser::from_string(value)
.with_body_preview(body_preview) .with_body_preview(body_preview)
.parse() .parse()
.map_err(|_| { .map_err(|_| ShellError::CantConvert {
ShellError::CantConvert("structured eml data".into(), "string".into(), head, None) to_type: "structured eml data".into(),
from_type: "string".into(),
span: head,
help: None,
})?; })?;
let mut collected = IndexMap::new(); let mut collected = IndexMap::new();