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())
} else {
Err(ShellError::NushellFailedSpanned(
"Missing Constant".to_string(),
"constant not added by the parser".to_string(),
call.head,
))
Err(ShellError::NushellFailedSpanned {
msg: "Missing Constant".to_string(),
label: "constant not added by the parser".to_string(),
span: call.head,
})
}
}

View File

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

View File

@ -100,9 +100,15 @@ You can also learn more at https://www.nushell.sh/book/"#;
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();
Err(ShellError::NotFound(span(&rest_spans)))
Err(ShellError::NotFound {
span: span(&rest_spans),
})
} else {
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 {
(cols, vals, span)
} else {
return Err(ShellError::NushellFailedSpanned(
"Expected record".to_string(),
format!("got {}", record.get_type()),
record.span()?,
));
return Err(ShellError::NushellFailedSpanned {
msg: "Expected record".to_string(),
label: format!("got {}", record.get_type()),
span: record.span()?,
});
};
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(), &[]) {
id
} else {
return Err(ShellError::ModuleNotFoundAtRuntime(
name,
span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
));
return Err(ShellError::ModuleNotFoundAtRuntime {
mod_name: name,
span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
});
};
let module = engine_state.get_module(module_id);

View File

@ -58,7 +58,10 @@ impl Command for HideEnv {
name.span,
));
} 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())
}
}
x => Err(ShellError::CantConvert(
"bool".into(),
x.get_type().to_string(),
result.span()?,
None,
)),
x => Err(ShellError::CantConvert {
to_type: "bool".into(),
from_type: x.get_type().to_string(),
span: result.span()?,
help: None,
}),
}
}

View File

