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:
JT
2023-09-04 02:27:29 +12:00
committed by GitHub
parent af79eb2943
commit 6cdfee3573
372 changed files with 5811 additions and 7448 deletions

View File

@ -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())
}
}

View File

@ -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",

View File

@ -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),
}
}

View File

@ -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),
}
}

View File

@ -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(),

View File

@ -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(),

View File

@ -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(

View File

@ -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),
}
}

View File

@ -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",

View File

@ -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(),

View File

@ -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(

View File

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

View File

@ -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())
}
}

View File

@ -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())),

View File

@ -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)?
}
})

View File

@ -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(

View File

@ -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()),
}
}

View File

@ -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())
}
}

View File

@ -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!");

View File

@ -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(()),

View File

@ -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()),
}
}