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