@ -61,10 +61,10 @@ impl Command for OverlayHide {
};
if !stack.is_overlay_active(&overlay_name.item) {
return Err(ShellError::OverlayNotFoundAtRuntime(
overlay_name.item,
overlay_name.span,
));
return Err(ShellError::OverlayNotFoundAtRuntime {
overlay_name: overlay_name.item,
span: overlay_name.span,
});
}
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() {
match stack.get_env_var(engine_state, &name.item) {
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 {
module_id
} else {
return Err(ShellError::NushellFailedSpanned(
"Not an overlay".to_string(),
"requires an overlay (path or a string)".to_string(),
overlay_expr.span,
));
return Err(ShellError::NushellFailedSpanned {
msg: "Not an overlay".to_string(),
label: "requires an overlay (path or a string)".to_string(),
span: overlay_expr.span,
});
}
} else {
return Err(ShellError::NushellFailedSpanned(
"Missing positional".to_string(),
"missing required overlay".to_string(),
call.head,
));
return Err(ShellError::NushellFailedSpanned {
msg: "Missing positional".to_string(),
label: "missing required overlay".to_string(),
span: call.head,
});
};
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));
}
} else {
return Err(ShellError::OverlayNotFoundAtRuntime(
name_arg.item,
name_arg.span,
));
return Err(ShellError::OverlayNotFoundAtRuntime {
overlay_name: name_arg.item,
span: name_arg.span,
});
};
if let Some(module_id) = maybe_origin_module_id {

View File

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

View File

@ -204,11 +204,11 @@ fn run_histogram(
}
if inputs.is_empty() {
return Err(ShellError::CantFindColumn(
col_name.clone(),
head_span,
list_span,
));
return Err(ShellError::CantFindColumn {
col_name: col_name.clone(),
span: head_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>();
match val {
Ok(f) => Ok(f.abs() >= f64::EPSILON),
Err(_) => Err(ShellError::CantConvert(
"boolean".to_string(),
"string".to_string(),
Err(_) => Err(ShellError::CantConvert {
to_type: "boolean".to_string(),
from_type: "string".to_string(),
span,
Some(
help: Some(
r#"the strings "true" and "false" can be converted into a bool"#
.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 },
Err(reason) => {
Value::Error {
error: ShellError::CantConvert(
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())
),
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()) },
}
}
},

View File

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

View File

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

View File

@ -187,12 +187,12 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
Ok(v) => v,
_ => {
return Value::Error {
error: ShellError::CantConvert(
"float".to_string(),
"integer".to_string(),
error: ShellError::CantConvert {
to_type: "float".to_string(),
from_type: "integer".to_string(),
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),
Err(e) => {
return Value::Error {
error: ShellError::CantConvert(
"string".to_string(),
"int".to_string(),
head,
Some(e.to_string()),
),
error: ShellError::CantConvert {
to_type: "string".to_string(),
from_type: "int".to_string(),
span: head,
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) {
Ok(n) => Value::int(n, head),
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) {
Ok(n) => n,
Err(_reason) => {
return Err(ShellError::CantConvert(
"int".to_string(),
"string".to_string(),
return Err(ShellError::CantConvert {
to_type: "int".to_string(),
from_type: "string".to_string(),
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)
@ -331,15 +336,15 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
let num =
match i64::from_str_radix(h.trim_start_matches("0x"), 16) {
Ok(n) => n,
Err(_reason) => return Err(ShellError::CantConvert(
"int".to_string(),
"string".to_string(),
Err(_reason) => return Err(ShellError::CantConvert {
to_type: "int".to_string(),
from_type: "string".to_string(),
span,
Some(
help: Some(
r#"hexadecimal digits following "0x" should be in 0-9, a-f, or A-F"#
.to_string(),
),
)),
}),
};
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) {
Ok(n) => n,
Err(_reason) => {
return Err(ShellError::CantConvert(
"int".to_string(),
"string".to_string(),
return Err(ShellError::CantConvert {
to_type: "int".to_string(),
from_type: "string".to_string(),
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)
@ -361,14 +366,14 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
Ok(n) => Ok(n),
Err(_) => match a_string.parse::<f64>() {
Ok(f) => Ok(f as i64),
_ => Err(ShellError::CantConvert(
"int".to_string(),
"string".to_string(),
_ => Err(ShellError::CantConvert {
to_type: "int".to_string(),
from_type: "string".to_string(),
span,
Some(format!(
help: Some(format!(
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: _,
} => Value::Error {
// Watch out for CantConvert's argument order
error: ShellError::CantConvert(
"string".into(),
"record".into(),
error: ShellError::CantConvert {
to_type: "string".into(),
from_type: "record".into(),
span,
Some("try using the `to nuon` command".into()),
),
help: Some("try using the `to nuon` command".into()),
},
},
Value::Binary { .. } => Value::Error {
error: ShellError::CantConvert(
"string".into(),
"binary".into(),
error: ShellError::CantConvert {
to_type: "string".into(),
from_type: "binary".into(),
span,
Some("try using the `decode` command".into()),
),
help: Some("try using the `decode` command".into()),
},
},
x => Value::Error {
error: ShellError::CantConvert(
String::from("string"),
x.get_type().to_string(),
error: ShellError::CantConvert {
to_type: String::from("string"),
from_type: x.get_type().to_string(),
span,
None,
),
help: None,
},
},
}
}

View File

@ -62,19 +62,19 @@ impl SQLiteDatabase {
path: db.path.clone(),
ctrlc: db.ctrlc.clone(),
}),
None => Err(ShellError::CantConvert(
"database".into(),
"non-database".into(),
None => Err(ShellError::CantConvert {
to_type: "database".into(),
from_type: "non-database".into(),
span,
None,
)),
help: None,
}),
},
x => Err(ShellError::CantConvert(
"database".into(),
x.get_type().to_string(),
x.span()?,
None,
)),
x => Err(ShellError::CantConvert {
to_type: "database".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
help: None,
}),
}
}
@ -309,7 +309,7 @@ impl CustomValue for SQLiteDatabase {
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
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> {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -248,11 +248,11 @@ pub fn group(
};
match row.get_data_by_key(&column_name.item) {
Some(group_key) => Ok(group_key.as_string()?),
None => Err(ShellError::CantFindColumn(
column_name.item.to_string(),
column_name.span,
row.expect_span(),
)),
None => Err(ShellError::CantFindColumn {
col_name: column_name.item.to_string(),
span: column_name.span,
src_span: row.expect_span(),
}),
}
});
@ -263,9 +263,9 @@ pub fn group(
data_group(values, &Some(block), name)
}
Grouper::ByBlock => Err(ShellError::NushellFailed(
"Block not implemented: This should never happen.".into(),
)),
Grouper::ByBlock => Err(ShellError::NushellFailed {
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_vals.push(val.clone());
} else {
return Err(ShellError::NushellFailedSpanned(
"Error indexing input columns".to_string(),
"originates from here".to_string(),
return Err(ShellError::NushellFailedSpanned {
msg: "Error indexing input columns".to_string(),
label: "originates from here".to_string(),
span,
));
});
}
}
}
@ -276,11 +276,11 @@ fn move_record_columns(
out_cols.push(col.into());
out_vals.push(val.clone());
} else {
return Err(ShellError::NushellFailedSpanned(
"Error indexing input columns".to_string(),
"originates from here".to_string(),
return Err(ShellError::NushellFailedSpanned {
msg: "Error indexing input columns".to_string(),
label: "originates from here".to_string(),
span,
));
});
}
}

View File

@ -164,11 +164,11 @@ pub fn split(
Box::new(
move |_, row: &Value| match row.get_data_by_key(&column_name.item) {
Some(group_key) => Ok(group_key.as_string()?),
None => Err(ShellError::CantFindColumn(
column_name.item.to_string(),
column_name.span,
row.span().unwrap_or(column_name.span),
)),
None => Err(ShellError::CantFindColumn {
col_name: column_name.item.to_string(),
span: 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()) {
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() {
pre_elems.push(v);
} else if idx == 0 {
return Err(ShellError::AccessEmptyContent(*span));
return Err(ShellError::AccessEmptyContent { span: *span });
} 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() {
pre_elems.push(v);
} 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) => {
if *u > i64::MAX as u64 {
Value::Error {
error: ShellError::CantConvert(
"i64 sized integer".into(),
"value larger than i64".into(),
error: ShellError::CantConvert {
to_type: "i64 sized integer".into(),
from_type: "value larger than i64".into(),
span,
None,
),
help: None,
},
}
} else {
Value::Int {
@ -182,12 +182,12 @@ fn convert_string_to_value(string_input: String, span: Span) -> Result<Value, Sh
)],
))
}
x => Err(ShellError::CantConvert(
format!("structured json data ({x})"),
"string".into(),
x => Err(ShellError::CantConvert {
to_type: format!("structured json data ({x})"),
from_type: "string".into(),
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 {
Ok(value) => Ok(convert_toml_to_value(&value, span)),
Err(err) => Err(ShellError::CantConvert(
"structured toml data".into(),
"string".into(),
Err(err) => Err(ShellError::CantConvert {
to_type: "structured toml data".into(),
from_type: "string".into(),
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 {
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(
@ -174,12 +179,12 @@ pub fn to_delimited_data(
}
Ok(x)
}
Err(_) => Err(ShellError::CantConvert(
format_name.into(),
value.get_type().to_string(),
value.span().unwrap_or(span),
None,
)),
Err(_) => Err(ShellError::CantConvert {
to_type: format_name.into(),
from_type: value.get_type().to_string(),
span: value.span().unwrap_or(span),
help: None,
}),
}?;
Ok(Value::string(output, span).into_pipeline_data())
}

View File

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

View File

@ -118,7 +118,12 @@ fn toml_into_pipeline_data(
}
.into_pipeline_data()),
_ => 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()),
}

View File

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

View File

@ -111,7 +111,12 @@ fn to_yaml(input: PipelineData, head: Span) -> Result<PipelineData, ShellError>
}
.into_pipeline_data()),
_ => 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()),
}

View File

@ -241,12 +241,12 @@ pub fn request_add_custom_headers(
}
x => {
return Err(ShellError::CantConvert(
"string list or single row".into(),
x.get_type().to_string(),
headers.span().unwrap_or_else(|_| Span::new(0, 0)),
None,
));
return Err(ShellError::CantConvert {
to_type: "string list or single row".into(),
from_type: x.get_type().to_string(),
span: headers.span().unwrap_or_else(|_| Span::new(0, 0)),
help: None,
});
}
}
} else {
@ -260,12 +260,12 @@ pub fn request_add_custom_headers(
}
x => {
return Err(ShellError::CantConvert(
"string list or single row".into(),
x.get_type().to_string(),
headers.span().unwrap_or_else(|_| Span::new(0, 0)),
None,
));
return Err(ShellError::CantConvert {
to_type: "string list or single row".into(),
from_type: x.get_type().to_string(),
span: headers.span().unwrap_or_else(|_| Span::new(0, 0)),
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) {
Ok(s) => Ok(s),
_ => Err(ShellError::CantConvert(
"URL".into(),
value.get_type().to_string(),
head,
None,
)),
_ => Err(ShellError::CantConvert {
to_type: "URL".into(),
from_type: value.get_type().to_string(),
span: head,
help: None,
}),
}
}
// Propagate existing errors

View File

@ -128,7 +128,12 @@ fn relative_to(path: &Path, span: Span, args: &Arguments) -> Value {
match lhs.strip_prefix(&rhs) {
Ok(p) => Value::string(p.to_string_lossy(), span),
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);
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
.item
.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))
}

View File

@ -89,7 +89,7 @@ fn switch_shell(
let new_path = shells
.get(new_shell)
.ok_or(ShellError::NotFound(span))?
.ok_or(ShellError::NotFound { span })?
.to_owned();
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()) {
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

View File

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

View File

@ -291,7 +291,7 @@ fn heuristic_parse_file(
Err(ShellError::IOError("Can not read input".to_string()))
}
} 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()))
}
} 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()))
}
} else {
Err(ShellError::NotFound(call.head))
Err(ShellError::NotFound { span: call.head })
}
}

View File

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

View File

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

View File

@ -197,7 +197,7 @@ fn eval_external(
) -> Result<PipelineData, ShellError> {
let decl_id = engine_state
.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);
@ -260,12 +260,12 @@ pub fn eval_expression(
}),
Expr::ValueWithUnit(e, unit) => match eval_expression(engine_state, stack, e)? {
Value::Int { val, .. } => Ok(compute(val, unit.item, unit.span)),
x => Err(ShellError::CantConvert(
"unit value".into(),
x.get_type().to_string(),
e.span,
None,
)),
x => Err(ShellError::CantConvert {
to_type: "unit value".into(),
from_type: x.get_type().to_string(),
span: e.span,
help: None,
}),
},
Expr::Range(from, next, to, operator) => {
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)?;
if is_env {
if cell_path.tail.is_empty() {
return Err(ShellError::CannotReplaceEnv(
cell_path.head.span,
));
return Err(ShellError::CannotReplaceEnv {
span: cell_path.head.span,
});
}
// 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)?,
};
if failed_to_run {
Err(ShellError::ExternalCommand(
"External command failed".to_string(),
stderr_msg,
Err(ShellError::ExternalCommand {
label: "External command failed".to_string(),
help: stderr_msg,
span,
))
})
} else {
// we've captured stderr message, but it's running success.
// 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 decl_id = engine_state
.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);
@ -54,11 +54,11 @@ impl Command for KnownExternal {
let extern_name = if let Some(name_bytes) = engine_state.find_decl_name(call.decl_id, &[]) {
String::from_utf8_lossy(name_bytes)
} else {
return Err(ShellError::NushellFailedSpanned(
"known external name not found".to_string(),
"could not find name for this command".to_string(),
call.head,
));
return Err(ShellError::NushellFailedSpanned {
msg: "known external name not found".to_string(),
label: "could not find name for this command".to_string(),
span: call.head,
});
};
let extern_name: Vec<_> = extern_name.split(' ').collect();

View File

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

View File

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

View File

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

View File

@ -108,7 +108,7 @@ impl Stack {
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> {
@ -116,7 +116,7 @@ impl Stack {
return Ok(v.clone());
}
Err(ShellError::VariableNotFoundAtRuntime(span))
Err(ShellError::VariableNotFoundAtRuntime { span })
}
pub fn add_var(&mut self, var_id: VarId, value: Value) {
@ -152,7 +152,9 @@ impl Stack {
self.active_overlays
.last()
.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 {

View File

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

View File

@ -226,15 +226,6 @@ pub enum ShellError {
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.
///
/// ## Resolution
@ -242,8 +233,12 @@ pub enum ShellError {
/// Make sure there's an appropriate `run-external` declaration for this external command.
#[error("Running external commands not supported")]
#[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.
///
/// ## Resolution
@ -251,7 +246,10 @@ pub enum ShellError {
/// Make sure the probability is between 0 and 1 and try again.
#[error("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.
///
@ -272,40 +270,47 @@ pub enum ShellError {
/// ## 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))]
#[error("Nushell failed: {msg}.")]
#[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
NushellFailed(String),
NushellFailed { msg: String },
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
///
/// ## 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))]
#[error("Nushell failed: {msg}.")]
#[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
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.
///
/// ## 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}.")]
#[error("Nushell failed: {msg}.")]
#[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
NushellFailedHelp(String, #[help] String),
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
///
/// ## 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),
NushellFailedHelp {
msg: String,
#[help]
help: String,
},
/// 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?
#[error("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.
///
/// ## Resolution
///
/// 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))]
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.
///
/// ## Resolution
///
/// 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))]
ModuleNotFoundAtRuntime(String, #[label = "module not found"] Span),
/// A referenced module or overlay was not found at runtime.
///
/// ## 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),
ModuleNotFoundAtRuntime {
mod_name: String,
#[label = "module not found"]
span: Span,
},
/// A referenced overlay was not found at runtime.
///
/// ## Resolution
///
/// 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))]
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.
///
@ -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.
#[error("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.
///
/// ## Resolution
///
/// 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))]
CantConvert(
String,
String,
#[label("can't convert {1} to {0}")] Span,
#[help] Option<String>,
),
CantConvert {
to_type: String,
from_type: String,
#[label("can't convert {from_type} to {to_type}")]
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.
///
/// ## Resolution
///
/// 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))]
CantConvertWithValue(
String,
String,
String,
#[label("can't be converted to {0}")] Span,
#[label("this {1} value...")] Span,
#[help] Option<String>,
),
CantConvertWithValue {
to_type: String,
from_type: String,
details: String,
#[label("can't be converted to {to_type}")]
dst_span: Span,
#[label("this {from_type} value...")]
src_span: Span,
#[help]
help: Option<String>,
},
/// An environment variable cannot be represented as a string.
///
/// ## Resolution
///
/// 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(
code(nu::shell::env_var_not_a_string),
help(
r#"The '{0}' 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."#
)
)]
EnvVarNotAString(String, #[label("value not representable as a string")] Span),
code(nu::shell::env_var_not_a_string),
help(
r#"The '{envvar_name}' environment variable must be a string or be convertible to a string.
Either make sure '{envvar_name}' is a string, or add a 'to_string' entry for it in ENV_CONVERSIONS."#
)
)]
EnvVarNotAString {
envvar_name: String,
#[label("value not representable as a string")]
span: Span,
},
/// This environment variable cannot be set manually.
///
/// ## Resolution
///
/// 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(
code(nu::shell::automatic_env_var_set_manually),
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
///
@ -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.")]
#[diagnostic(
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.
///
@ -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.
#[error("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.
///
@ -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.
#[error("Can't convert range to countable values")]
#[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.
///
/// ## Resolution
///
/// 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))]
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.
///
/// ## Resolution
///
/// 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))]
InsertAfterNextFreeIndex(
usize,
#[label = "can't insert at index (the next available index is {0})"] Span,
),
InsertAfterNextFreeIndex {
available_idx: usize,
#[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.
///
@ -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.
#[error("Row number too large (empty content).")]
#[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.
///
/// ## 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.
#[error("Row number too large.")]
#[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.
///
@ -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.
#[error("Data cannot be accessed with a cell path")]
#[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.
///
@ -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?
#[error("Cannot find column")]
#[diagnostic(code(nu::shell::column_not_found))]
CantFindColumn(
String,
#[label = "cannot find column '{0}'"] Span,
#[label = "value originates here"] Span,
),
CantFindColumn {
col_name: String,
#[label = "cannot find column '{col_name}'"]
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.
///
@ -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.
#[error("Column already exists")]
#[diagnostic(code(nu::shell::column_already_exists))]
ColumnAlreadyExists(
String,
#[label = "column '{0}' already exists"] Span,
#[label = "value originates here"] Span,
),
ColumnAlreadyExists {
col_name: String,
#[label = "column '{col_name}' already exists"]
span: Span,
#[label = "value originates here"]
src_span: Span,
},
/// 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?
#[error("Not a list value")]
#[diagnostic(code(nu::shell::not_a_list))]
NotAList(
#[label = "value not a list"] Span,
#[label = "value originates here"] Span,
),
NotAList {
#[label = "value not a list"]
dst_span: Span,
#[label = "value originates here"]
src_span: Span,
},
/// 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.
#[error("External command failed")]
#[diagnostic(code(nu::shell::external_command), help("{1}"))]
ExternalCommand(String, String, #[label("{0}")] Span),
#[diagnostic(code(nu::shell::external_command), help("{help}"))]
ExternalCommand {
label: String,
help: String,
#[label("{label}")]
span: Span,
},
/// 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
fn follow_path_int(&self, _count: usize, span: Span) -> Result<Value, ShellError> {
Err(ShellError::IncompatiblePathAccess(
format!("{} doesn't support path access", self.value_string()),
Err(ShellError::IncompatiblePathAccess {
type_name: self.value_string(),
span,
))
})
}
fn follow_path_string(&self, _column_name: String, span: Span) -> Result<Value, ShellError> {
Err(ShellError::IncompatiblePathAccess(
format!("{} doesn't support path access", self.value_string()),
Err(ShellError::IncompatiblePathAccess {
type_name: self.value_string(),
span,
))
})
}
// ordering with other value

View File

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

View File

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

View File

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

View File

@ -68,7 +68,7 @@ impl Range {
incr.eq(expr_span, &zero, expr_span),
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
@ -76,7 +76,7 @@ impl Range {
to.gt(operator.span, &from, 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
@ -84,7 +84,7 @@ impl Range {
to.lt(operator.span, &from, 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 {
@ -218,7 +218,7 @@ impl Iterator for RangeIterator {
} else {
self.done = true;
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>() {
Ok(cool.clone())
} else {
Err(ShellError::CantConvert(
"cool".into(),
"non-cool".into(),
*span,
None,
))
Err(ShellError::CantConvert {
to_type: "cool".into(),
from_type: "non-cool".into(),
span: *span,
help: None,
})
}
}
x => Err(ShellError::CantConvert(
"cool".into(),
x.get_type().to_string(),
x.span()?,
None,
)),
x => Err(ShellError::CantConvert {
to_type: "cool".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
help: None,
}),
}
}
}

View File

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

View File

@ -24,19 +24,19 @@ impl SecondCustomValue {
match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Some(value) => Ok(value.clone()),
None => Err(ShellError::CantConvert(
"cool".into(),
"non-cool".into(),
*span,
None,
)),
None => Err(ShellError::CantConvert {
to_type: "cool".into(),
from_type: "non-cool".into(),
span: *span,
help: None,
}),
},
x => Err(ShellError::CantConvert(
"cool".into(),
x.get_type().to_string(),
x.span()?,
None,
)),
x => Err(ShellError::CantConvert {
to_type: "cool".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
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)
.with_body_preview(body_preview)
.parse()
.map_err(|_| {
ShellError::CantConvert("structured eml data".into(), "string".into(), head, None)
.map_err(|_| ShellError::CantConvert {
to_type: "structured eml data".into(),
from_type: "string".into(),
span: head,
help: None,
})?;
let mut collected = IndexMap::new();