mirror of
https://github.com/nushell/nushell.git
synced 2025-08-12 22:07:55 +02:00
Move Value to helpers, separate span call (#10121)
# Description As part of the refactor to split spans off of Value, this moves to using helper functions to create values, and using `.span()` instead of matching span out of Value directly. Hoping to get a few more helping hands to finish this, as there are a lot of commands to update :) # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --> --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: WindSoilder <windsoilder@outlook.com>
This commit is contained in:
@ -32,16 +32,16 @@ impl Command for From {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&From.signature(),
|
||||
&From.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -81,16 +81,16 @@ impl Command for FromCsv {
|
||||
Example {
|
||||
description: "Convert comma-separated data to a table",
|
||||
example: "\"ColA,ColB\n1,2\" | from csv",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list (
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["ColA".to_string(), "ColB".to_string()],
|
||||
vals: vec![
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
})
|
||||
Span::test_data(),
|
||||
))
|
||||
},
|
||||
Example {
|
||||
description: "Convert comma-separated data to a table, ignoring headers",
|
||||
|
@ -38,22 +38,16 @@ fn from_delimited_string_to_value(
|
||||
let mut output_row = vec![];
|
||||
for value in row?.iter() {
|
||||
if no_infer {
|
||||
output_row.push(Value::String {
|
||||
span,
|
||||
val: value.into(),
|
||||
});
|
||||
output_row.push(Value::string(value.to_string(), span));
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(i) = value.parse::<i64>() {
|
||||
output_row.push(Value::Int { val: i, span });
|
||||
output_row.push(Value::int(i, span));
|
||||
} else if let Ok(f) = value.parse::<f64>() {
|
||||
output_row.push(Value::Float { val: f, span });
|
||||
output_row.push(Value::float(f, span));
|
||||
} else {
|
||||
output_row.push(Value::String {
|
||||
val: value.into(),
|
||||
span,
|
||||
});
|
||||
output_row.push(Value::string(value.to_string(), span));
|
||||
}
|
||||
}
|
||||
rows.push(Value::record(
|
||||
@ -65,7 +59,7 @@ fn from_delimited_string_to_value(
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Value::List { vals: rows, span })
|
||||
Ok(Value::list(rows, span))
|
||||
}
|
||||
|
||||
pub(super) struct DelimitedReaderConfig {
|
||||
@ -96,7 +90,11 @@ pub(super) fn from_delimited_data(
|
||||
|
||||
pub fn trim_from_str(trim: Option<Value>) -> Result<Trim, ShellError> {
|
||||
match trim {
|
||||
Some(Value::String { val: item, span }) => match item.as_str() {
|
||||
Some(v) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::String {val: item, ..} => match item.as_str() {
|
||||
|
||||
"all" => Ok(Trim::All),
|
||||
"headers" => Ok(Trim::Headers),
|
||||
"fields" => Ok(Trim::Fields),
|
||||
@ -107,7 +105,10 @@ pub fn trim_from_str(trim: Option<Value>) -> Result<Trim, ShellError> {
|
||||
.into(),
|
||||
span,
|
||||
}),
|
||||
},
|
||||
}
|
||||
_ => Ok(Trim::None),
|
||||
}
|
||||
}
|
||||
_ => Ok(Trim::None),
|
||||
}
|
||||
}
|
||||
|
@ -41,10 +41,10 @@ impl Command for FromJson {
|
||||
cols: vec!["a".to_string(), "b".to_string()],
|
||||
vals: vec![
|
||||
Value::test_int(1),
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -75,10 +75,7 @@ impl Command for FromJson {
|
||||
} else {
|
||||
match convert_string_to_value(x.to_string(), span) {
|
||||
Ok(v) => Some(v),
|
||||
Err(error) => Some(Value::Error {
|
||||
error: Box::new(error),
|
||||
span,
|
||||
}),
|
||||
Err(error) => Some(Value::error(error, span)),
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -100,12 +97,12 @@ fn convert_nujson_to_value(value: &nu_json::Value, span: Span) -> Value {
|
||||
.map(|x| convert_nujson_to_value(x, span))
|
||||
.collect();
|
||||
|
||||
Value::List { vals: v, span }
|
||||
Value::list(v, span)
|
||||
}
|
||||
nu_json::Value::Bool(b) => Value::Bool { val: *b, span },
|
||||
nu_json::Value::F64(f) => Value::Float { val: *f, span },
|
||||
nu_json::Value::I64(i) => Value::Int { val: *i, span },
|
||||
nu_json::Value::Null => Value::Nothing { span },
|
||||
nu_json::Value::Bool(b) => Value::bool(*b, span),
|
||||
nu_json::Value::F64(f) => Value::float(*f, span),
|
||||
nu_json::Value::I64(i) => Value::int(*i, span),
|
||||
nu_json::Value::Null => Value::nothing(span),
|
||||
nu_json::Value::Object(k) => Value::record(
|
||||
k.iter()
|
||||
.map(|(k, v)| (k.clone(), convert_nujson_to_value(v, span)))
|
||||
@ -114,26 +111,20 @@ 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: Box::new(ShellError::CantConvert {
|
||||
Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "i64 sized integer".into(),
|
||||
from_type: "value larger than i64".into(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Value::Int {
|
||||
val: *u as i64,
|
||||
span,
|
||||
}
|
||||
Value::int(*u as i64, span)
|
||||
}
|
||||
}
|
||||
nu_json::Value::String(s) => Value::String {
|
||||
val: s.clone(),
|
||||
span,
|
||||
},
|
||||
nu_json::Value::String(s) => Value::string(s.clone(), span),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,10 @@ impl Command for FromNuon {
|
||||
cols: vec!["a".to_string(), "b".to_string()],
|
||||
vals: vec![
|
||||
Value::test_int(1),
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -206,8 +206,8 @@ fn convert_to_value(
|
||||
"closures not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::Binary(val) => Ok(Value::Binary { val, span }),
|
||||
Expr::Bool(val) => Ok(Value::Bool { val, span }),
|
||||
Expr::Binary(val) => Ok(Value::binary(val, span)),
|
||||
Expr::Bool(val) => Ok(Value::bool(val, span)),
|
||||
Expr::Call(..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"Error when loading".into(),
|
||||
@ -220,16 +220,16 @@ fn convert_to_value(
|
||||
"subexpressions and cellpaths not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::DateTime(dt) => Ok(Value::Date { val: dt, span }),
|
||||
Expr::DateTime(dt) => Ok(Value::date(dt, span)),
|
||||
Expr::ExternalCall(..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"Error when loading".into(),
|
||||
"calls not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::Filepath(val) => Ok(Value::String { val, span }),
|
||||
Expr::Directory(val) => Ok(Value::String { val, span }),
|
||||
Expr::Float(val) => Ok(Value::Float { val, span }),
|
||||
Expr::Filepath(val) => Ok(Value::string(val, span)),
|
||||
Expr::Directory(val) => Ok(Value::string(val, span)),
|
||||
Expr::Float(val) => Ok(Value::float(val, span)),
|
||||
Expr::FullCellPath(full_cell_path) => {
|
||||
if !full_cell_path.tail.is_empty() {
|
||||
Err(ShellError::OutsideSpannedLabeledError(
|
||||
@ -255,7 +255,7 @@ fn convert_to_value(
|
||||
"extra tokens in input file".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::GlobPattern(val) => Ok(Value::String { val, span }),
|
||||
Expr::GlobPattern(val) => Ok(Value::string(val, span)),
|
||||
Expr::ImportPattern(..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"Error when loading".into(),
|
||||
@ -268,7 +268,7 @@ fn convert_to_value(
|
||||
"overlays not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::Int(val) => Ok(Value::Int { val, span }),
|
||||
Expr::Int(val) => Ok(Value::int(val, span)),
|
||||
Expr::Keyword(kw, ..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"Error when loading".into(),
|
||||
@ -281,7 +281,7 @@ fn convert_to_value(
|
||||
output.push(convert_to_value(val, span, original_text)?);
|
||||
}
|
||||
|
||||
Ok(Value::List { vals: output, span })
|
||||
Ok(Value::list(output, span))
|
||||
}
|
||||
Expr::MatchBlock(..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
@ -289,7 +289,7 @@ fn convert_to_value(
|
||||
"match blocks not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::Nothing => Ok(Value::Nothing { span }),
|
||||
Expr::Nothing => Ok(Value::nothing(span)),
|
||||
Expr::Operator(..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"Error when loading".into(),
|
||||
@ -300,25 +300,25 @@ fn convert_to_value(
|
||||
let from = if let Some(f) = from {
|
||||
convert_to_value(*f, span, original_text)?
|
||||
} else {
|
||||
Value::Nothing { span: expr.span }
|
||||
Value::nothing(expr.span)
|
||||
};
|
||||
|
||||
let next = if let Some(s) = next {
|
||||
convert_to_value(*s, span, original_text)?
|
||||
} else {
|
||||
Value::Nothing { span: expr.span }
|
||||
Value::nothing(expr.span)
|
||||
};
|
||||
|
||||
let to = if let Some(t) = to {
|
||||
convert_to_value(*t, span, original_text)?
|
||||
} else {
|
||||
Value::Nothing { span: expr.span }
|
||||
Value::nothing(expr.span)
|
||||
};
|
||||
|
||||
Ok(Value::Range {
|
||||
val: Box::new(Range::new(expr.span, from, next, to, &operator)?),
|
||||
span: expr.span,
|
||||
})
|
||||
Ok(Value::range(
|
||||
Range::new(expr.span, from, next, to, &operator)?,
|
||||
expr.span,
|
||||
))
|
||||
}
|
||||
Expr::Record(key_vals) => {
|
||||
let mut record = Record::new();
|
||||
@ -355,7 +355,7 @@ fn convert_to_value(
|
||||
"signatures not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::String(s) => Ok(Value::String { val: s, span }),
|
||||
Expr::String(s) => Ok(Value::string(s, span)),
|
||||
Expr::StringInterpolation(..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"Error when loading".into(),
|
||||
@ -414,7 +414,7 @@ fn convert_to_value(
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Value::List { vals: output, span })
|
||||
Ok(Value::list(output, span))
|
||||
}
|
||||
Expr::ValueWithUnit(val, unit) => {
|
||||
let size = match val.expr {
|
||||
@ -430,80 +430,41 @@ fn convert_to_value(
|
||||
};
|
||||
|
||||
match unit.item {
|
||||
Unit::Byte => Ok(Value::Filesize { val: size, span }),
|
||||
Unit::Kilobyte => Ok(Value::Filesize {
|
||||
val: size * 1000,
|
||||
Unit::Byte => Ok(Value::filesize(size, span)),
|
||||
Unit::Kilobyte => Ok(Value::filesize(size * 1000, span)),
|
||||
Unit::Megabyte => Ok(Value::filesize(size * 1000 * 1000, span)),
|
||||
Unit::Gigabyte => Ok(Value::filesize(size * 1000 * 1000 * 1000, span)),
|
||||
Unit::Terabyte => Ok(Value::filesize(size * 1000 * 1000 * 1000 * 1000, span)),
|
||||
Unit::Petabyte => Ok(Value::filesize(
|
||||
size * 1000 * 1000 * 1000 * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Megabyte => Ok(Value::Filesize {
|
||||
val: size * 1000 * 1000,
|
||||
)),
|
||||
Unit::Exabyte => Ok(Value::filesize(
|
||||
size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Gigabyte => Ok(Value::Filesize {
|
||||
val: size * 1000 * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Terabyte => Ok(Value::Filesize {
|
||||
val: size * 1000 * 1000 * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Petabyte => Ok(Value::Filesize {
|
||||
val: size * 1000 * 1000 * 1000 * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Exabyte => Ok(Value::Filesize {
|
||||
val: size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
|
||||
Unit::Kibibyte => Ok(Value::Filesize {
|
||||
val: size * 1024,
|
||||
Unit::Kibibyte => Ok(Value::filesize(size * 1024, span)),
|
||||
Unit::Mebibyte => Ok(Value::filesize(size * 1024 * 1024, span)),
|
||||
Unit::Gibibyte => Ok(Value::filesize(size * 1024 * 1024 * 1024, span)),
|
||||
Unit::Tebibyte => Ok(Value::filesize(size * 1024 * 1024 * 1024 * 1024, span)),
|
||||
Unit::Pebibyte => Ok(Value::filesize(
|
||||
size * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
span,
|
||||
}),
|
||||
Unit::Mebibyte => Ok(Value::Filesize {
|
||||
val: size * 1024 * 1024,
|
||||
)),
|
||||
Unit::Exbibyte => Ok(Value::filesize(
|
||||
size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
span,
|
||||
}),
|
||||
Unit::Gibibyte => Ok(Value::Filesize {
|
||||
val: size * 1024 * 1024 * 1024,
|
||||
span,
|
||||
}),
|
||||
Unit::Tebibyte => Ok(Value::Filesize {
|
||||
val: size * 1024 * 1024 * 1024 * 1024,
|
||||
span,
|
||||
}),
|
||||
Unit::Pebibyte => Ok(Value::Filesize {
|
||||
val: size * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
span,
|
||||
}),
|
||||
Unit::Exbibyte => Ok(Value::Filesize {
|
||||
val: size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
|
||||
Unit::Nanosecond => Ok(Value::Duration { val: size, span }),
|
||||
Unit::Microsecond => Ok(Value::Duration {
|
||||
val: size * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Millisecond => Ok(Value::Duration {
|
||||
val: size * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Second => Ok(Value::Duration {
|
||||
val: size * 1000 * 1000 * 1000,
|
||||
span,
|
||||
}),
|
||||
Unit::Minute => Ok(Value::Duration {
|
||||
val: size * 1000 * 1000 * 1000 * 60,
|
||||
span,
|
||||
}),
|
||||
Unit::Hour => Ok(Value::Duration {
|
||||
val: size * 1000 * 1000 * 1000 * 60 * 60,
|
||||
span,
|
||||
}),
|
||||
Unit::Nanosecond => Ok(Value::duration(size, span)),
|
||||
Unit::Microsecond => Ok(Value::duration(size * 1000, span)),
|
||||
Unit::Millisecond => Ok(Value::duration(size * 1000 * 1000, span)),
|
||||
Unit::Second => Ok(Value::duration(size * 1000 * 1000 * 1000, span)),
|
||||
Unit::Minute => Ok(Value::duration(size * 1000 * 1000 * 1000 * 60, span)),
|
||||
Unit::Hour => Ok(Value::duration(size * 1000 * 1000 * 1000 * 60 * 60, span)),
|
||||
Unit::Day => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24) {
|
||||
Some(val) => Ok(Value::Duration { val, span }),
|
||||
Some(val) => Ok(Value::duration(val, span)),
|
||||
None => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"day duration too large".into(),
|
||||
@ -513,7 +474,7 @@ fn convert_to_value(
|
||||
},
|
||||
|
||||
Unit::Week => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24 * 7) {
|
||||
Some(val) => Ok(Value::Duration { val, span }),
|
||||
Some(val) => Ok(Value::duration(val, span)),
|
||||
None => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"week duration too large".into(),
|
||||
|
@ -158,13 +158,7 @@ fn from_ods(
|
||||
sheet_output.push(Value::record(record, head));
|
||||
}
|
||||
|
||||
dict.insert(
|
||||
sheet_name,
|
||||
Value::List {
|
||||
vals: sheet_output,
|
||||
span: head,
|
||||
},
|
||||
);
|
||||
dict.insert(sheet_name, Value::list(sheet_output, head));
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
"Could not load sheet".to_string(),
|
||||
|
@ -44,20 +44,20 @@ impl Command for FromSsv {
|
||||
example: r#"'FOO BAR
|
||||
1 2' | from ssv"#,
|
||||
description: "Converts ssv formatted string to table",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["FOO".to_string(), "BAR".to_string()],
|
||||
vals: vec![Value::test_string("1"), Value::test_string("2")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}, Example {
|
||||
example: r#"'FOO BAR
|
||||
1 2' | from ssv -n"#,
|
||||
description: "Converts ssv formatted string to table but not treating the first row as column names",
|
||||
result: Some(
|
||||
Value::List {
|
||||
vals: vec![
|
||||
Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["column1".to_string(), "column2".to_string()],
|
||||
vals: vec![Value::test_string("FOO"), Value::test_string("BAR")],
|
||||
@ -67,8 +67,8 @@ impl Command for FromSsv {
|
||||
vals: vec![Value::test_string("1"), Value::test_string("2")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}
|
||||
Span::test_data(),
|
||||
)
|
||||
),
|
||||
}]
|
||||
}
|
||||
@ -280,7 +280,7 @@ fn from_ssv_string_to_value(
|
||||
})
|
||||
.collect();
|
||||
|
||||
Value::List { vals: rows, span }
|
||||
Value::list(rows, span)
|
||||
}
|
||||
|
||||
fn from_ssv(
|
||||
|
@ -41,10 +41,10 @@ b = [1, 2]' | from toml",
|
||||
cols: vec!["a".to_string(), "b".to_string()],
|
||||
vals: vec![
|
||||
Value::test_int(1),
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -73,25 +73,19 @@ fn convert_toml_to_value(value: &toml::Value, span: Span) -> Value {
|
||||
.map(|x| convert_toml_to_value(x, span))
|
||||
.collect();
|
||||
|
||||
Value::List { vals: v, span }
|
||||
Value::list(v, span)
|
||||
}
|
||||
toml::Value::Boolean(b) => Value::Bool { val: *b, span },
|
||||
toml::Value::Float(f) => Value::Float { val: *f, span },
|
||||
toml::Value::Integer(i) => Value::Int { val: *i, span },
|
||||
toml::Value::Boolean(b) => Value::bool(*b, span),
|
||||
toml::Value::Float(f) => Value::float(*f, span),
|
||||
toml::Value::Integer(i) => Value::int(*i, span),
|
||||
toml::Value::Table(k) => Value::record(
|
||||
k.iter()
|
||||
.map(|(k, v)| (k.clone(), convert_toml_to_value(v, span)))
|
||||
.collect(),
|
||||
span,
|
||||
),
|
||||
toml::Value::String(s) => Value::String {
|
||||
val: s.clone(),
|
||||
span,
|
||||
},
|
||||
toml::Value::Datetime(d) => Value::String {
|
||||
val: d.to_string(),
|
||||
span,
|
||||
},
|
||||
toml::Value::String(s) => Value::string(s.clone(), span),
|
||||
toml::Value::Datetime(d) => Value::string(d.to_string(), span),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,16 +75,16 @@ impl Command for FromTsv {
|
||||
Example {
|
||||
description: "Convert tab-separated data to a table",
|
||||
example: "\"ColA\tColB\n1\t2\" | from tsv",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list (
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["ColA".to_string(), "ColB".to_string()],
|
||||
vals: vec![
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
})
|
||||
Span::test_data(),
|
||||
))
|
||||
},
|
||||
Example {
|
||||
description: "Create a tsv file with header columns and open it",
|
||||
|
@ -157,13 +157,7 @@ fn from_xlsx(
|
||||
sheet_output.push(Value::record(record, head));
|
||||
}
|
||||
|
||||
dict.insert(
|
||||
sheet_name,
|
||||
Value::List {
|
||||
vals: sheet_output,
|
||||
span: head,
|
||||
},
|
||||
);
|
||||
dict.insert(sheet_name, Value::list(sheet_output, head));
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
"Could not load sheet".to_string(),
|
||||
|
@ -336,10 +336,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn table(list: &[Value]) -> Value {
|
||||
Value::List {
|
||||
vals: list.to_vec(),
|
||||
span: Span::test_data(),
|
||||
}
|
||||
Value::list(list.to_vec(), Span::test_data())
|
||||
}
|
||||
|
||||
fn content_tag(
|
||||
|
@ -88,28 +88,20 @@ fn convert_yaml_value_to_nu_value(
|
||||
val_span,
|
||||
);
|
||||
Ok(match v {
|
||||
serde_yaml::Value::Bool(b) => Value::Bool { val: *b, span },
|
||||
serde_yaml::Value::Number(n) if n.is_i64() => Value::Int {
|
||||
val: n.as_i64().ok_or(err_not_compatible_number)?,
|
||||
span,
|
||||
},
|
||||
serde_yaml::Value::Number(n) if n.is_f64() => Value::Float {
|
||||
val: n.as_f64().ok_or(err_not_compatible_number)?,
|
||||
span,
|
||||
},
|
||||
serde_yaml::Value::String(s) => Value::String {
|
||||
val: s.to_string(),
|
||||
span,
|
||||
},
|
||||
serde_yaml::Value::Bool(b) => Value::bool(*b, span),
|
||||
serde_yaml::Value::Number(n) if n.is_i64() => {
|
||||
Value::int(n.as_i64().ok_or(err_not_compatible_number)?, span)
|
||||
}
|
||||
serde_yaml::Value::Number(n) if n.is_f64() => {
|
||||
Value::float(n.as_f64().ok_or(err_not_compatible_number)?, span)
|
||||
}
|
||||
serde_yaml::Value::String(s) => Value::string(s.to_string(), span),
|
||||
serde_yaml::Value::Sequence(a) => {
|
||||
let result: Result<Vec<Value>, ShellError> = a
|
||||
.iter()
|
||||
.map(|x| convert_yaml_value_to_nu_value(x, span, val_span))
|
||||
.collect();
|
||||
Value::List {
|
||||
vals: result?,
|
||||
span,
|
||||
}
|
||||
Value::list(result?, span)
|
||||
}
|
||||
serde_yaml::Value::Mapping(t) => {
|
||||
// Using an IndexMap ensures consistent ordering
|
||||
@ -155,10 +147,7 @@ fn convert_yaml_value_to_nu_value(
|
||||
.first()
|
||||
.and_then(|e| match e {
|
||||
(serde_yaml::Value::String(s), serde_yaml::Value::Null) => {
|
||||
Some(Value::String {
|
||||
val: "{{ ".to_owned() + s.as_str() + " }}",
|
||||
span,
|
||||
})
|
||||
Some(Value::string("{{ ".to_owned() + s.as_str() + " }}", span))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
@ -177,19 +166,19 @@ fn convert_yaml_value_to_nu_value(
|
||||
let value = match &t.value {
|
||||
serde_yaml::Value::String(s) => {
|
||||
let val = format!("{} {}", tag, s).trim().to_string();
|
||||
Value::String { val, span }
|
||||
Value::string(val, span)
|
||||
}
|
||||
serde_yaml::Value::Number(n) => {
|
||||
let val = format!("{} {}", tag, n).trim().to_string();
|
||||
Value::String { val, span }
|
||||
Value::string(val, span)
|
||||
}
|
||||
serde_yaml::Value::Bool(b) => {
|
||||
let val = format!("{} {}", tag, b).trim().to_string();
|
||||
Value::String { val, span }
|
||||
Value::string(val, span)
|
||||
}
|
||||
serde_yaml::Value::Null => {
|
||||
let val = format!("{}", tag).trim().to_string();
|
||||
Value::String { val, span }
|
||||
Value::string(val, span)
|
||||
}
|
||||
v => convert_yaml_value_to_nu_value(v, span, val_span)?,
|
||||
};
|
||||
@ -223,10 +212,7 @@ pub fn from_yaml_string_to_value(
|
||||
match documents.len() {
|
||||
0 => Ok(Value::nothing(span)),
|
||||
1 => Ok(documents.remove(0)),
|
||||
_ => Ok(Value::List {
|
||||
vals: documents,
|
||||
span,
|
||||
}),
|
||||
_ => Ok(Value::list(documents, span)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,22 +229,22 @@ pub fn get_examples() -> Vec<Example<'static>> {
|
||||
Example {
|
||||
example: "'[ a: 1, b: [1, 2] ]' | from yaml",
|
||||
description: "Converts yaml formatted string to table",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["a".to_string()],
|
||||
vals: vec![Value::test_int(1)],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["b".to_string()],
|
||||
vals: vec![Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}],
|
||||
vals: vec![Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -349,8 +335,8 @@ mod test {
|
||||
Span::test_data(),
|
||||
);
|
||||
|
||||
let expected: Result<Value, ShellError> = Ok(Value::List {
|
||||
vals: vec![
|
||||
let expected: Result<Value, ShellError> = Ok(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["a".to_string(), "b".to_string()],
|
||||
vals: vec![Value::test_string("b"), Value::test_string("c")],
|
||||
@ -360,8 +346,8 @@ mod test {
|
||||
vals: vec![Value::test_string("g"), Value::test_string("h")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
});
|
||||
Span::test_data(),
|
||||
));
|
||||
|
||||
// Unfortunately the eq function for Value doesn't compare well enough to detect
|
||||
// ordering errors in List columns or values.
|
||||
|
@ -32,16 +32,16 @@ impl Command for To {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&To.signature(),
|
||||
&To.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,10 @@ fn from_value_to_delimited_string(
|
||||
config: &Config,
|
||||
head: Span,
|
||||
) -> Result<String, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Record { val, span } => record_to_delimited(val, *span, separator, config, head),
|
||||
Value::List { vals, span } => table_to_delimited(vals, *span, separator, config, head),
|
||||
Value::Record { val, .. } => record_to_delimited(val, span, separator, config, head),
|
||||
Value::List { vals, .. } => table_to_delimited(vals, span, separator, config, head),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error.clone()),
|
||||
v => Err(make_unsupported_input_error(v, head, v.span())),
|
||||
|
@ -64,20 +64,18 @@ impl Command for ToJson {
|
||||
};
|
||||
|
||||
match json_result {
|
||||
Ok(serde_json_string) => Ok(Value::String {
|
||||
val: serde_json_string,
|
||||
span,
|
||||
Ok(serde_json_string) => {
|
||||
Ok(Value::string(serde_json_string, span).into_pipeline_data())
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
_ => Ok(Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
_ => Ok(Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "JSON".into(),
|
||||
from_type: value.get_type().to_string(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
.into_pipeline_data()),
|
||||
}
|
||||
}
|
||||
@ -107,6 +105,7 @@ impl Command for ToJson {
|
||||
}
|
||||
|
||||
pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
|
||||
let span = v.span();
|
||||
Ok(match v {
|
||||
Value::Bool { val, .. } => nu_json::Value::Bool(*val),
|
||||
Value::Filesize { val, .. } => nu_json::Value::I64(*val),
|
||||
@ -146,8 +145,8 @@ pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
|
||||
let collected = val.collect()?;
|
||||
value_to_json_value(&collected)?
|
||||
}
|
||||
Value::CustomValue { val, span } => {
|
||||
let collected = val.to_base_value(*span)?;
|
||||
Value::CustomValue { val, .. } => {
|
||||
let collected = val.to_base_value(span)?;
|
||||
value_to_json_value(&collected)?
|
||||
}
|
||||
})
|
||||
|
@ -161,9 +161,10 @@ fn table(input: PipelineData, pretty: bool, config: &Config) -> String {
|
||||
|
||||
for row in vec_of_values {
|
||||
let mut escaped_row: Vec<String> = Vec::new();
|
||||
let span = row.span();
|
||||
|
||||
match row.to_owned() {
|
||||
Value::Record { span, .. } => {
|
||||
Value::Record { .. } => {
|
||||
for i in 0..headers.len() {
|
||||
let data = row.get_data_by_key(&headers[i]);
|
||||
let value_string = data
|
||||
@ -224,23 +225,13 @@ pub fn group_by(values: PipelineData, head: Span, config: &Config) -> (PipelineD
|
||||
if value.len() == 1 {
|
||||
output.push(value.pop().unwrap_or_else(|| Value::nothing(head)))
|
||||
} else {
|
||||
output.push(Value::List {
|
||||
vals: value.to_vec(),
|
||||
span: head,
|
||||
})
|
||||
output.push(Value::list(value.to_vec(), head))
|
||||
}
|
||||
}
|
||||
if output.len() == 1 {
|
||||
single_list = true;
|
||||
}
|
||||
(
|
||||
Value::List {
|
||||
vals: output,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data(),
|
||||
single_list,
|
||||
)
|
||||
(Value::list(output, head).into_pipeline_data(), single_list)
|
||||
}
|
||||
|
||||
fn get_output_string(
|
||||
@ -391,8 +382,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn render_table() {
|
||||
let value = Value::List {
|
||||
vals: vec![
|
||||
let value = Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["country".to_string()],
|
||||
vals: vec![Value::test_string("Ecuador")],
|
||||
@ -406,8 +397,8 @@ mod tests {
|
||||
vals: vec![Value::test_string("USA")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
};
|
||||
Span::test_data(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
table(
|
||||
|
@ -73,20 +73,18 @@ impl Command for ToNuon {
|
||||
};
|
||||
|
||||
match nuon_result {
|
||||
Ok(serde_nuon_string) => Ok(Value::String {
|
||||
val: serde_nuon_string,
|
||||
span,
|
||||
Ok(serde_nuon_string) => {
|
||||
Ok(Value::string(serde_nuon_string, span).into_pipeline_data())
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
_ => Ok(Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
_ => Ok(Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "NUON".into(),
|
||||
from_type: value.get_type().to_string(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
.into_pipeline_data()),
|
||||
}
|
||||
}
|
||||
|
@ -64,11 +64,7 @@ impl Command for ToText {
|
||||
// Even if the data is collected when it arrives at `to text`, we should be able to stream it out
|
||||
let collected_input = local_into_string(input.into_value(span), line_ending, config);
|
||||
|
||||
Ok(Value::String {
|
||||
val: collected_input,
|
||||
span,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::string(collected_input, span).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ impl Command for ToToml {
|
||||
// Helper method to recursively convert nu_protocol::Value -> toml::Value
|
||||
// This shouldn't be called at the top-level
|
||||
fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellError> {
|
||||
let span = v.span();
|
||||
Ok(match &v {
|
||||
Value::Bool { val, .. } => toml::Value::Boolean(*val),
|
||||
Value::Int { val, .. } => toml::Value::Integer(*val),
|
||||
@ -66,13 +67,13 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellErr
|
||||
helper(engine_state, &collected)?
|
||||
}
|
||||
Value::List { vals, .. } => toml::Value::Array(toml_list(engine_state, vals)?),
|
||||
Value::Block { span, .. } => {
|
||||
let code = engine_state.get_span_contents(*span);
|
||||
Value::Block { .. } => {
|
||||
let code = engine_state.get_span_contents(span);
|
||||
let code = String::from_utf8_lossy(code).to_string();
|
||||
toml::Value::String(code)
|
||||
}
|
||||
Value::Closure { span, .. } => {
|
||||
let code = engine_state.get_span_contents(*span);
|
||||
Value::Closure { .. } => {
|
||||
let code = engine_state.get_span_contents(span);
|
||||
let code = String::from_utf8_lossy(code).to_string();
|
||||
toml::Value::String(code)
|
||||
}
|
||||
@ -113,20 +114,16 @@ fn toml_into_pipeline_data(
|
||||
span: Span,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
match toml::to_string(&toml_value) {
|
||||
Ok(serde_toml_string) => Ok(Value::String {
|
||||
val: serde_toml_string,
|
||||
span,
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
_ => Ok(Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
Ok(serde_toml_string) => Ok(Value::string(serde_toml_string, span).into_pipeline_data()),
|
||||
_ => Ok(Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "TOML".into(),
|
||||
from_type: value_type.to_string(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
.into_pipeline_data()),
|
||||
}
|
||||
}
|
||||
@ -194,10 +191,10 @@ mod tests {
|
||||
m.insert("is".to_owned(), Value::nothing(Span::test_data()));
|
||||
m.insert(
|
||||
"features".to_owned(),
|
||||
Value::List {
|
||||
vals: vec![Value::test_string("hello"), Value::test_string("array")],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_string("hello"), Value::test_string("array")],
|
||||
Span::test_data(),
|
||||
),
|
||||
);
|
||||
let tv = value_to_toml_value(
|
||||
&engine_state,
|
||||
@ -223,10 +220,7 @@ mod tests {
|
||||
.expect_err("Expected non-valid toml (String) to cause error!");
|
||||
value_to_toml_value(
|
||||
&engine_state,
|
||||
&Value::List {
|
||||
vals: vec![Value::test_string("1")],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
&Value::list(vec![Value::test_string("1")], Span::test_data()),
|
||||
Span::test_data(),
|
||||
)
|
||||
.expect_err("Expected non-valid toml (Table) to cause error!");
|
||||
|
@ -98,14 +98,15 @@ fn to_xml_entry<W: Write>(
|
||||
writer: &mut quick_xml::Writer<W>,
|
||||
) -> Result<(), ShellError> {
|
||||
let entry_span = entry.span();
|
||||
let span = entry.span();
|
||||
|
||||
// Allow using strings directly as content.
|
||||
// So user can write
|
||||
// {tag: a content: ['qwe']}
|
||||
// instead of longer
|
||||
// {tag: a content: [{content: 'qwe'}]}
|
||||
if let (Value::String { val, span }, false) = (&entry, top_level) {
|
||||
return to_xml_text(val.as_str(), *span, writer);
|
||||
if let (Value::String { val, .. }, false) = (&entry, top_level) {
|
||||
return to_xml_text(val.as_str(), span, writer);
|
||||
}
|
||||
|
||||
if !matches!(entry, Value::Record { .. }) {
|
||||
@ -130,8 +131,10 @@ fn to_xml_entry<W: Write>(
|
||||
.get_data_by_key(COLUMN_CONTENT_NAME)
|
||||
.unwrap_or_else(|| Value::nothing(Span::unknown()));
|
||||
|
||||
let content_span = content.span();
|
||||
let tag_span = tag.span();
|
||||
match (tag, attrs, content) {
|
||||
(Value::Nothing { .. }, Value::Nothing { .. }, Value::String { val, span }) => {
|
||||
(Value::Nothing { .. }, Value::Nothing { .. }, Value::String { val, .. }) => {
|
||||
// Strings can not appear on top level of document
|
||||
if top_level {
|
||||
return Err(ShellError::CantConvert {
|
||||
@ -141,16 +144,9 @@ fn to_xml_entry<W: Write>(
|
||||
help: Some("Strings can not be a root element of document".into()),
|
||||
});
|
||||
}
|
||||
to_xml_text(val.as_str(), span, writer)
|
||||
to_xml_text(val.as_str(), content_span, writer)
|
||||
}
|
||||
(
|
||||
Value::String {
|
||||
val: tag_name,
|
||||
span: tag_span,
|
||||
},
|
||||
attrs,
|
||||
children,
|
||||
) => to_tag_like(
|
||||
(Value::String { val: tag_name, .. }, attrs, children) => to_tag_like(
|
||||
entry_span, tag_name, tag_span, attrs, children, top_level, writer,
|
||||
),
|
||||
_ => Ok(()),
|
||||
|
@ -106,20 +106,16 @@ fn to_yaml(input: PipelineData, head: Span) -> Result<PipelineData, ShellError>
|
||||
|
||||
let yaml_value = value_to_yaml_value(&value)?;
|
||||
match serde_yaml::to_string(&yaml_value) {
|
||||
Ok(serde_yaml_string) => Ok(Value::String {
|
||||
val: serde_yaml_string,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
_ => Ok(Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
Ok(serde_yaml_string) => Ok(Value::string(serde_yaml_string, head).into_pipeline_data()),
|
||||
_ => Ok(Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "YAML".into(),
|
||||
from_type: value.get_type().to_string(),
|
||||
span: head,
|
||||
help: None,
|
||||
}),
|
||||
span: head,
|
||||
}
|
||||
},
|
||||
head,
|
||||
)
|
||||
.into_pipeline_data()),
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user