forked from extern/nushell
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 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