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

@ -63,8 +63,8 @@ impl Command for DetectColumns {
Example {
description: "Splits string across multiple columns",
example: "'a b c' | detect columns -n",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
result: Some(Value::list(
vec![Value::test_record(Record {
cols: vec![
"column0".to_string(),
"column1".to_string(),
@ -77,7 +77,7 @@ impl Command for DetectColumns {
],
})],
span,
}),
)),
},
Example {
description: "",
@ -150,10 +150,7 @@ fn detect_columns(
if headers.len() == row.len() {
for (header, val) in headers.iter().zip(row.iter()) {
cols.push(header.item.clone());
vals.push(Value::String {
val: val.item.clone(),
span: name_span,
});
vals.push(Value::string(val.item.clone(), name_span));
}
} else {
let mut pre_output = vec![];
@ -217,10 +214,7 @@ fn detect_columns(
}
Err(processing_error) => {
let err = processing_error("could not find range index", name_span);
return Value::Error {
error: Box::new(err),
span: name_span,
};
return Value::error(err, name_span);
}
}
} else {

View File

@ -90,8 +90,8 @@ fn action(
"binhex" => GeneralPurpose::new(&alphabet::BIN_HEX, NO_PAD),
"crypt" => GeneralPurpose::new(&alphabet::CRYPT, NO_PAD),
"mutf7" => GeneralPurpose::new(&alphabet::IMAP_MUTF7, NO_PAD),
not_valid => return Value::Error { error:
Box::new(ShellError::GenericError(
not_valid => return Value::error (
ShellError::GenericError(
"value is not an accepted character set".to_string(),
format!(
"{not_valid} is not a valid character-set.\nPlease use `help encode base64` to see a list of valid character sets."
@ -99,48 +99,46 @@ fn action(
Some(config_character_set.span),
None,
Vec::new(),
)), span:config_character_set.span}
), config_character_set.span)
};
let value_span = input.span();
match input {
// Propagate existing errors.
Value::Error { .. } => input.clone(),
Value::Binary { val, span } => match base64_config.action_type {
Value::Binary { val, .. } => match base64_config.action_type {
ActionType::Encode => {
let mut enc_vec = Vec::new();
enc_vec.resize(val.len() * 4 / 3 + 4, 0);
let bytes_written = match base64_engine.encode_slice(val, &mut enc_vec) {
Ok(bytes_written) => bytes_written,
Err(err) => {
return Value::Error {
error: Box::new(ShellError::GenericError(
return Value::error(
ShellError::GenericError(
"Error encoding data".into(),
err.to_string(),
Some(*span),
Some(value_span),
None,
Vec::new(),
)),
span: *span,
}
),
value_span,
)
}
};
enc_vec.truncate(bytes_written);
Value::string(std::str::from_utf8(&enc_vec).unwrap_or(""), command_span)
}
ActionType::Decode => Value::Error {
error: Box::new(ShellError::UnsupportedInput(
ActionType::Decode => Value::error(
ShellError::UnsupportedInput(
"Binary data can only be encoded".to_string(),
"value originates from here".into(),
command_span,
// This line requires the Value::Error {} match above.
input.span(),
)),
span: command_span,
},
),
command_span,
),
},
Value::String {
val,
span: value_span,
} => {
Value::String { val, .. } => {
match base64_config.action_type {
ActionType::Encode => {
let mut enc_str = String::new();
@ -160,22 +158,22 @@ fn action(
} else {
match String::from_utf8(decoded_value) {
Ok(string_value) => Value::string(string_value, command_span),
Err(e) => Value::Error {
error: Box::new(ShellError::GenericError(
Err(e) => Value::error(
ShellError::GenericError(
"base64 payload isn't a valid utf-8 sequence"
.to_owned(),
e.to_string(),
Some(*value_span),
Some(value_span),
Some("consider using the `--binary` flag".to_owned()),
Vec::new(),
)),
span: *value_span,
},
),
value_span,
),
}
}
}
Err(_) => Value::Error {
error: Box::new(ShellError::GenericError(
Err(_) => Value::error(
ShellError::GenericError(
"value could not be base64 decoded".to_string(),
format!(
"invalid base64 input for character set {}",
@ -184,20 +182,20 @@ fn action(
Some(command_span),
None,
Vec::new(),
)),
span: command_span,
},
),
command_span,
),
}
}
}
}
other => Value::Error {
error: Box::new(ShellError::TypeMismatch {
other => Value::error(
ShellError::TypeMismatch {
err_message: format!("string or binary, not {}", other.get_type()),
span: other.span(),
}),
span: other.span(),
},
},
other.span(),
),
}
}
@ -323,10 +321,7 @@ mod tests {
#[test]
fn base64_encode_binary() {
let word = Value::Binary {
val: vec![77, 97, 110],
span: Span::test_data(),
};
let word = Value::binary(vec![77, 97, 110], Span::test_data());
let expected = Value::test_string("TWFu");
let actual = action(
@ -349,10 +344,7 @@ mod tests {
#[test]
fn base64_decode_binary_expect_error() {
let word = Value::Binary {
val: vec![77, 97, 110],
span: Span::test_data(),
};
let word = Value::binary(vec![77, 97, 110], Span::test_data());
let actual = action(
&word,

View File

@ -47,10 +47,7 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
Example {
description: "Decode an UTF-16 string into nushell UTF-8 string",
example: r#"0x[00 53 00 6F 00 6D 00 65 00 20 00 44 00 61 00 74 00 61] | decode utf-16be"#,
result: Some(Value::String {
val: "Some Data".to_owned(),
span: Span::test_data(),
}),
result: Some(Value::string("Some Data".to_owned(), Span::test_data())),
},
]
}
@ -77,29 +74,29 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
Some(encoding_name) => super::encoding::decode(head, encoding_name, &bytes),
None => super::encoding::detect_encoding_name(head, input_span, &bytes)
.map(|encoding| encoding.decode(&bytes).0.into_owned())
.map(|s| Value::String { val: s, span: head }),
.map(|s| Value::string(s, head)),
}
.map(|val| val.into_pipeline_data())
}
PipelineData::Value(v, ..) => match v {
Value::Binary {
val: bytes,
span: input_span,
} => match encoding {
Some(encoding_name) => super::encoding::decode(head, encoding_name, &bytes),
None => super::encoding::detect_encoding_name(head, input_span, &bytes)
.map(|encoding| encoding.decode(&bytes).0.into_owned())
.map(|s| Value::String { val: s, span: head }),
PipelineData::Value(v, ..) => {
let input_span = v.span();
match v {
Value::Binary { val: bytes, .. } => match encoding {
Some(encoding_name) => super::encoding::decode(head, encoding_name, &bytes),
None => super::encoding::detect_encoding_name(head, input_span, &bytes)
.map(|encoding| encoding.decode(&bytes).0.into_owned())
.map(|s| Value::string(s, head)),
}
.map(|val| val.into_pipeline_data()),
Value::Error { error, .. } => Err(*error),
_ => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(),
wrong_type: v.get_type().to_string(),
dst_span: head,
src_span: v.span(),
}),
}
.map(|val| val.into_pipeline_data()),
Value::Error { error, .. } => Err(*error),
_ => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "binary".into(),
wrong_type: v.get_type().to_string(),
dst_span: head,
src_span: v.span(),
}),
},
}
// This should be more precise, but due to difficulties in getting spans
// from PipelineData::ListData, this is as it is.
_ => Err(ShellError::UnsupportedInput(

View File

@ -53,23 +53,23 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
Example {
description: "Encode an UTF-8 string into Shift-JIS",
example: r#""" | encode shift-jis"#,
result: Some(Value::Binary {
val: vec![
result: Some(Value::binary(
vec![
0x95, 0x89, 0x82, 0xaf, 0x82, 0xe9, 0x82, 0xc6, 0x92, 0x6d, 0x82, 0xc1,
0x82, 0xc4, 0x90, 0xed, 0x82, 0xa4, 0x82, 0xcc, 0x82, 0xaa, 0x81, 0x41,
0x97, 0x79, 0x82, 0xa9, 0x82, 0xc9, 0x94, 0xfc, 0x82, 0xb5, 0x82, 0xa2,
0x82, 0xcc, 0x82, 0xbe,
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Replace characters with HTML entities if they can't be encoded",
example: r#""🎈" | encode -i shift-jis"#,
result: Some(Value::Binary {
val: vec![0x26, 0x23, 0x31, 0x32, 0x37, 0x38, 0x38, 0x30, 0x3b],
span: Span::test_data(),
}),
result: Some(Value::binary(
vec![0x26, 0x23, 0x31, 0x32, 0x37, 0x38, 0x38, 0x30, 0x3b],
Span::test_data(),
)),
},
]
}
@ -95,19 +95,22 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
super::encoding::encode(head, encoding, &s.item, s.span, ignore_errors)
.map(|val| val.into_pipeline_data())
}
PipelineData::Value(v, ..) => match v {
Value::String { val: s, span } => {
super::encoding::encode(head, encoding, &s, span, ignore_errors)
.map(|val| val.into_pipeline_data())
PipelineData::Value(v, ..) => {
let span = v.span();
match v {
Value::String { val: s, .. } => {
super::encoding::encode(head, encoding, &s, span, ignore_errors)
.map(|val| val.into_pipeline_data())
}
Value::Error { error, .. } => Err(*error),
_ => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: v.get_type().to_string(),
dst_span: head,
src_span: v.span(),
}),
}
Value::Error { error, .. } => Err(*error),
_ => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: v.get_type().to_string(),
dst_span: head,
src_span: v.span(),
}),
},
}
// This should be more precise, but due to difficulties in getting spans
// from PipelineData::ListStream, this is as it is.
_ => Err(ShellError::UnsupportedInput(

View File

@ -34,10 +34,7 @@ pub fn decode(
parse_encoding(encoding_name.span, &encoding_name.item)
}?;
let (result, ..) = encoding.decode(bytes);
Ok(Value::String {
val: result.into_owned(),
span: head,
})
Ok(Value::string(result.into_owned(), head))
}
pub fn encode(
@ -66,10 +63,7 @@ pub fn encode(
vec![],
))
} else {
Ok(Value::Binary {
val: result.into_owned(),
span: head,
})
Ok(Value::binary(result.into_owned(), head))
}
}

View File

@ -79,19 +79,19 @@ impl Command for FormatDate {
Example {
description: "Format a given date-time using the default format (RFC 2822).",
example: r#"'2021-10-22 20:00:12 +01:00' | into datetime | format date"#,
result: Some(Value::String {
val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string(
"Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
Span::test_data(),
)),
},
Example {
description:
"Format a given date-time as a string using the default format (RFC 2822).",
example: r#""2021-10-22 20:00:12 +01:00" | format date"#,
result: Some(Value::String {
val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string(
"Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
Span::test_data(),
)),
},
Example {
description: "Format the current date-time using a given format string.",
@ -126,17 +126,14 @@ where
let format = date_time.format_localized(formatter, locale);
match formatter_buf.write_fmt(format_args!("{format}")) {
Ok(_) => Value::String {
val: formatter_buf,
span,
},
Err(_) => Value::Error {
error: Box::new(ShellError::TypeMismatch {
Ok(_) => Value::string(formatter_buf, span),
Err(_) => Value::error(
ShellError::TypeMismatch {
err_message: "invalid format".to_string(),
span,
}),
},
span,
},
),
}
}
@ -151,39 +148,28 @@ fn format_helper(value: Value, formatter: &str, formatter_span: Span, head_span:
Err(e) => e,
}
}
_ => Value::Error {
error: Box::new(ShellError::DatetimeParseError(
value.debug_value(),
head_span,
)),
span: head_span,
},
_ => Value::error(
ShellError::DatetimeParseError(value.debug_value(), head_span),
head_span,
),
}
}
fn format_helper_rfc2822(value: Value, span: Span) -> Value {
let val_span = value.span();
match value {
Value::Date { val, span: _ } => Value::String {
val: val.to_rfc2822(),
span,
},
Value::String {
val,
span: val_span,
} => {
Value::Date { val, .. } => Value::string(val.to_rfc2822(), span),
Value::String { val, .. } => {
let dt = parse_date_from_string(&val, val_span);
match dt {
Ok(x) => Value::String {
val: x.to_rfc2822(),
span,
},
Ok(x) => Value::string(x.to_rfc2822(), span),
Err(e) => e,
}
}
_ => Value::Error {
error: Box::new(ShellError::DatetimeParseError(value.debug_value(), span)),
_ => Value::error(
ShellError::DatetimeParseError(value.debug_value(), span),
span,
},
),
}
}

View File

@ -111,14 +111,12 @@ impl Command for FormatDuration {
}
fn format_value_impl(val: &Value, arg: &Arguments, span: Span) -> Value {
let inner_span = val.span();
match val {
Value::Duration {
val: inner,
span: inner_span,
} => {
Value::Duration { val: inner, .. } => {
let duration = *inner;
let float_precision = arg.float_precision;
match convert_inner_to_unit(duration, &arg.format_value, span, *inner_span) {
match convert_inner_to_unit(duration, &arg.format_value, span, inner_span) {
Ok(d) => {
let unit = if &arg.format_value == "us" {
"µs"
@ -126,33 +124,24 @@ fn format_value_impl(val: &Value, arg: &Arguments, span: Span) -> Value {
&arg.format_value
};
if d.fract() == 0.0 {
Value::String {
val: format!("{} {}", d, unit),
span: *inner_span,
}
Value::string(format!("{} {}", d, unit), inner_span)
} else {
Value::String {
val: format!("{:.float_precision$} {}", d, unit),
span: *inner_span,
}
Value::string(format!("{:.float_precision$} {}", d, unit), inner_span)
}
}
Err(e) => Value::Error {
error: Box::new(e),
span: *inner_span,
},
Err(e) => Value::error(e, inner_span),
}
}
Value::Error { .. } => val.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "filesize".into(),
wrong_type: val.get_type().to_string(),
dst_span: span,
src_span: val.span(),
}),
},
span,
},
),
}
}

View File

@ -103,22 +103,23 @@ impl Command for FormatFilesize {
}
fn format_value_impl(val: &Value, arg: &Arguments, span: Span) -> Value {
let value_span = val.span();
match val {
Value::Filesize { val, span } => Value::String {
Value::Filesize { val, .. } => Value::string(
// don't need to concern about metric, we just format units by what user input.
val: format_filesize(*val, &arg.format_value, None),
span: *span,
},
format_filesize(*val, &arg.format_value, None),
span,
),
Value::Error { .. } => val.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "filesize".into(),
wrong_type: val.get_type().to_string(),
dst_span: span,
src_span: val.span(),
}),
src_span: value_span,
},
span,
},
),
}
}

View File

@ -43,13 +43,13 @@ impl Command for Parse {
}
fn examples(&self) -> Vec<Example> {
let result = Value::List {
vals: vec![Value::test_record(Record {
let result = Value::list(
vec![Value::test_record(Record {
cols: vec!["foo".to_string(), "bar".to_string()],
vals: vec![Value::test_string("hi"), Value::test_string("there")],
})],
span: Span::test_data(),
};
Span::test_data(),
);
vec![
Example {
@ -65,19 +65,19 @@ impl Command for Parse {
Example {
description: "Parse a string using fancy-regex named capture group pattern",
example: "\"foo bar.\" | parse -r '\\s*(?<name>\\w+)(?=\\.)'",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
result: Some(Value::list(
vec![Value::test_record(Record {
cols: vec!["name".to_string()],
vals: vec![Value::test_string("bar")],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Parse a string using fancy-regex capture group pattern",
example: "\"foo! bar.\" | parse -r '(\\w+)(?=\\.)|(\\w+)(?=!)'",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_record(Record {
cols: vec!["capture0".to_string(), "capture1".to_string()],
vals: vec![Value::test_string(""), Value::test_string("foo")],
@ -87,34 +87,34 @@ impl Command for Parse {
vals: vec![Value::test_string("bar"), Value::test_string("")],
}),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Parse a string using fancy-regex look behind pattern",
example:
"\" @another(foo bar) \" | parse -r '\\s*(?<=[() ])(@\\w+)(\\([^)]*\\))?\\s*'",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
result: Some(Value::list(
vec![Value::test_record(Record {
cols: vec!["capture0".to_string(), "capture1".to_string()],
vals: vec![
Value::test_string("@another"),
Value::test_string("(foo bar)"),
],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Parse a string using fancy-regex look ahead atomic group pattern",
example: "\"abcd\" | parse -r '^a(bc(?=d)|b)cd$'",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
result: Some(Value::list(
vec![Value::test_record(Record {
cols: vec!["capture0".to_string()],
vals: vec![Value::test_string("b")],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -342,14 +342,14 @@ impl Iterator for ParseStreamer {
let Some(v) = self.stream.next() else { return None };
let Ok(s) = v.as_string() else {
return Some(Value::Error {
error: Box::new(ShellError::PipelineMismatch {
return Some(Value::error (
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: self.span,
src_span: v.span(),
}),
span: v.span(),
})
},
v.span(),
))
};
let parsed = stream_helper(
@ -401,24 +401,19 @@ impl Iterator for ParseStreamerExternal {
let chunk = match chunk {
Some(Ok(chunk)) => chunk,
Some(Err(err)) => {
return Some(Value::Error {
error: Box::new(err),
span: self.span,
})
}
Some(Err(err)) => return Some(Value::error(err, self.span)),
_ => return None,
};
let Ok(chunk) = String::from_utf8(chunk) else {
return Some(Value::Error {
error: Box::new(ShellError::PipelineMismatch {
return Some(Value::error(
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: self.span,
src_span: self.span,
}),
span: self.span,
})
},
self.span,
))
};
stream_helper(
@ -444,16 +439,16 @@ fn stream_helper(
let captures = match c {
Ok(c) => c,
Err(e) => {
return Some(Value::Error {
error: Box::new(ShellError::GenericError(
return Some(Value::error(
ShellError::GenericError(
"Error with regular expression captures".into(),
e.to_string(),
Some(span),
Some(e.to_string()),
Vec::new(),
)),
),
span,
})
))
}
};

View File

@ -121,27 +121,22 @@ fn size(
}
input.map(
move |v| {
let value_span = v.span();
// First, obtain the span. If this fails, propagate the error that results.
let value_span = match &v {
Value::Error { error, span } => {
return Value::Error {
error: error.clone(),
span: *span,
}
}
v => v.span(),
};
if let Value::Error { error, .. } = v {
return Value::error(*error, span);
}
// Now, check if it's a string.
match v.as_string() {
Ok(s) => counter(&s, span),
Err(_) => Value::Error {
error: Box::new(ShellError::PipelineMismatch {
Err(_) => Value::error(
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: span,
src_span: value_span,
}),
},
span,
},
),
}
},
engine_state.ctrlc.clone(),

View File

@ -46,28 +46,28 @@ impl Command for SubCommand {
Example {
description: "Split the string into a list of characters",
example: "'hello' | split chars",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("h"),
Value::test_string("e"),
Value::test_string("l"),
Value::test_string("l"),
Value::test_string("o"),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split on grapheme clusters",
example: "'🇯🇵ほげ' | split chars -g",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("🇯🇵"),
Value::test_string(""),
Value::test_string(""),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split multiple strings into lists of characters",
@ -118,16 +118,14 @@ fn split_chars(
}
fn split_chars_helper(v: &Value, name: Span, graphemes: bool) -> Value {
let span = v.span();
match v {
Value::Error { error, span } => Value::Error {
error: error.clone(),
span: *span,
},
Value::Error { error, .. } => Value::error(*error.clone(), span),
v => {
let v_span = v.span();
if let Ok(s) = v.as_string() {
Value::List {
vals: if graphemes {
Value::list(
if graphemes {
s.graphemes(true)
.collect::<Vec<_>>()
.into_iter()
@ -140,17 +138,17 @@ fn split_chars_helper(v: &Value, name: Span, graphemes: bool) -> Value {
.map(move |x| Value::string(x, v_span))
.collect()
},
span: v_span,
}
v_span,
)
} else {
Value::Error {
error: Box::new(ShellError::PipelineMismatch {
Value::error(
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: name,
src_span: v_span,
}),
span: name,
}
},
name,
)
}
}
}

View File

@ -63,8 +63,8 @@ impl Command for SubCommand {
Example {
description: "Split a string into columns by the specified separator",
example: "'a--b--c' | split column '--'",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
result: Some(Value::list(
vec![Value::test_record(Record {
cols: vec![
"column1".to_string(),
"column2".to_string(),
@ -76,14 +76,14 @@ impl Command for SubCommand {
Value::test_string("c"),
],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a string into columns of char and remove the empty columns",
example: "'abc' | split column -c ''",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
result: Some(Value::list(
vec![Value::test_record(Record {
cols: vec![
"column1".to_string(),
"column2".to_string(),
@ -95,14 +95,14 @@ impl Command for SubCommand {
Value::test_string("c"),
],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a list of strings into a table",
example: "['a-b' 'c-d'] | split column -",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_record(Record {
cols: vec!["column1".to_string(), "column2".to_string()],
vals: vec![Value::test_string("a"), Value::test_string("b")],
@ -112,14 +112,14 @@ impl Command for SubCommand {
vals: vec![Value::test_string("c"), Value::test_string("d")],
}),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a list of strings into a table, ignoring padding",
example: r"['a - b' 'c - d'] | split column -r '\s*-\s*'",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_record(Record {
cols: vec!["column1".to_string(), "column2".to_string()],
vals: vec![Value::test_string("a"), Value::test_string("b")],
@ -129,8 +129,8 @@ impl Command for SubCommand {
vals: vec![Value::test_string("c"), Value::test_string("d")],
}),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -203,21 +203,18 @@ fn split_column_helper(
} else {
match v {
Value::Error { error, .. } => {
vec![Value::Error {
error: Box::new(*error.clone()),
span: head,
}]
vec![Value::error(*error.clone(), head)]
}
v => {
let span = v.span();
vec![Value::Error {
error: Box::new(ShellError::PipelineMismatch {
vec![Value::error(
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: head,
src_span: span,
}),
},
span,
}]
)]
}
}
}

View File

@ -34,16 +34,16 @@ impl Command for SplitCommand {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(Value::String {
val: get_full_help(
Ok(Value::string(
get_full_help(
&SplitCommand.signature(),
&SplitCommand.examples(),
engine_state,
stack,
self.is_parser_keyword(),
),
span: call.head,
}
call.head,
)
.into_pipeline_data())
}
}

View File

@ -56,100 +56,97 @@ impl Command for SubCommand {
Example {
description: "Split a list of chars into two lists",
example: "[a, b, c, d, e, f, g] | split list d",
result: Some(Value::List {
vals: vec![
Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::list(
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
],
span: Span::test_data(),
},
Value::List {
vals: vec![
Span::test_data(),
),
Value::list(
vec![
Value::test_string("e"),
Value::test_string("f"),
Value::test_string("g"),
],
span: Span::test_data(),
},
Span::test_data(),
),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a list of lists into two lists of lists",
example: "[[1,2], [2,3], [3,4]] | split list [2,3]",
result: Some(Value::List {
vals: vec![
Value::List {
vals: vec![Value::List {
vals: vec![Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
}],
span: Span::test_data(),
},
Value::List {
vals: vec![Value::List {
vals: vec![Value::test_int(3), Value::test_int(4)],
span: Span::test_data(),
}],
span: Span::test_data(),
},
result: Some(Value::list(
vec![
Value::list(
vec![Value::list(
vec![Value::test_int(1), Value::test_int(2)],
Span::test_data(),
)],
Span::test_data(),
),
Value::list(
vec![Value::list(
vec![Value::test_int(3), Value::test_int(4)],
Span::test_data(),
)],
Span::test_data(),
),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a list of chars into two lists",
example: "[a, b, c, d, a, e, f, g] | split list a",
result: Some(Value::List {
vals: vec![
Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::list(
vec![
Value::test_string("b"),
Value::test_string("c"),
Value::test_string("d"),
],
span: Span::test_data(),
},
Value::List {
vals: vec![
Span::test_data(),
),
Value::list(
vec![
Value::test_string("e"),
Value::test_string("f"),
Value::test_string("g"),
],
span: Span::test_data(),
},
Span::test_data(),
),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a list of chars into lists based on multiple characters",
example: r"[a, b, c, d, a, e, f, g] | split list -r '(b|e)'",
result: Some(Value::List {
vals: vec![
Value::List {
vals: vec![Value::test_string("a")],
span: Span::test_data(),
},
Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::list(vec![Value::test_string("a")], Span::test_data()),
Value::list(
vec![
Value::test_string("c"),
Value::test_string("d"),
Value::test_string("a"),
],
span: Span::test_data(),
},
Value::List {
vals: vec![Value::test_string("f"), Value::test_string("g")],
span: Span::test_data(),
},
Span::test_data(),
),
Value::list(
vec![Value::test_string("f"), Value::test_string("g")],
Span::test_data(),
),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -211,10 +208,7 @@ fn split_list(
for val in iter {
if matcher.compare(&val)? {
if !temp_list.is_empty() {
returned_list.push(Value::List {
vals: temp_list.clone(),
span: call.head,
});
returned_list.push(Value::list(temp_list.clone(), call.head));
temp_list = Vec::new();
}
} else {
@ -222,16 +216,9 @@ fn split_list(
}
}
if !temp_list.is_empty() {
returned_list.push(Value::List {
vals: temp_list.clone(),
span: call.head,
});
returned_list.push(Value::list(temp_list.clone(), call.head));
}
Ok(Value::List {
vals: returned_list,
span: call.head,
}
.into_pipeline_data())
Ok(Value::list(returned_list, call.head).into_pipeline_data())
}
#[cfg(test)]

View File

@ -62,54 +62,54 @@ impl Command for SubCommand {
Example {
description: "Split a string into rows of char",
example: "'abc' | split row ''",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string(""),
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
Value::test_string(""),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a string into rows by the specified separator",
example: "'a--b--c' | split row '--'",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a string by '-'",
example: "'-a-b-c-' | split row '-'",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string(""),
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
Value::test_string(""),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Split a string by regex",
example: r"'a b c' | split row -r '\s+'",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -146,12 +146,10 @@ fn split_row(
}
fn split_row_helper(v: &Value, regex: &Regex, max_split: Option<usize>, name: Span) -> Vec<Value> {
let span = v.span();
match v {
Value::Error { error, span } => {
vec![Value::Error {
error: Box::new(*error.clone()),
span: *span,
}]
Value::Error { error, .. } => {
vec![Value::error(*error.clone(), span)]
}
v => {
let v_span = v.span();
@ -168,14 +166,14 @@ fn split_row_helper(v: &Value, regex: &Regex, max_split: Option<usize>, name: Sp
.collect(),
}
} else {
vec![Value::Error {
error: Box::new(ShellError::PipelineMismatch {
vec![Value::error(
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: name,
src_span: v_span,
}),
span: name,
}]
},
name,
)]
}
}
}

View File

@ -73,23 +73,23 @@ impl Command for SubCommand {
Example {
description: "Split the string's words into separate rows",
example: "'hello world' | split words",
result: Some(Value::List {
vals: vec![Value::test_string("hello"), Value::test_string("world")],
span: Span::test_data(),
}),
result: Some(Value::list(
vec![Value::test_string("hello"), Value::test_string("world")],
Span::test_data(),
)),
},
Example {
description:
"Split the string's words, of at least 3 characters, into separate rows",
example: "'hello to the world' | split words -l 3",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("hello"),
Value::test_string("the"),
Value::test_string("world"),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description:
@ -152,12 +152,10 @@ fn split_words_helper(v: &Value, word_length: Option<usize>, span: Span, graphem
// [^\p{L}\'] = do not match any unicode uppercase or lowercase letters or apostrophes
// Let's go with the unicode one in hopes that it works on more than just ascii characters
let regex_replace = Regex::new(r"[^\p{L}\']").expect("regular expression error");
let v_span = v.span();
match v {
Value::Error { error, span } => Value::Error {
error: Box::new(*error.clone()),
span: *span,
},
Value::Error { error, .. } => Value::error(*error.clone(), v_span),
v => {
let v_span = v.span();
if let Ok(s) = v.as_string() {
@ -189,19 +187,16 @@ fn split_words_helper(v: &Value, word_length: Option<usize>, span: Span, graphem
}
})
.collect::<Vec<Value>>();
Value::List {
vals: words,
span: v_span,
}
Value::list(words, v_span)
} else {
Value::Error {
error: Box::new(ShellError::PipelineMismatch {
Value::error(
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: span,
src_span: v_span,
}),
span,
}
},
v_span,
)
}
}
}

View File

@ -68,13 +68,13 @@ impl Command for SubCommand {
Example {
description: "Capitalize a column in a table",
example: "[[lang, gems]; [nu_test, 100]] | str capitalize lang",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
result: Some(Value::list(
vec![Value::test_record(Record {
cols: vec!["lang".to_string(), "gems".to_string()],
vals: vec![Value::test_string("Nu_test"), Value::test_int(100)],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -98,10 +98,7 @@ fn operate(
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
if let Err(error) = r {
return Value::Error {
error: Box::new(error),
span: head,
};
return Value::error(error, head);
}
}
ret
@ -113,20 +110,17 @@ fn operate(
fn action(input: &Value, head: Span) -> Value {
match input {
Value::String { val, .. } => Value::String {
val: uppercase_helper(val),
span: head,
},
Value::String { val, .. } => Value::string(uppercase_helper(val), head),
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -68,24 +68,24 @@ impl Command for SubCommand {
Example {
description: "Downcase contents",
example: "[[ColA ColB]; [Test ABC]] | str downcase ColA",
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_string("test"), Value::test_string("ABC")],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Downcase contents",
example: "[[ColA ColB]; [Test ABC]] | str downcase ColA ColB",
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_string("test"), Value::test_string("abc")],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -109,10 +109,7 @@ fn operate(
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
if let Err(error) = r {
return Value::Error {
error: Box::new(error),
span: head,
};
return Value::error(error, head);
}
}
ret
@ -124,20 +121,17 @@ fn operate(
fn action(input: &Value, head: Span) -> Value {
match input {
Value::String { val, .. } => Value::String {
val: val.to_ascii_lowercase(),
span: head,
},
Value::String { val, .. } => Value::string(val.to_ascii_lowercase(), head),
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -51,19 +51,16 @@ where
{
let case_operation = args.case_operation;
match input {
Value::String { val, .. } => Value::String {
val: case_operation(val),
span: head,
},
Value::String { val, .. } => Value::string(case_operation(val), head),
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -34,16 +34,16 @@ impl Command for Str {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(Value::String {
val: get_full_help(
Ok(Value::string(
get_full_help(
&Str.signature(),
&Str.examples(),
engine_state,
stack,
self.is_parser_keyword(),
),
span: call.head,
}
call.head,
)
.into_pipeline_data())
}
}

View File

@ -78,10 +78,7 @@ fn operate(
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
if let Err(error) = r {
return Value::Error {
error: Box::new(error),
span: head,
};
return Value::error(error, head);
}
}
ret
@ -93,20 +90,17 @@ fn operate(
fn action(input: &Value, head: Span) -> Value {
match input {
Value::String { val: s, .. } => Value::String {
val: s.to_uppercase(),
span: head,
},
Value::String { val: s, .. } => Value::string(s.to_uppercase(), head),
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -97,24 +97,24 @@ impl Command for SubCommand {
Example {
description: "Check if input contains string in a table",
example: " [[ColA ColB]; [test 100]] | str contains -i 'E' ColA",
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_bool(true), Value::test_int(100)],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Check if input contains string in a table",
example: " [[ColA ColB]; [test hello]] | str contains 'e' ColA ColB",
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_bool(true), Value::test_bool(true)],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Check if input string contains 'banana'",
@ -124,26 +124,26 @@ impl Command for SubCommand {
Example {
description: "Check if list contains string",
example: "[one two three] | str contains o",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_bool(true),
Value::test_bool(true),
Value::test_bool(false),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Check if list does not contain string",
example: "[one two three] | str contains -n o",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_bool(false),
Value::test_bool(false),
Value::test_bool(true),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -182,15 +182,15 @@ fn action(
head,
),
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -80,15 +80,15 @@ impl Command for SubCommand {
Example {
description: "Compute edit distance between strings in table and another string, using cell paths",
example: "[{a: 'nutshell' b: 'numetal'}] | str distance 'nushell' 'a' 'b'",
result: Some(Value::List {
vals: vec![
result: Some(Value::list (
vec![
Value::test_record(Record {
cols: vec!["a".to_string(), "b".to_string()],
vals: vec![Value::test_int(1), Value::test_int(4)],
})
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Compute edit distance between strings in record and another string, using cell paths",
@ -111,15 +111,15 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
Value::int(distance as i64, head)
}
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -105,15 +105,15 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
Value::bool(ends_with, head)
}
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -43,142 +43,142 @@ impl Command for SubCommand {
Example {
description: "Define a range inside braces to produce a list of string.",
example: "\"{3..5}\" | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("3"),
Value::test_string("4"),
Value::test_string("5")
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Ignore the next character after the backslash ('\\')",
example: "'A{B\\,,C}' | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("AB,"),
Value::test_string("AC"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Commas that are not inside any braces need to be skipped.",
example: "'Welcome\\, {home,mon ami}!' | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("Welcome, home!"),
Value::test_string("Welcome, mon ami!"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Use double backslashes to add a backslash.",
example: "'A{B\\\\,C}' | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("AB\\"),
Value::test_string("AC"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Export comma separated values inside braces (`{}`) to a string list.",
example: "\"{apple,banana,cherry}\" | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("apple"),
Value::test_string("banana"),
Value::test_string("cherry")
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "If the piped data is path, you may want to use --path flag, or else manually replace the backslashes with double backslashes.",
example: "'C:\\{Users,Windows}' | str expand --path",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("C:\\Users"),
Value::test_string("C:\\Windows"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Brace expressions can be used one after another.",
example: "\"A{b,c}D{e,f}G\" | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("AbDeG"),
Value::test_string("AbDfG"),
Value::test_string("AcDeG"),
Value::test_string("AcDfG"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Collection may include an empty item. It can be put at the start of the list.",
example: "\"A{,B,C}\" | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("A"),
Value::test_string("AB"),
Value::test_string("AC"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Empty item can be at the end of the collection.",
example: "\"A{B,C,}\" | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("AB"),
Value::test_string("AC"),
Value::test_string("A"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Empty item can be in the middle of the collection.",
example: "\"A{B,,C}\" | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("AB"),
Value::test_string("A"),
Value::test_string("AC"),
],
span: Span::test_data()
},)
Span::test_data()
)),
},
Example {
description: "Also, it is possible to use one inside another. Here is a real-world example, that creates files:",
example: "\"A{B{1,3},C{2,5}}D\" | str expand",
result: Some(Value::List{
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("AB1D"),
Value::test_string("AB3D"),
Value::test_string("AC2D"),
Value::test_string("AC5D"),
],
span: Span::test_data()
},)
Span::test_data()
)),
}
]
}
@ -203,14 +203,14 @@ impl Command for SubCommand {
let contents = if is_path { s.replace('\\', "\\\\") } else { s };
str_expand(&contents, span, v.span())
}
Err(_) => Value::Error {
error: Box::new(ShellError::PipelineMismatch {
Err(_) => Value::error(
ShellError::PipelineMismatch {
exp_input_type: "string".into(),
dst_span: span,
src_span: value_span,
}),
},
span,
},
),
}
},
engine_state.ctrlc.clone(),
@ -230,17 +230,17 @@ fn str_expand(contents: &str, span: Span, value_span: Span) -> Value {
Ok(node) => {
match expand(&node) {
Ok(possibilities) => {
Value::List { vals: possibilities.iter().map(|e| Value::string(e,span)).collect::<Vec<Value>>(), span }
Value::list(possibilities.iter().map(|e| Value::string(e,span)).collect::<Vec<Value>>(), span)
},
Err(e) => match e {
bracoxide::ExpansionError::NumConversionFailed(s) => Value::Error { error:
Box::new(ShellError::GenericError("Number Conversion Failed".to_owned(), format!("Number conversion failed at {s}."), Some(value_span), Some("Expected number, found text. Range format is `{M..N}`, where M and N are numeric values representing the starting and ending limits.".to_owned()), vec![])),
bracoxide::ExpansionError::NumConversionFailed(s) => Value::error(
ShellError::GenericError("Number Conversion Failed".to_owned(), format!("Number conversion failed at {s}."), Some(value_span), Some("Expected number, found text. Range format is `{M..N}`, where M and N are numeric values representing the starting and ending limits.".to_owned()), vec![]),
span,
},
),
},
}
},
Err(e) => Value::Error { error: Box::new(
Err(e) => Value::error(
match e {
ParsingError::NoTokens => ShellError::PipelineEmpty { dst_span: value_span },
ParsingError::OBraExpected(s) => ShellError::GenericError("Opening Brace Expected".to_owned(), format!("Opening brace is expected at {s}."), Some(value_span), Some("In brace syntax, we use equal amount of opening (`{`) and closing (`}`). Please, take a look at the examples.".to_owned()), vec![]),
@ -255,31 +255,31 @@ fn str_expand(contents: &str, span: Span, value_span: Span) -> Value {
ParsingError::ExtraOBra(s) => ShellError::GenericError("Extra Opening Brace".to_owned(), format!("Used extra opening brace at {s}."), Some(value_span), Some("To escape opening brace use backslash, e.g. `\\{`".to_owned()), vec![]),
ParsingError::NothingInBraces(s) => ShellError::GenericError("Nothing In Braces".to_owned(), format!("Nothing found inside braces at {s}."), Some(value_span), Some("Please provide valid content within the braces. Additionally, you can safely remove it, not needed.".to_owned()), vec![]),
}
),
,
span,
}
)
}
},
Err(e) => match e {
TokenizationError::EmptyContent => Value::Error {
error: Box::new(ShellError::PipelineEmpty { dst_span: value_span }),
span: value_span,
},
TokenizationError::FormatNotSupported => Value::Error {
error: Box::new(
TokenizationError::EmptyContent => Value::error(
ShellError::PipelineEmpty { dst_span: value_span },
value_span,
),
TokenizationError::FormatNotSupported => Value::error(
ShellError::GenericError(
"Format Not Supported".to_owned(),
"Usage of only `{` or `}`. Brace Expansion syntax, needs to have equal amount of opening (`{`) and closing (`}`)".to_owned(),
Some(value_span),
Some("In brace expansion syntax, it is important to have an equal number of opening (`{`) and closing (`}`) braces. Please ensure that you provide a balanced pair of braces in your brace expansion pattern.".to_owned()),
vec![]
)),
span: value_span,
},
TokenizationError::NoBraces => Value::Error {
error: Box::new(ShellError::GenericError("No Braces".to_owned(), "At least one `{}` brace expansion expected.".to_owned(), Some(value_span), Some("Please, examine the examples.".to_owned()), vec![])),
span: value_span,
}
),
value_span,
),
TokenizationError::NoBraces => Value::error(
ShellError::GenericError("No Braces".to_owned(), "At least one `{}` brace expansion expected.".to_owned(), Some(value_span), Some("Please, examine the examples.".to_owned()), vec![]),
value_span,
)
},
}
}
@ -292,51 +292,33 @@ mod tests {
fn dots() {
assert_eq!(
str_expand("{a.b.c,d}", Span::test_data(), Span::test_data()),
Value::List {
vals: vec![
Value::String {
val: String::from("a.b.c"),
span: Span::test_data(),
},
Value::String {
val: String::from("d"),
span: Span::test_data(),
},
Value::list(
vec![
Value::string(String::from("a.b.c"), Span::test_data(),),
Value::string(String::from("d"), Span::test_data(),)
],
span: Span::test_data(),
}
Span::test_data(),
)
);
assert_eq!(
str_expand("{1.2.3,a}", Span::test_data(), Span::test_data()),
Value::List {
vals: vec![
Value::String {
val: String::from("1.2.3"),
span: Span::test_data(),
},
Value::String {
val: String::from("a"),
span: Span::test_data(),
},
Value::list(
vec![
Value::string(String::from("1.2.3"), Span::test_data(),),
Value::string(String::from("a"), Span::test_data(),)
],
span: Span::test_data(),
}
Span::test_data(),
)
);
assert_eq!(
str_expand("{a-1.2,b}", Span::test_data(), Span::test_data()),
Value::List {
vals: vec![
Value::String {
val: String::from("a-1.2"),
span: Span::test_data(),
},
Value::String {
val: String::from("b"),
span: Span::test_data(),
},
Value::list(
vec![
Value::string(String::from("a-1.2"), Span::test_data(),),
Value::string(String::from("b"), Span::test_data(),)
],
span: Span::test_data(),
}
Span::test_data(),
)
);
}

View File

@ -161,10 +161,7 @@ fn action(
}
Err(processing_error) => {
let err = processing_error("could not find `index-of`", head);
return Value::Error {
error: Box::new(err),
span: head,
};
return Value::error(err, head);
}
}
} else {
@ -198,15 +195,15 @@ fn action(
}
}
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}
@ -262,17 +259,9 @@ mod tests {
fn returns_index_of_next_substring() {
let word = Value::test_string("Cargo.Cargo");
let range = Range {
from: Value::Int {
val: 1,
span: Span::test_data(),
},
incr: Value::Int {
val: 1,
span: Span::test_data(),
},
to: Value::Nothing {
span: Span::test_data(),
},
from: Value::int(1, Span::test_data()),
incr: Value::int(1, Span::test_data()),
to: Value::nothing(Span::test_data()),
inclusion: RangeInclusion::Inclusive,
};
@ -293,18 +282,10 @@ mod tests {
fn index_does_not_exist_due_to_end_index() {
let word = Value::test_string("Cargo.Banana");
let range = Range {
from: Value::Nothing {
span: Span::test_data(),
},
from: Value::nothing(Span::test_data()),
inclusion: RangeInclusion::Inclusive,
incr: Value::Int {
val: 1,
span: Span::test_data(),
},
to: Value::Int {
val: 5,
span: Span::test_data(),
},
incr: Value::int(1, Span::test_data()),
to: Value::int(5, Span::test_data()),
};
let options = Arguments {
@ -324,18 +305,9 @@ mod tests {
fn returns_index_of_nums_in_middle_due_to_index_limit_from_both_ends() {
let word = Value::test_string("123123123");
let range = Range {
from: Value::Int {
val: 2,
span: Span::test_data(),
},
incr: Value::Int {
val: 1,
span: Span::test_data(),
},
to: Value::Int {
val: 6,
span: Span::test_data(),
},
from: Value::int(2, Span::test_data()),
incr: Value::int(1, Span::test_data()),
to: Value::int(6, Span::test_data()),
inclusion: RangeInclusion::Inclusive,
};
@ -356,18 +328,9 @@ mod tests {
fn index_does_not_exists_due_to_strict_bounds() {
let word = Value::test_string("123456");
let range = Range {
from: Value::Int {
val: 2,
span: Span::test_data(),
},
incr: Value::Int {
val: 1,
span: Span::test_data(),
},
to: Value::Int {
val: 5,
span: Span::test_data(),
},
from: Value::int(2, Span::test_data()),
incr: Value::int(1, Span::test_data()),
to: Value::int(5, Span::test_data()),
inclusion: RangeInclusion::RightExclusive,
};
@ -386,10 +349,7 @@ mod tests {
#[test]
fn use_utf8_bytes() {
let word = Value::String {
val: String::from("🇯🇵ほげ ふが ぴよ"),
span: Span::test_data(),
};
let word = Value::string(String::from("🇯🇵ほげ ふが ぴよ"), Span::test_data());
let options = Arguments {
substring: String::from("ふが"),

View File

@ -70,11 +70,7 @@ impl Command for StrJoin {
strings.join("")
};
Ok(Value::String {
val: output,
span: call.head,
}
.into_pipeline_data())
Ok(Value::string(output, call.head).into_pipeline_data())
}
fn examples(&self) -> Vec<Example> {

View File

@ -102,10 +102,10 @@ impl Command for SubCommand {
Example {
description: "Return the lengths of multiple strings",
example: "['hi' 'there'] | str length",
result: Some(Value::List {
vals: vec![Value::test_int(2), Value::test_int(5)],
span: Span::test_data(),
}),
result: Some(Value::list(
vec![Value::test_int(2), Value::test_int(5)],
Span::test_data(),
)),
},
]
}
@ -135,15 +135,15 @@ fn action(input: &Value, arg: &Arguments, head: Span) -> Value {
head,
),
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}
@ -153,10 +153,7 @@ mod test {
#[test]
fn use_utf8_bytes() {
let word = Value::String {
val: String::from("🇯🇵ほげ ふが ぴよ"),
span: Span::test_data(),
};
let word = Value::string(String::from("🇯🇵ほげ ふが ぴよ"), Span::test_data());
let options = Arguments {
cell_paths: None,

View File

@ -149,8 +149,8 @@ impl Command for SubCommand {
description: "Find and replace all occurrences of find string in table using regular expression",
example:
"[[ColA ColB ColC]; [abc abc ads]] | str replace -ar 'b' 'z' ColA ColC",
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(), "ColC".to_string()],
vals: vec![
Value::test_string("azc"),
@ -158,8 +158,8 @@ impl Command for SubCommand {
Value::test_string("ads"),
],
})],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description: "Find and replace all occurrences of find string in record using regular expression",
@ -225,15 +225,9 @@ fn action(
if *no_regex {
// just use regular string replacement vs regular expressions
if *all {
Value::String {
val: val.replace(find_str, replace_str),
span: head,
}
Value::string(val.replace(find_str, replace_str), head)
} else {
Value::String {
val: val.replacen(find_str, replace_str, 1),
span: head,
}
Value::string(val.replacen(find_str, replace_str, 1), head)
}
} else {
// use regular expressions to replace strings
@ -247,50 +241,50 @@ fn action(
match regex {
Ok(re) => {
if *all {
Value::String {
val: {
Value::string(
{
if *literal_replace {
re.replace_all(val, NoExpand(replace_str)).to_string()
} else {
re.replace_all(val, replace_str).to_string()
}
},
span: head,
}
head,
)
} else {
Value::String {
val: {
Value::string(
{
if *literal_replace {
re.replace(val, NoExpand(replace_str)).to_string()
} else {
re.replace(val, replace_str).to_string()
}
},
span: head,
}
head,
)
}
}
Err(e) => Value::Error {
error: Box::new(ShellError::IncorrectValue {
Err(e) => Value::error(
ShellError::IncorrectValue {
msg: format!("Regex error: {e}"),
val_span: find.span,
call_span: head,
}),
span: find.span,
},
},
find.span,
),
}
}
}
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -64,14 +64,14 @@ impl Command for SubCommand {
Example {
description: "Reverse multiple strings in a list",
example: "['Nushell' 'is' 'cool'] | str reverse",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_string("llehsuN"),
Value::test_string("si"),
Value::test_string("looc"),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
@ -79,20 +79,17 @@ impl Command for SubCommand {
fn action(input: &Value, _arg: &CellPathOnlyArgs, head: Span) -> Value {
match input {
Value::String { val, .. } => Value::String {
val: val.chars().rev().collect::<String>(),
span: head,
},
Value::String { val, .. } => Value::string(val.chars().rev().collect::<String>(), head),
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -118,15 +118,15 @@ fn action(
Value::bool(starts_with, head)
}
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.span(),
}),
span: head,
},
},
head,
),
}
}

View File

@ -144,15 +144,15 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
if start < len && end >= 0 {
match start.cmp(&end) {
Ordering::Equal => Value::string("", head),
Ordering::Greater => Value::Error {
error: Box::new(ShellError::TypeMismatch {
Ordering::Greater => Value::error(
ShellError::TypeMismatch {
err_message: "End must be greater than or equal to Start".to_string(),
span: head,
}),
span: head,
},
Ordering::Less => Value::String {
val: {
},
head,
),
Ordering::Less => Value::string(
{
if end == isize::max_value() {
if args.graphemes {
s.graphemes(true)
@ -181,8 +181,8 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
.to_string()
}
},
span: head,
},
head,
),
}
} else {
Value::string("", head)
@ -190,16 +190,16 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: Box::new(ShellError::UnsupportedInput(
other => Value::error(
ShellError::UnsupportedInput(
"Only string values are supported".into(),
format!("input type: {:?}", other.get_type()),
head,
// This line requires the Value::Error match above.
other.span(),
)),
span: head,
},
),
head,
),
}
}
@ -279,10 +279,7 @@ mod tests {
#[test]
fn use_utf8_bytes() {
let word = Value::String {
val: String::from("🇯🇵ほげ ふが ぴよ"),
span: Span::test_data(),
};
let word = Value::string(String::from("🇯🇵ほげ ふが ぴよ"), Span::test_data());
let options = Arguments {
cell_paths: None,

View File

@ -172,48 +172,46 @@ fn action(input: &Value, arg: &Arguments, head: Span) -> Value {
let trim_side = &arg.trim_side;
let mode = &arg.mode;
match input {
Value::String { val: s, .. } => Value::String {
val: trim(s, char_, trim_side),
span: head,
},
Value::String { val: s, .. } => Value::string(trim(s, char_, trim_side), head),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => match mode {
ActionMode::Global => match other {
Value::Record { val: record, span } => {
let new_vals = record.vals.iter().map(|v| action(v, arg, head)).collect();
other => {
let span = other.span();
Value::record(
Record {
cols: record.cols.to_vec(),
vals: new_vals,
},
*span,
match mode {
ActionMode::Global => match other {
Value::Record { val: record, .. } => {
let new_vals = record.vals.iter().map(|v| action(v, arg, head)).collect();
Value::record(
Record {
cols: record.cols.to_vec(),
vals: new_vals,
},
span,
)
}
Value::List { vals, .. } => {
let new_vals = vals.iter().map(|v| action(v, arg, head)).collect();
Value::list(new_vals, span)
}
_ => input.clone(),
},
ActionMode::Local => {
Value::error(
ShellError::UnsupportedInput(
"Only string values are supported".into(),
format!("input type: {:?}", other.get_type()),
head,
// This line requires the Value::Error match above.
other.span(),
),
head,
)
}
Value::List { vals, span } => {
let new_vals = vals.iter().map(|v| action(v, arg, head)).collect();
Value::List {
vals: new_vals,
span: *span,
}
}
_ => input.clone(),
},
ActionMode::Local => {
Value::Error {
error: Box::new(ShellError::UnsupportedInput(
"Only string values are supported".into(),
format!("input type: {:?}", other.get_type()),
head,
// This line requires the Value::Error match above.
other.span(),
)),
span: head,
}
}
},
}
}
}
@ -261,13 +259,12 @@ mod tests {
}
fn make_list(vals: Vec<&str>) -> Value {
Value::List {
vals: vals
.iter()
Value::list(
vals.iter()
.map(|x| Value::test_string(x.to_string()))
.collect(),
span: Span::test_data(),
}
Span::test_data(),
)
}
#[test]
@ -422,22 +419,22 @@ mod tests {
#[test]
fn global_trim_left_table() {
let row = Value::List {
vals: vec![
let row = Value::list(
vec![
Value::test_string(" a "),
Value::test_int(65),
Value::test_string(" d"),
],
span: Span::test_data(),
};
let expected = Value::List {
vals: vec![
Span::test_data(),
);
let expected = Value::list(
vec![
Value::test_string("a "),
Value::test_int(65),
Value::test_string("d"),
],
span: Span::test_data(),
};
Span::test_data(),
);
let args = Arguments {
to_trim: None,
@ -522,22 +519,22 @@ mod tests {
#[test]
fn global_trim_right_table() {
let row = Value::List {
vals: vec![
let row = Value::list(
vec![
Value::test_string(" a "),
Value::test_int(65),
Value::test_string(" d"),
],
span: Span::test_data(),
};
let expected = Value::List {
vals: vec![
Span::test_data(),
);
let expected = Value::list(
vec![
Value::test_string(" a"),
Value::test_int(65),
Value::test_string(" d"),
],
span: Span::test_data(),
};
Span::test_data(),
);
let args = Arguments {
to_trim: None,
trim_side: TrimSide::Right,