mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 06:55:36 +02:00
Move Value to helpers, separate span call (#10121)
# Description As part of the refactor to split spans off of Value, this moves to using helper functions to create values, and using `.span()` instead of matching span out of Value directly. Hoping to get a few more helping hands to finish this, as there are a lot of commands to update :) # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --> --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: WindSoilder <windsoilder@outlook.com>
This commit is contained in:
@ -91,56 +91,50 @@ impl Command for BytesAdd {
|
||||
Example {
|
||||
description: "Add bytes `0x[AA]` to `0x[1F FF AA AA]`",
|
||||
example: "0x[1F FF AA AA] | bytes add 0x[AA]",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xAA, 0x1F, 0xFF, 0xAA, 0xAA],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0xAA, 0x1F, 0xFF, 0xAA, 0xAA],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Add bytes `0x[AA BB]` to `0x[1F FF AA AA]` at index 1",
|
||||
example: "0x[1F FF AA AA] | bytes add 0x[AA BB] -i 1",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x1F, 0xAA, 0xBB, 0xFF, 0xAA, 0xAA],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0x1F, 0xAA, 0xBB, 0xFF, 0xAA, 0xAA],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Add bytes `0x[11]` to `0x[FF AA AA]` at the end",
|
||||
example: "0x[FF AA AA] | bytes add 0x[11] -e",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xFF, 0xAA, 0xAA, 0x11],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0xFF, 0xAA, 0xAA, 0x11],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Add bytes `0x[11 22 33]` to `0x[FF AA AA]` at the end, at index 1(the index is start from end)",
|
||||
example: "0x[FF AA BB] | bytes add 0x[11 22 33] -e -i 1",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xFF, 0xAA, 0x11, 0x22, 0x33, 0xBB],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0xFF, 0xAA, 0x11, 0x22, 0x33, 0xBB],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn add(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => add_impl(val, args, *val_span),
|
||||
Value::Binary { val, .. } => add_impl(val, args, val_span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,12 +145,12 @@ fn add_impl(input: &[u8], args: &Arguments, span: Span) -> Value {
|
||||
let mut added_data = args.added_data.clone();
|
||||
let mut result = input.to_vec();
|
||||
result.append(&mut added_data);
|
||||
Value::Binary { val: result, span }
|
||||
Value::binary(result, span)
|
||||
} else {
|
||||
let mut result = args.added_data.clone();
|
||||
let mut input = input.to_vec();
|
||||
result.append(&mut input);
|
||||
Value::Binary { val: result, span }
|
||||
Value::binary(result, span)
|
||||
}
|
||||
}
|
||||
Some(mut indx) => {
|
||||
@ -175,7 +169,7 @@ fn add_impl(input: &[u8], args: &Arguments, span: Span) -> Value {
|
||||
result.append(&mut added_data);
|
||||
let mut after_data = input[inserted_index..].to_vec();
|
||||
result.append(&mut after_data);
|
||||
Value::Binary { val: result, span }
|
||||
Value::binary(result, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,18 +94,12 @@ impl Command for BytesAt {
|
||||
Example {
|
||||
description: "Get a subbytes `0x[10 01]` from the bytes `0x[33 44 55 10 01 13]`",
|
||||
example: " 0x[33 44 55 10 01 13] | bytes at 3..<4",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x10],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0x10], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Get a subbytes `0x[10 01 13]` from the bytes `0x[33 44 55 10 01 13]`",
|
||||
example: " 0x[33 44 55 10 01 13] | bytes at 3..6",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x10, 0x01, 0x13],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0x10, 0x01, 0x13], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Get the remaining characters from a starting index",
|
||||
@ -118,35 +112,26 @@ impl Command for BytesAt {
|
||||
Example {
|
||||
description: "Get the characters from the beginning until ending index",
|
||||
example: " 0x[33 44 55 10 01 13] | bytes at ..<4",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x33, 0x44, 0x55, 0x10],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(
|
||||
vec![0x33, 0x44, 0x55, 0x10],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Or the characters from the beginning until ending index inside a table",
|
||||
example: r#" [[ColA ColB ColC]; [0x[11 12 13] 0x[14 15 16] 0x[17 18 19]]] | bytes at 1.. ColB 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::Binary {
|
||||
val: vec![0x11, 0x12, 0x13],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Binary {
|
||||
val: vec![0x15, 0x16],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Binary {
|
||||
val: vec![0x18, 0x19],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::binary(vec![0x11, 0x12, 0x13], Span::test_data()),
|
||||
Value::binary(vec![0x15, 0x16], Span::test_data()),
|
||||
Value::binary(vec![0x18, 0x19], Span::test_data()),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -169,51 +154,46 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
|
||||
if start < len && end >= 0 {
|
||||
match start.cmp(&end) {
|
||||
Ordering::Equal => Value::Binary {
|
||||
val: vec![],
|
||||
span: head,
|
||||
},
|
||||
Ordering::Greater => Value::Error {
|
||||
error: Box::new(ShellError::TypeMismatch {
|
||||
Ordering::Equal => Value::binary(vec![], head),
|
||||
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::Binary {
|
||||
val: {
|
||||
if end == isize::max_value() {
|
||||
val.iter().skip(start as usize).copied().collect()
|
||||
} else {
|
||||
val.iter()
|
||||
.skip(start as usize)
|
||||
.take((end - start) as usize)
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
span: head,
|
||||
},
|
||||
head,
|
||||
),
|
||||
Ordering::Less => Value::binary(
|
||||
if end == isize::max_value() {
|
||||
val.iter()
|
||||
.skip(start as usize)
|
||||
.copied()
|
||||
.collect::<Vec<u8>>()
|
||||
} else {
|
||||
val.iter()
|
||||
.skip(start as usize)
|
||||
.take((end - start) as usize)
|
||||
.copied()
|
||||
.collect()
|
||||
},
|
||||
head,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
Value::Binary {
|
||||
val: vec![],
|
||||
span: head,
|
||||
}
|
||||
Value::binary(vec![], head)
|
||||
}
|
||||
}
|
||||
|
||||
Value::Error { .. } => input.clone(),
|
||||
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
other => Value::error(
|
||||
ShellError::UnsupportedInput(
|
||||
"Only binary values are supported".into(),
|
||||
format!("input type: {:?}", other.get_type()),
|
||||
head,
|
||||
// This line requires the Value::Error match above.
|
||||
other.span(),
|
||||
)),
|
||||
span: head,
|
||||
},
|
||||
),
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ impl Command for BytesBuild {
|
||||
vec![Example {
|
||||
example: "bytes build 0x[01 02] 0x[03] 0x[04]",
|
||||
description: "Builds binary data from 0x[01 02], 0x[03], 0x[04]",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x01, 0x02, 0x03, 0x04],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(
|
||||
vec![0x01, 0x02, 0x03, 0x04],
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -63,11 +63,7 @@ impl Command for BytesBuild {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Binary {
|
||||
val: output,
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::binary(output, call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,16 +34,16 @@ impl Command for Bytes {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&Bytes.signature(),
|
||||
&Bytes.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -68,28 +68,16 @@ impl Command for BytesCollect {
|
||||
}
|
||||
|
||||
match separator {
|
||||
None => Ok(Value::Binary {
|
||||
val: output_binary,
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
None => Ok(Value::binary(output_binary, call.head).into_pipeline_data()),
|
||||
Some(sep) => {
|
||||
if output_binary.is_empty() {
|
||||
Ok(Value::Binary {
|
||||
val: output_binary,
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::binary(output_binary, call.head).into_pipeline_data())
|
||||
} else {
|
||||
// have push one extra separator in previous step, pop them out.
|
||||
for _ in sep {
|
||||
let _ = output_binary.pop();
|
||||
}
|
||||
Ok(Value::Binary {
|
||||
val: output_binary,
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::binary(output_binary, call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,18 +88,15 @@ impl Command for BytesCollect {
|
||||
Example {
|
||||
description: "Create a byte array from input",
|
||||
example: "[0x[11] 0x[13 15]] | bytes collect",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x11, 0x13, 0x15],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0x11, 0x13, 0x15], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Create a byte array from input with a separator",
|
||||
example: "[0x[11] 0x[33] 0x[44]] | bytes collect 0x[01]",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x11, 0x01, 0x33, 0x01, 0x44],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(
|
||||
vec![0x11, 0x01, 0x33, 0x01, 0x44],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -89,22 +89,20 @@ impl Command for BytesEndsWith {
|
||||
}
|
||||
|
||||
fn ends_with(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => Value::bool(val.ends_with(&args.pattern), *val_span),
|
||||
Value::Binary { val, .. } => Value::bool(val.ends_with(&args.pattern), val_span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,58 +95,53 @@ impl Command for BytesIndexOf {
|
||||
Example {
|
||||
description: "Returns all matched index",
|
||||
example: " 0x[33 44 55 10 01 33 44 33 44] | bytes index-of -a 0x[33 44]",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(5), Value::test_int(7)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(5), Value::test_int(7)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Returns all matched index, searching from end",
|
||||
example: " 0x[33 44 55 10 01 33 44 33 44] | bytes index-of -a -e 0x[33 44]",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(7), Value::test_int(5), Value::test_int(0)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(7), Value::test_int(5), Value::test_int(0)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Returns index of pattern for specific column",
|
||||
example: r#" [[ColA ColB ColC]; [0x[11 12 13] 0x[14 15 16] 0x[17 18 19]]] | bytes index-of 0x[11] 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_int(0),
|
||||
Value::Binary {
|
||||
val: vec![0x14, 0x15, 0x16],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::binary(vec![0x14, 0x15, 0x16], Span::test_data()),
|
||||
Value::test_int(-1),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn index_of(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => index_of_impl(val, args, *val_span),
|
||||
Value::Binary { val, .. } => index_of_impl(val, args, val_span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,22 +152,20 @@ fn index_of_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
|
||||
let mut iter = input.windows(arg.pattern.len());
|
||||
|
||||
if arg.end {
|
||||
Value::Int {
|
||||
val: iter
|
||||
.rev()
|
||||
Value::int(
|
||||
iter.rev()
|
||||
.position(|sub_bytes| sub_bytes == arg.pattern)
|
||||
.map(|x| (input.len() - arg.pattern.len() - x) as i64)
|
||||
.unwrap_or(-1),
|
||||
span,
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Value::Int {
|
||||
val: iter
|
||||
.position(|sub_bytes| sub_bytes == arg.pattern)
|
||||
Value::int(
|
||||
iter.position(|sub_bytes| sub_bytes == arg.pattern)
|
||||
.map(|x| x as i64)
|
||||
.unwrap_or(-1),
|
||||
span,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -186,10 +179,7 @@ fn search_all_index(input: &[u8], pattern: &[u8], from_end: bool, span: Span) ->
|
||||
);
|
||||
while left >= 0 {
|
||||
if &input[left as usize..right as usize] == pattern {
|
||||
result.push(Value::Int {
|
||||
val: left as i64,
|
||||
span,
|
||||
});
|
||||
result.push(Value::int(left as i64, span));
|
||||
left -= pattern.len() as isize;
|
||||
right -= pattern.len() as isize;
|
||||
} else {
|
||||
@ -197,7 +187,7 @@ fn search_all_index(input: &[u8], pattern: &[u8], from_end: bool, span: Span) ->
|
||||
right -= 1;
|
||||
}
|
||||
}
|
||||
Value::List { vals: result, span }
|
||||
Value::list(result, span)
|
||||
} else {
|
||||
// doing find stuff.
|
||||
let (mut left, mut right) = (0, pattern.len());
|
||||
@ -205,10 +195,7 @@ fn search_all_index(input: &[u8], pattern: &[u8], from_end: bool, span: Span) ->
|
||||
let pattern_len = pattern.len();
|
||||
while right <= input_len {
|
||||
if &input[left..right] == pattern {
|
||||
result.push(Value::Int {
|
||||
val: left as i64,
|
||||
span,
|
||||
});
|
||||
result.push(Value::int(left as i64, span));
|
||||
left += pattern_len;
|
||||
right += pattern_len;
|
||||
} else {
|
||||
@ -217,7 +204,7 @@ fn search_all_index(input: &[u8], pattern: &[u8], from_end: bool, span: Span) ->
|
||||
}
|
||||
}
|
||||
|
||||
Value::List { vals: result, span }
|
||||
Value::list(result, span)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,32 +64,30 @@ impl Command for BytesLen {
|
||||
Example {
|
||||
description: "Return the lengths of multiple binaries",
|
||||
example: "[0x[1F FF AA AB] 0x[1F]] | bytes length",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn length(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => Value::int(val.len() as i64, *val_span),
|
||||
Value::Binary { val, .. } => Value::int(val.len() as i64, val_span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,10 +87,10 @@ impl Command for BytesRemove {
|
||||
Example {
|
||||
description: "Remove contents",
|
||||
example: "0x[10 AA FF AA FF] | bytes remove 0x[10 AA]",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xFF, 0xAA, 0xFF],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary (
|
||||
vec![0xFF, 0xAA, 0xFF],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Remove all occurrences of find binary in record field",
|
||||
@ -103,56 +103,54 @@ impl Command for BytesRemove {
|
||||
Example {
|
||||
description: "Remove occurrences of find binary from end",
|
||||
example: "0x[10 AA 10 BB CC AA 10] | bytes remove -e 0x[10]",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x10, 0xAA, 0x10, 0xBB, 0xCC, 0xAA],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary (
|
||||
vec![0x10, 0xAA, 0x10, 0xBB, 0xCC, 0xAA],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Remove all occurrences of find binary in table",
|
||||
example: "[[ColA ColB ColC]; [0x[11 12 13] 0x[14 15 16] 0x[17 18 19]]] | bytes remove 0x[11] 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::Binary {
|
||||
val: vec![0x12, 0x13],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Binary {
|
||||
val: vec![0x14, 0x15, 0x16],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Binary {
|
||||
val: vec![0x17, 0x18, 0x19],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::binary (
|
||||
vec![0x12, 0x13],
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::binary (
|
||||
vec![0x14, 0x15, 0x16],
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::binary (
|
||||
vec![0x17, 0x18, 0x19],
|
||||
Span::test_data(),
|
||||
),
|
||||
]
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn remove(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => remove_impl(val, args, *val_span),
|
||||
Value::Binary { val, .. } => remove_impl(val, args, val_span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +178,7 @@ fn remove_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
|
||||
let mut remain = input[..left as usize].iter().copied().rev().collect();
|
||||
result.append(&mut remain);
|
||||
result = result.into_iter().rev().collect();
|
||||
Value::Binary { val: result, span }
|
||||
Value::binary(result, span)
|
||||
} else {
|
||||
let (mut left, mut right) = (0, arg.pattern.len());
|
||||
while right <= input_len {
|
||||
@ -200,7 +198,7 @@ fn remove_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
|
||||
// we have something to remove and remove_all is False.
|
||||
let mut remain = input[left..].to_vec();
|
||||
result.append(&mut remain);
|
||||
Value::Binary { val: result, span }
|
||||
Value::binary(result, span)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,64 +87,62 @@ impl Command for BytesReplace {
|
||||
Example {
|
||||
description: "Find and replace contents",
|
||||
example: "0x[10 AA FF AA FF] | bytes replace 0x[10 AA] 0x[FF]",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xFF, 0xFF, 0xAA, 0xFF],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary (
|
||||
vec![0xFF, 0xFF, 0xAA, 0xFF],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find and replace all occurrences of find binary",
|
||||
example: "0x[10 AA 10 BB 10] | bytes replace -a 0x[10] 0x[A0]",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xA0, 0xAA, 0xA0, 0xBB, 0xA0],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary (
|
||||
vec![0xA0, 0xAA, 0xA0, 0xBB, 0xA0],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find and replace all occurrences of find binary in table",
|
||||
example: "[[ColA ColB ColC]; [0x[11 12 13] 0x[14 15 16] 0x[17 18 19]]] | bytes replace -a 0x[11] 0x[13] 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::Binary {
|
||||
val: vec![0x13, 0x12, 0x13],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Binary {
|
||||
val: vec![0x14, 0x15, 0x16],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Binary {
|
||||
val: vec![0x17, 0x18, 0x19],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::binary (
|
||||
vec![0x13, 0x12, 0x13],
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::binary (
|
||||
vec![0x14, 0x15, 0x16],
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::binary (
|
||||
vec![0x17, 0x18, 0x19],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn replace(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => replace_impl(val, args, *val_span),
|
||||
Value::Binary { val, .. } => replace_impl(val, args, val_span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,10 +172,7 @@ fn replace_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
|
||||
|
||||
let mut remain = input[left..].to_vec();
|
||||
replaced.append(&mut remain);
|
||||
Value::Binary {
|
||||
val: replaced,
|
||||
span,
|
||||
}
|
||||
Value::binary(replaced, span)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -56,47 +56,39 @@ impl Command for BytesReverse {
|
||||
Example {
|
||||
description: "Reverse bytes `0x[1F FF AA AA]`",
|
||||
example: "0x[1F FF AA AA] | bytes reverse",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xAA, 0xAA, 0xFF, 0x1F],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(
|
||||
vec![0xAA, 0xAA, 0xFF, 0x1F],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Reverse bytes `0x[FF AA AA]`",
|
||||
example: "0x[FF AA AA] | bytes reverse",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0xAA, 0xAA, 0xFF],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0xAA, 0xAA, 0xFF], Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn reverse(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => {
|
||||
Value::Binary { val, .. } => {
|
||||
let mut reversed_input = val.to_vec();
|
||||
reversed_input.reverse();
|
||||
Value::Binary {
|
||||
val: reversed_input,
|
||||
span: *val_span,
|
||||
}
|
||||
Value::binary(reversed_input, val_span)
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,15 +84,15 @@ impl Command for BytesStartsWith {
|
||||
Ok(v @ Value::Error { .. }) => return Ok(v.clone().into_pipeline_data()),
|
||||
// Unsupported data
|
||||
Ok(other) => {
|
||||
return Ok(Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
return Ok(Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string and binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
.into_pipeline_data());
|
||||
}
|
||||
Err(err) => return Err(err.to_owned()),
|
||||
@ -147,22 +147,20 @@ impl Command for BytesStartsWith {
|
||||
}
|
||||
|
||||
fn starts_with(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => Value::bool(val.starts_with(&args.pattern), *val_span),
|
||||
Value::Binary { val, .. } => Value::bool(val.starts_with(&args.pattern), val_span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => val.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,18 +65,40 @@ impl HashableValue {
|
||||
///
|
||||
/// If the given value is not hashable(mainly because of it is structured data), an error will returned.
|
||||
pub fn from_value(value: Value, span: Span) -> Result<Self, ShellError> {
|
||||
let val_span = value.span();
|
||||
match value {
|
||||
Value::Bool { val, span } => Ok(HashableValue::Bool { val, span }),
|
||||
Value::Int { val, span } => Ok(HashableValue::Int { val, span }),
|
||||
Value::Filesize { val, span } => Ok(HashableValue::Filesize { val, span }),
|
||||
Value::Duration { val, span } => Ok(HashableValue::Duration { val, span }),
|
||||
Value::Date { val, span } => Ok(HashableValue::Date { val, span }),
|
||||
Value::Float { val, span } => Ok(HashableValue::Float {
|
||||
val: val.to_ne_bytes(),
|
||||
span,
|
||||
Value::Bool { val, .. } => Ok(HashableValue::Bool {
|
||||
val,
|
||||
span: val_span,
|
||||
}),
|
||||
Value::Int { val, .. } => Ok(HashableValue::Int {
|
||||
val,
|
||||
span: val_span,
|
||||
}),
|
||||
Value::Filesize { val, .. } => Ok(HashableValue::Filesize {
|
||||
val,
|
||||
span: val_span,
|
||||
}),
|
||||
Value::Duration { val, .. } => Ok(HashableValue::Duration {
|
||||
val,
|
||||
span: val_span,
|
||||
}),
|
||||
Value::Date { val, .. } => Ok(HashableValue::Date {
|
||||
val,
|
||||
span: val_span,
|
||||
}),
|
||||
Value::Float { val, .. } => Ok(HashableValue::Float {
|
||||
val: val.to_ne_bytes(),
|
||||
span: val_span,
|
||||
}),
|
||||
Value::String { val, .. } => Ok(HashableValue::String {
|
||||
val,
|
||||
span: val_span,
|
||||
}),
|
||||
Value::Binary { val, .. } => Ok(HashableValue::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
}),
|
||||
Value::String { val, span } => Ok(HashableValue::String { val, span }),
|
||||
Value::Binary { val, span } => Ok(HashableValue::Binary { val, span }),
|
||||
|
||||
// Explicitly propagate errors instead of dropping them.
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
@ -92,17 +114,14 @@ impl HashableValue {
|
||||
/// Convert from self to nu's core data type `Value`.
|
||||
pub fn into_value(self) -> Value {
|
||||
match self {
|
||||
HashableValue::Bool { val, span } => Value::Bool { val, span },
|
||||
HashableValue::Int { val, span } => Value::Int { val, span },
|
||||
HashableValue::Filesize { val, span } => Value::Filesize { val, span },
|
||||
HashableValue::Duration { val, span } => Value::Duration { val, span },
|
||||
HashableValue::Date { val, span } => Value::Date { val, span },
|
||||
HashableValue::Float { val, span } => Value::Float {
|
||||
val: f64::from_ne_bytes(val),
|
||||
span,
|
||||
},
|
||||
HashableValue::String { val, span } => Value::String { val, span },
|
||||
HashableValue::Binary { val, span } => Value::Binary { val, span },
|
||||
HashableValue::Bool { val, span } => Value::bool(val, span),
|
||||
HashableValue::Int { val, span } => Value::int(val, span),
|
||||
HashableValue::Filesize { val, span } => Value::filesize(val, span),
|
||||
HashableValue::Duration { val, span } => Value::duration(val, span),
|
||||
HashableValue::Date { val, span } => Value::date(val, span),
|
||||
HashableValue::Float { val, span } => Value::float(f64::from_ne_bytes(val), span),
|
||||
HashableValue::String { val, span } => Value::string(val, span),
|
||||
HashableValue::Binary { val, span } => Value::binary(val, span),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -167,29 +186,24 @@ mod test {
|
||||
let span = Span::test_data();
|
||||
let values = vec![
|
||||
(
|
||||
Value::Bool { val: true, span },
|
||||
Value::bool(true, span),
|
||||
HashableValue::Bool { val: true, span },
|
||||
),
|
||||
(Value::int(1, span), HashableValue::Int { val: 1, span }),
|
||||
(
|
||||
Value::Int { val: 1, span },
|
||||
HashableValue::Int { val: 1, span },
|
||||
),
|
||||
(
|
||||
Value::Filesize { val: 1, span },
|
||||
Value::filesize(1, span),
|
||||
HashableValue::Filesize { val: 1, span },
|
||||
),
|
||||
(
|
||||
Value::Duration { val: 1, span },
|
||||
Value::duration(1, span),
|
||||
HashableValue::Duration { val: 1, span },
|
||||
),
|
||||
(
|
||||
Value::Date {
|
||||
val: DateTime::<FixedOffset>::parse_from_rfc2822(
|
||||
"Wed, 18 Feb 2015 23:16:09 GMT",
|
||||
)
|
||||
.unwrap(),
|
||||
Value::date(
|
||||
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT")
|
||||
.unwrap(),
|
||||
span,
|
||||
},
|
||||
),
|
||||
HashableValue::Date {
|
||||
val: DateTime::<FixedOffset>::parse_from_rfc2822(
|
||||
"Wed, 18 Feb 2015 23:16:09 GMT",
|
||||
@ -199,17 +213,14 @@ mod test {
|
||||
},
|
||||
),
|
||||
(
|
||||
Value::String {
|
||||
val: "1".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::string("1".to_string(), span),
|
||||
HashableValue::String {
|
||||
val: "1".to_string(),
|
||||
span,
|
||||
},
|
||||
),
|
||||
(
|
||||
Value::Binary { val: vec![1], span },
|
||||
Value::binary(vec![1], span),
|
||||
HashableValue::Binary { val: vec![1], span },
|
||||
),
|
||||
];
|
||||
@ -225,22 +236,12 @@ mod test {
|
||||
fn from_unhashable_value() {
|
||||
let span = Span::test_data();
|
||||
let values = [
|
||||
Value::List {
|
||||
vals: vec![Value::Bool { val: true, span }],
|
||||
span,
|
||||
},
|
||||
Value::Closure {
|
||||
val: 0,
|
||||
captures: HashMap::new(),
|
||||
span,
|
||||
},
|
||||
Value::Nothing { span },
|
||||
Value::Error {
|
||||
error: Box::new(ShellError::DidYouMean("what?".to_string(), span)),
|
||||
span,
|
||||
},
|
||||
Value::CellPath {
|
||||
val: CellPath {
|
||||
Value::list(vec![Value::bool(true, span)], span),
|
||||
Value::closure(0, HashMap::new(), span),
|
||||
Value::nothing(span),
|
||||
Value::error(ShellError::DidYouMean("what?".to_string(), span), span),
|
||||
Value::cell_path(
|
||||
CellPath {
|
||||
members: vec![PathMember::Int {
|
||||
val: 0,
|
||||
span,
|
||||
@ -248,7 +249,7 @@ mod test {
|
||||
}],
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
];
|
||||
for v in values {
|
||||
assert!(HashableValue::from_value(v, Span::unknown()).is_err())
|
||||
@ -259,15 +260,12 @@ mod test {
|
||||
fn from_to_tobe_same() {
|
||||
let span = Span::test_data();
|
||||
let values = vec![
|
||||
Value::Bool { val: true, span },
|
||||
Value::Int { val: 1, span },
|
||||
Value::Filesize { val: 1, span },
|
||||
Value::Duration { val: 1, span },
|
||||
Value::String {
|
||||
val: "1".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::Binary { val: vec![1], span },
|
||||
Value::bool(true, span),
|
||||
Value::int(1, span),
|
||||
Value::filesize(1, span),
|
||||
Value::duration(1, span),
|
||||
Value::string("1".to_string(), span),
|
||||
Value::binary(vec![1], span),
|
||||
];
|
||||
for val in values.into_iter() {
|
||||
let expected_val = val.clone();
|
||||
|
@ -51,8 +51,8 @@ impl Command for Histogram {
|
||||
Example {
|
||||
description: "Compute a histogram for a list of numbers",
|
||||
example: "[1 2 1] | histogram",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list (
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["value".to_string(), "count".to_string(), "quantile".to_string(), "percentage".to_string(), "frequency".to_string()],
|
||||
vals: vec![
|
||||
Value::test_int(1),
|
||||
@ -72,8 +72,8 @@ impl Command for Histogram {
|
||||
Value::test_string("*********************************"),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}
|
||||
Span::test_data(),
|
||||
)
|
||||
),
|
||||
},
|
||||
Example {
|
||||
@ -274,16 +274,10 @@ fn histogram_impl(
|
||||
cols: result_cols.clone(),
|
||||
vals: vec![
|
||||
val.into_value(),
|
||||
Value::Int { val: count, span },
|
||||
Value::Float {
|
||||
val: quantile,
|
||||
span,
|
||||
},
|
||||
Value::String {
|
||||
val: percentage,
|
||||
span,
|
||||
},
|
||||
Value::String { val: freq, span },
|
||||
Value::int(count, span),
|
||||
Value::float(quantile, span),
|
||||
Value::string(percentage, span),
|
||||
Value::string(freq, span),
|
||||
],
|
||||
},
|
||||
span,
|
||||
@ -291,11 +285,7 @@ fn histogram_impl(
|
||||
));
|
||||
}
|
||||
result.sort_by(|a, b| b.0.cmp(&a.0));
|
||||
Value::List {
|
||||
vals: result.into_iter().map(|x| x.1).collect(),
|
||||
span,
|
||||
}
|
||||
.into_pipeline_data()
|
||||
Value::list(result.into_iter().map(|x| x.1).collect(), span).into_pipeline_data()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -86,53 +86,35 @@ impl Command for Fill {
|
||||
description:
|
||||
"Fill a string on the left side to a width of 15 with the character '─'",
|
||||
example: "'nushell' | fill -a l -c '─' -w 15",
|
||||
result: Some(Value::String {
|
||||
val: "nushell────────".into(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("nushell────────", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Fill a string on the right side to a width of 15 with the character '─'",
|
||||
example: "'nushell' | fill -a r -c '─' -w 15",
|
||||
result: Some(Value::String {
|
||||
val: "────────nushell".into(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("────────nushell", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Fill a string on both sides to a width of 15 with the character '─'",
|
||||
example: "'nushell' | fill -a m -c '─' -w 15",
|
||||
result: Some(Value::String {
|
||||
val: "────nushell────".into(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("────nushell────", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Fill a number on the left side to a width of 5 with the character '0'",
|
||||
example: "1 | fill --alignment right --character '0' --width 5",
|
||||
result: Some(Value::String {
|
||||
val: "00001".into(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("00001", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Fill a number on both sides to a width of 5 with the character '0'",
|
||||
example: "1.1 | fill --alignment center --character '0' --width 5",
|
||||
result: Some(Value::String {
|
||||
val: "01.10".into(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("01.10", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Fill a filesize on the left side to a width of 5 with the character '0'",
|
||||
example: "1kib | fill --alignment middle --character '0' --width 10",
|
||||
result: Some(Value::String {
|
||||
val: "0001024000".into(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("0001024000", Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -198,15 +180,15 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
Value::String { val, .. } => fill_string(val, args, span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "int, filesize, float, string".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,18 +196,18 @@ fn fill_float(num: f64, args: &Arguments, span: Span) -> Value {
|
||||
let s = num.to_string();
|
||||
let out_str = pad(&s, args.width, &args.character, args.alignment, false);
|
||||
|
||||
Value::String { val: out_str, span }
|
||||
Value::string(out_str, span)
|
||||
}
|
||||
fn fill_int(num: i64, args: &Arguments, span: Span) -> Value {
|
||||
let s = num.to_string();
|
||||
let out_str = pad(&s, args.width, &args.character, args.alignment, false);
|
||||
|
||||
Value::String { val: out_str, span }
|
||||
Value::string(out_str, span)
|
||||
}
|
||||
fn fill_string(s: &str, args: &Arguments, span: Span) -> Value {
|
||||
let out_str = pad(s, args.width, &args.character, args.alignment, false);
|
||||
|
||||
Value::String { val: out_str, span }
|
||||
Value::string(out_str, span)
|
||||
}
|
||||
|
||||
fn pad(s: &str, width: usize, pad_char: &str, alignment: FillAlignment, truncate: bool) -> String {
|
||||
|
@ -72,29 +72,29 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "convert string to a nushell binary primitive",
|
||||
example: "'This is a string that is exactly 52 characters long.' | into binary",
|
||||
result: Some(Value::Binary {
|
||||
val: "This is a string that is exactly 52 characters long."
|
||||
result: Some(Value::binary(
|
||||
"This is a string that is exactly 52 characters long."
|
||||
.to_string()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a number to a nushell binary primitive",
|
||||
example: "1 | into binary",
|
||||
result: Some(Value::Binary {
|
||||
val: i64::from(1).to_ne_bytes().to_vec(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(
|
||||
i64::from(1).to_ne_bytes().to_vec(),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a boolean to a nushell binary primitive",
|
||||
example: "true | into binary",
|
||||
result: Some(Value::Binary {
|
||||
val: i64::from(1).to_ne_bytes().to_vec(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(
|
||||
i64::from(1).to_ne_bytes().to_vec(),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a filesize to a nushell binary primitive",
|
||||
@ -109,19 +109,16 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "convert a decimal to a nushell binary primitive",
|
||||
example: "1.234 | into binary",
|
||||
result: Some(Value::Binary {
|
||||
val: 1.234f64.to_ne_bytes().to_vec(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(
|
||||
1.234f64.to_ne_bytes().to_vec(),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"convert an integer to a nushell binary primitive with compact enabled",
|
||||
example: "10 | into binary --compact",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![10],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![10], Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -138,22 +135,16 @@ fn into_binary(
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
|
||||
match input {
|
||||
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
|
||||
val: vec![],
|
||||
span: head,
|
||||
PipelineData::ExternalStream { stdout: None, .. } => {
|
||||
Ok(Value::binary(vec![], head).into_pipeline_data())
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
PipelineData::ExternalStream {
|
||||
stdout: Some(stream),
|
||||
..
|
||||
} => {
|
||||
// TODO: in the future, we may want this to stream out, converting each to bytes
|
||||
let output = stream.into_bytes()?;
|
||||
Ok(Value::Binary {
|
||||
val: output.item,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::binary(output.item, head).into_pipeline_data())
|
||||
}
|
||||
_ => {
|
||||
let args = Arguments {
|
||||
@ -168,50 +159,32 @@ fn into_binary(
|
||||
pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
|
||||
let value = match input {
|
||||
Value::Binary { .. } => input.clone(),
|
||||
Value::Int { val, .. } => Value::Binary {
|
||||
val: val.to_ne_bytes().to_vec(),
|
||||
span,
|
||||
},
|
||||
Value::Float { val, .. } => Value::Binary {
|
||||
val: val.to_ne_bytes().to_vec(),
|
||||
span,
|
||||
},
|
||||
Value::Filesize { val, .. } => Value::Binary {
|
||||
val: val.to_ne_bytes().to_vec(),
|
||||
span,
|
||||
},
|
||||
Value::String { val, .. } => Value::Binary {
|
||||
val: val.as_bytes().to_vec(),
|
||||
span,
|
||||
},
|
||||
Value::Bool { val, .. } => Value::Binary {
|
||||
val: i64::from(*val).to_ne_bytes().to_vec(),
|
||||
span,
|
||||
},
|
||||
Value::Duration { val, .. } => Value::Binary {
|
||||
val: val.to_ne_bytes().to_vec(),
|
||||
span,
|
||||
},
|
||||
Value::Date { val, .. } => Value::Binary {
|
||||
val: val.format("%c").to_string().as_bytes().to_vec(),
|
||||
span,
|
||||
},
|
||||
Value::Int { val, .. } => Value::binary(val.to_ne_bytes().to_vec(), span),
|
||||
Value::Float { val, .. } => Value::binary(val.to_ne_bytes().to_vec(), span),
|
||||
Value::Filesize { val, .. } => Value::binary(val.to_ne_bytes().to_vec(), span),
|
||||
Value::String { val, .. } => Value::binary(val.as_bytes().to_vec(), span),
|
||||
Value::Bool { val, .. } => Value::binary(i64::from(*val).to_ne_bytes().to_vec(), span),
|
||||
Value::Duration { val, .. } => Value::binary(val.to_ne_bytes().to_vec(), span),
|
||||
Value::Date { val, .. } => {
|
||||
Value::binary(val.format("%c").to_string().as_bytes().to_vec(), span)
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "integer, float, filesize, string, date, duration, binary or bool"
|
||||
.into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
if _args.compact {
|
||||
if let Value::Binary { val, span } = value {
|
||||
let val_span = value.span();
|
||||
if let Value::Binary { val, .. } = value {
|
||||
let val = if cfg!(target_endian = "little") {
|
||||
match val.iter().rposition(|&x| x != 0) {
|
||||
Some(idx) => &val[..idx + 1],
|
||||
@ -224,10 +197,7 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
|
||||
}
|
||||
};
|
||||
|
||||
Value::Binary {
|
||||
val: val.to_vec(),
|
||||
span,
|
||||
}
|
||||
Value::binary(val.to_vec(), val_span)
|
||||
} else {
|
||||
value
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Convert value to boolean in table",
|
||||
example: "[[value]; ['false'] ['1'] [0] [1.0] [true]] | into bool value",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["value".to_string()],
|
||||
vals: vec![Value::bool(false, span)],
|
||||
@ -82,7 +82,7 @@ impl Command for SubCommand {
|
||||
}),
|
||||
],
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Convert bool to boolean",
|
||||
@ -149,32 +149,23 @@ fn string_to_boolean(s: &str, span: Span) -> Result<bool, ShellError> {
|
||||
fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
match input {
|
||||
Value::Bool { .. } => input.clone(),
|
||||
Value::Int { val, .. } => Value::Bool {
|
||||
val: *val != 0,
|
||||
span,
|
||||
},
|
||||
Value::Float { val, .. } => Value::Bool {
|
||||
val: val.abs() >= f64::EPSILON,
|
||||
span,
|
||||
},
|
||||
Value::Int { val, .. } => Value::bool(*val != 0, span),
|
||||
Value::Float { val, .. } => Value::bool(val.abs() >= f64::EPSILON, span),
|
||||
Value::String { val, .. } => match string_to_boolean(val, span) {
|
||||
Ok(val) => Value::Bool { val, span },
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span,
|
||||
},
|
||||
Ok(val) => Value::bool(val, span),
|
||||
Err(error) => Value::error(error, span),
|
||||
},
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "bool, integer, float or string".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,16 +34,16 @@ impl Command for Into {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&Into.signature(),
|
||||
&[],
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -154,10 +154,10 @@ impl Command for SubCommand {
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
let example_result_1 = |nanos: i64| {
|
||||
Some(Value::Date {
|
||||
val: Utc.timestamp_nanos(nanos).into(),
|
||||
span: Span::test_data(),
|
||||
})
|
||||
Some(Value::date(
|
||||
Utc.timestamp_nanos(nanos).into(),
|
||||
Span::test_data(),
|
||||
))
|
||||
};
|
||||
vec![
|
||||
Example {
|
||||
@ -195,35 +195,35 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Convert list of timestamps to datetimes",
|
||||
example: r#"["2023-03-30 10:10:07 -05:00", "2023-05-05 13:43:49 -05:00", "2023-06-05 01:37:42 -05:00"] | into datetime"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
Value::Date {
|
||||
val: DateTime::parse_from_str(
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::date(
|
||||
DateTime::parse_from_str(
|
||||
"2023-03-30 10:10:07 -05:00",
|
||||
"%Y-%m-%d %H:%M:%S %z",
|
||||
)
|
||||
.expect("date calculation should not fail in test"),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Date {
|
||||
val: DateTime::parse_from_str(
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::date(
|
||||
DateTime::parse_from_str(
|
||||
"2023-05-05 13:43:49 -05:00",
|
||||
"%Y-%m-%d %H:%M:%S %z",
|
||||
)
|
||||
.expect("date calculation should not fail in test"),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Date {
|
||||
val: DateTime::parse_from_str(
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::date(
|
||||
DateTime::parse_from_str(
|
||||
"2023-06-05 01:37:42 -05:00",
|
||||
"%Y-%m-%d %H:%M:%S %z",
|
||||
)
|
||||
.expect("date calculation should not fail in test"),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -240,12 +240,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
if matches!(input, Value::String { .. }) && dateformat.is_none() {
|
||||
if let Ok(input_val) = input.as_spanned_string() {
|
||||
match parse_date_from_string(&input_val.item, input_val.span) {
|
||||
Ok(date) => {
|
||||
return Value::Date {
|
||||
val: date,
|
||||
span: input_val.span,
|
||||
}
|
||||
}
|
||||
Ok(date) => return Value::date(date, input_val.span),
|
||||
Err(err) => err,
|
||||
};
|
||||
}
|
||||
@ -259,15 +254,15 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => return input.clone(),
|
||||
other => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
return Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string and integer".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
span: head,
|
||||
};
|
||||
},
|
||||
head,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -277,107 +272,87 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
// note all these `.timestamp_nanos()` could overflow if we didn't check range in `<date> | into int`.
|
||||
|
||||
// default to UTC
|
||||
None => Value::Date {
|
||||
val: Utc.timestamp_nanos(ts).into(),
|
||||
span: head,
|
||||
},
|
||||
None => Value::date(Utc.timestamp_nanos(ts).into(), head),
|
||||
Some(Spanned { item, span }) => match item {
|
||||
Zone::Utc => {
|
||||
let dt = Utc.timestamp_nanos(ts);
|
||||
Value::Date {
|
||||
val: dt.into(),
|
||||
span: *span,
|
||||
}
|
||||
Value::date(dt.into(), *span)
|
||||
}
|
||||
Zone::Local => {
|
||||
let dt = Local.timestamp_nanos(ts);
|
||||
Value::Date {
|
||||
val: dt.into(),
|
||||
span: *span,
|
||||
}
|
||||
Value::date(dt.into(), *span)
|
||||
}
|
||||
Zone::East(i) => match FixedOffset::east_opt((*i as i32) * HOUR) {
|
||||
Some(eastoffset) => {
|
||||
let dt = eastoffset.timestamp_nanos(ts);
|
||||
Value::Date {
|
||||
val: dt,
|
||||
span: *span,
|
||||
}
|
||||
Value::date(dt, *span)
|
||||
}
|
||||
None => Value::Error {
|
||||
error: Box::new(ShellError::DatetimeParseError(
|
||||
input.debug_value(),
|
||||
*span,
|
||||
)),
|
||||
span: *span,
|
||||
},
|
||||
None => Value::error(
|
||||
ShellError::DatetimeParseError(input.debug_value(), *span),
|
||||
*span,
|
||||
),
|
||||
},
|
||||
Zone::West(i) => match FixedOffset::west_opt((*i as i32) * HOUR) {
|
||||
Some(westoffset) => {
|
||||
let dt = westoffset.timestamp_nanos(ts);
|
||||
Value::Date {
|
||||
val: dt,
|
||||
span: *span,
|
||||
}
|
||||
Value::date(dt, *span)
|
||||
}
|
||||
None => Value::Error {
|
||||
error: Box::new(ShellError::DatetimeParseError(
|
||||
input.debug_value(),
|
||||
*span,
|
||||
)),
|
||||
span: *span,
|
||||
},
|
||||
None => Value::error(
|
||||
ShellError::DatetimeParseError(input.debug_value(), *span),
|
||||
*span,
|
||||
),
|
||||
},
|
||||
Zone::Error => Value::Error {
|
||||
Zone::Error => Value::error(
|
||||
// This is an argument error, not an input error
|
||||
error: Box::new(ShellError::TypeMismatch {
|
||||
ShellError::TypeMismatch {
|
||||
err_message: "Invalid timezone or offset".to_string(),
|
||||
span: *span,
|
||||
}),
|
||||
span: *span,
|
||||
},
|
||||
},
|
||||
*span,
|
||||
),
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// If input is not a timestamp, try parsing it as a string
|
||||
let span = input.span();
|
||||
match input {
|
||||
Value::String { val, span } => {
|
||||
Value::String { val, .. } => {
|
||||
match dateformat {
|
||||
Some(dt) => match DateTime::parse_from_str(val, &dt.0) {
|
||||
Ok(d) => Value::Date { val: d, span: head },
|
||||
Ok(d) => Value::date ( d, head ),
|
||||
Err(reason) => {
|
||||
Value::Error {
|
||||
error: Box::new(ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) }),
|
||||
span: head,
|
||||
}
|
||||
Value::error (
|
||||
ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) },
|
||||
head,
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
// Tries to automatically parse the date
|
||||
// (i.e. without a format string)
|
||||
// and assumes the system's local timezone if none is specified
|
||||
None => match parse_date_from_string(val, *span) {
|
||||
Ok(date) => Value::Date {
|
||||
val: date,
|
||||
span: *span,
|
||||
},
|
||||
None => match parse_date_from_string(val, span) {
|
||||
Ok(date) => Value::date (
|
||||
date,
|
||||
span,
|
||||
),
|
||||
Err(err) => err,
|
||||
},
|
||||
}
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
span: head,
|
||||
},
|
||||
},
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,11 +379,10 @@ mod tests {
|
||||
cell_paths: None,
|
||||
};
|
||||
let actual = action(&date_str, &args, Span::test_data());
|
||||
let expected = Value::Date {
|
||||
val: DateTime::parse_from_str("16.11.1984 8:00 am +0000", "%d.%m.%Y %H:%M %P %z")
|
||||
.unwrap(),
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let expected = Value::date(
|
||||
DateTime::parse_from_str("16.11.1984 8:00 am +0000", "%d.%m.%Y %H:%M %P %z").unwrap(),
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
|
||||
@ -421,11 +395,10 @@ mod tests {
|
||||
cell_paths: None,
|
||||
};
|
||||
let actual = action(&date_str, &args, Span::test_data());
|
||||
let expected = Value::Date {
|
||||
val: DateTime::parse_from_str("2020-08-04T16:39:18+00:00", "%Y-%m-%dT%H:%M:%S%z")
|
||||
.unwrap(),
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let expected = Value::date(
|
||||
DateTime::parse_from_str("2020-08-04T16:39:18+00:00", "%Y-%m-%dT%H:%M:%S%z").unwrap(),
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
|
||||
@ -442,11 +415,10 @@ mod tests {
|
||||
cell_paths: None,
|
||||
};
|
||||
let actual = action(&date_str, &args, Span::test_data());
|
||||
let expected = Value::Date {
|
||||
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
||||
.unwrap(),
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let expected = Value::date(
|
||||
DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z").unwrap(),
|
||||
Span::test_data(),
|
||||
);
|
||||
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
@ -464,11 +436,10 @@ mod tests {
|
||||
cell_paths: None,
|
||||
};
|
||||
let actual = action(&date_int, &args, Span::test_data());
|
||||
let expected = Value::Date {
|
||||
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
||||
.unwrap(),
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let expected = Value::date(
|
||||
DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z").unwrap(),
|
||||
Span::test_data(),
|
||||
);
|
||||
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
@ -486,10 +457,10 @@ mod tests {
|
||||
cell_paths: None,
|
||||
};
|
||||
let actual = action(&date_str, &args, Span::test_data());
|
||||
let expected = Value::Date {
|
||||
val: Local.timestamp_opt(1614434140, 0).unwrap().into(),
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let expected = Value::date(
|
||||
Local.timestamp_opt(1614434140, 0).unwrap().into(),
|
||||
Span::test_data(),
|
||||
);
|
||||
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
@ -504,10 +475,10 @@ mod tests {
|
||||
};
|
||||
let actual = action(&date_str, &args, Span::test_data());
|
||||
|
||||
let expected = Value::Date {
|
||||
val: Utc.timestamp_opt(1614434140, 0).unwrap().into(),
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let expected = Value::date(
|
||||
Utc.timestamp_opt(1614434140, 0).unwrap().into(),
|
||||
Span::test_data(),
|
||||
);
|
||||
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
|
@ -62,13 +62,13 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Convert string to decimal in table",
|
||||
example: "[[num]; ['5.01']] | into decimal num",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["num".to_string()],
|
||||
vals: vec![Value::test_float(5.01)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Convert string to decimal",
|
||||
@ -93,43 +93,44 @@ impl Command for SubCommand {
|
||||
}
|
||||
|
||||
fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
|
||||
let span = input.span();
|
||||
match input {
|
||||
Value::Float { .. } => input.clone(),
|
||||
Value::String { val: s, span } => {
|
||||
Value::String { val: s, .. } => {
|
||||
let other = s.trim();
|
||||
|
||||
match other.parse::<f64>() {
|
||||
Ok(x) => Value::float(x, head),
|
||||
Err(reason) => Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
Err(reason) => Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "float".to_string(),
|
||||
from_type: reason.to_string(),
|
||||
span: *span,
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
span: *span,
|
||||
},
|
||||
},
|
||||
span,
|
||||
),
|
||||
}
|
||||
}
|
||||
Value::Int { val: v, span } => Value::float(*v as f64, *span),
|
||||
Value::Bool { val: b, span } => Value::Float {
|
||||
val: match b {
|
||||
Value::Int { val: v, .. } => Value::float(*v as f64, span),
|
||||
Value::Bool { val: b, .. } => Value::float(
|
||||
match b {
|
||||
true => 1.0,
|
||||
false => 0.0,
|
||||
},
|
||||
span: *span,
|
||||
},
|
||||
span,
|
||||
),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string, integer or bool".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
span: head,
|
||||
},
|
||||
},
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,71 +62,50 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Convert duration string to duration value",
|
||||
example: "'7min' | into duration",
|
||||
result: Some(Value::Duration {
|
||||
val: 7 * 60 * NS_PER_SEC,
|
||||
span,
|
||||
}),
|
||||
result: Some(Value::duration(7 * 60 * NS_PER_SEC, span)),
|
||||
},
|
||||
Example {
|
||||
description: "Convert compound duration string to duration value",
|
||||
example: "'1day 2hr 3min 4sec' | into duration",
|
||||
result: Some(Value::Duration {
|
||||
val: (((((/* 1 * */24) + 2) * 60) + 3) * 60 + 4) * NS_PER_SEC,
|
||||
result: Some(Value::duration(
|
||||
(((((/* 1 * */24) + 2) * 60) + 3) * 60 + 4) * NS_PER_SEC,
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Convert table of duration strings to table of duration values",
|
||||
example:
|
||||
"[[value]; ['1sec'] ['2min'] ['3hr'] ['4day'] ['5wk']] | into duration value",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["value".to_string()],
|
||||
vals: vec![Value::Duration {
|
||||
val: NS_PER_SEC,
|
||||
span,
|
||||
}],
|
||||
vals: vec![Value::duration(NS_PER_SEC, span)],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["value".to_string()],
|
||||
vals: vec![Value::Duration {
|
||||
val: 2 * 60 * NS_PER_SEC,
|
||||
span,
|
||||
}],
|
||||
vals: vec![Value::duration(2 * 60 * NS_PER_SEC, span)],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["value".to_string()],
|
||||
vals: vec![Value::Duration {
|
||||
val: 3 * 60 * 60 * NS_PER_SEC,
|
||||
span,
|
||||
}],
|
||||
vals: vec![Value::duration(3 * 60 * 60 * NS_PER_SEC, span)],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["value".to_string()],
|
||||
vals: vec![Value::Duration {
|
||||
val: 4 * 24 * 60 * 60 * NS_PER_SEC,
|
||||
span,
|
||||
}],
|
||||
vals: vec![Value::duration(4 * 24 * 60 * 60 * NS_PER_SEC, span)],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["value".to_string()],
|
||||
vals: vec![Value::Duration {
|
||||
val: 5 * 7 * 24 * 60 * 60 * NS_PER_SEC,
|
||||
span,
|
||||
}],
|
||||
vals: vec![Value::duration(5 * 7 * 24 * 60 * 60 * NS_PER_SEC, span)],
|
||||
}),
|
||||
],
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Convert duration to duration",
|
||||
example: "420sec | into duration",
|
||||
result: Some(Value::Duration {
|
||||
val: 7 * 60 * NS_PER_SEC,
|
||||
span,
|
||||
}),
|
||||
result: Some(Value::duration(7 * 60 * NS_PER_SEC, span)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -154,10 +133,7 @@ fn into_duration(
|
||||
let r =
|
||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, span)));
|
||||
if let Err(error) = r {
|
||||
return Value::Error {
|
||||
error: Box::new(error),
|
||||
span,
|
||||
};
|
||||
return Value::error(error, span);
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,29 +203,24 @@ fn string_to_duration(s: &str, span: Span) -> Result<i64, ShellError> {
|
||||
}
|
||||
|
||||
fn action(input: &Value, span: Span) -> Value {
|
||||
let value_span = input.span();
|
||||
match input {
|
||||
Value::Duration { .. } => input.clone(),
|
||||
Value::String {
|
||||
val,
|
||||
span: value_span,
|
||||
} => match compound_to_duration(val, *value_span) {
|
||||
Ok(val) => Value::Duration { val, span },
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span,
|
||||
},
|
||||
Value::String { val, .. } => match compound_to_duration(val, value_span) {
|
||||
Ok(val) => Value::duration(val, span),
|
||||
Err(error) => Value::error(error, span),
|
||||
},
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string or duration".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,69 +79,45 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Convert string to filesize in table",
|
||||
example: r#"[[device size]; ["/dev/sda1" "200"] ["/dev/loop0" "50"]] | into filesize size"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["device".to_string(), "size".to_string()],
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: "/dev/sda1".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Filesize {
|
||||
val: 200,
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("/dev/sda1".to_string(), Span::test_data()),
|
||||
Value::filesize(200, Span::test_data()),
|
||||
],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["device".to_string(), "size".to_string()],
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: "/dev/loop0".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Filesize {
|
||||
val: 50,
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("/dev/loop0".to_string(), Span::test_data()),
|
||||
Value::filesize(50, Span::test_data()),
|
||||
],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Convert string to filesize",
|
||||
example: "'2' | into filesize",
|
||||
result: Some(Value::Filesize {
|
||||
val: 2,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::filesize(2, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Convert decimal to filesize",
|
||||
example: "8.3 | into filesize",
|
||||
result: Some(Value::Filesize {
|
||||
val: 8,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::filesize(8, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Convert int to filesize",
|
||||
example: "5 | into filesize",
|
||||
result: Some(Value::Filesize {
|
||||
val: 5,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::filesize(5, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Convert file size to filesize",
|
||||
example: "4KB | into filesize",
|
||||
result: Some(Value::Filesize {
|
||||
val: 4000,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::filesize(4000, Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -151,37 +127,22 @@ pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
let value_span = input.span();
|
||||
match input {
|
||||
Value::Filesize { .. } => input.clone(),
|
||||
Value::Int { val, .. } => Value::Filesize {
|
||||
val: *val,
|
||||
span: value_span,
|
||||
},
|
||||
Value::Float { val, .. } => Value::Filesize {
|
||||
val: *val as i64,
|
||||
span: value_span,
|
||||
},
|
||||
Value::Int { val, .. } => Value::filesize(*val, value_span),
|
||||
Value::Float { val, .. } => Value::filesize(*val as i64, value_span),
|
||||
Value::String { val, .. } => match int_from_string(val, value_span) {
|
||||
Ok(val) => Value::Filesize {
|
||||
val,
|
||||
span: value_span,
|
||||
},
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span: value_span,
|
||||
},
|
||||
Ok(val) => Value::filesize(val, value_span),
|
||||
Err(error) => Value::error(error, value_span),
|
||||
},
|
||||
Value::Nothing { .. } => Value::Filesize {
|
||||
val: 0,
|
||||
span: value_span,
|
||||
},
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
Value::Nothing { .. } => Value::filesize(0, value_span),
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string and integer".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: value_span,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
|
||||
|
@ -107,33 +107,44 @@ impl Command for SubCommand {
|
||||
|
||||
let radix = call.get_flag::<Value>(engine_state, stack, "radix")?;
|
||||
let radix: u32 = match radix {
|
||||
Some(Value::Int { val, span }) => {
|
||||
if !(2..=36).contains(&val) {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "Radix must lie in the range [2, 36]".to_string(),
|
||||
span,
|
||||
});
|
||||
Some(val) => {
|
||||
let span = val.span();
|
||||
match val {
|
||||
Value::Int { val, .. } => {
|
||||
if !(2..=36).contains(&val) {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "Radix must lie in the range [2, 36]".to_string(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
val as u32
|
||||
}
|
||||
_ => 10,
|
||||
}
|
||||
val as u32
|
||||
}
|
||||
Some(_) => 10,
|
||||
None => 10,
|
||||
};
|
||||
|
||||
let endian = call.get_flag::<Value>(engine_state, stack, "endian")?;
|
||||
let little_endian = match endian {
|
||||
Some(Value::String { val, span }) => match val.as_str() {
|
||||
"native" => cfg!(target_endian = "little"),
|
||||
"little" => true,
|
||||
"big" => false,
|
||||
_ => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "Endian must be one of native, little, big".to_string(),
|
||||
span,
|
||||
})
|
||||
Some(val) => {
|
||||
let span = val.span();
|
||||
match val {
|
||||
Value::String { val, .. } => match val.as_str() {
|
||||
"native" => cfg!(target_endian = "little"),
|
||||
"little" => true,
|
||||
"big" => false,
|
||||
_ => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "Endian must be one of native, little, big"
|
||||
.to_string(),
|
||||
span,
|
||||
})
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
Some(_) => false,
|
||||
}
|
||||
None => cfg!(target_endian = "little"),
|
||||
};
|
||||
|
||||
@ -175,10 +186,10 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Convert bool to integer",
|
||||
example: "[false, true] | into int",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Convert date to integer (Unix nanosecond timestamp)",
|
||||
@ -217,6 +228,7 @@ impl Command for SubCommand {
|
||||
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let radix = args.radix;
|
||||
let little_endian = args.little_endian;
|
||||
let val_span = input.span();
|
||||
match input {
|
||||
Value::Int { val: _, .. } => {
|
||||
if radix == 10 {
|
||||
@ -225,47 +237,35 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
convert_int(input, span, radix)
|
||||
}
|
||||
}
|
||||
Value::Filesize { val, .. } => Value::Int { val: *val, span },
|
||||
Value::Float { val, .. } => Value::Int {
|
||||
val: {
|
||||
Value::Filesize { val, .. } => Value::int(*val, span),
|
||||
Value::Float { val, .. } => Value::int(
|
||||
{
|
||||
if radix == 10 {
|
||||
*val as i64
|
||||
} else {
|
||||
match convert_int(
|
||||
&Value::Int {
|
||||
val: *val as i64,
|
||||
span,
|
||||
},
|
||||
span,
|
||||
radix,
|
||||
)
|
||||
.as_i64()
|
||||
{
|
||||
match convert_int(&Value::int(*val as i64, span), span, radix).as_i64() {
|
||||
Ok(v) => v,
|
||||
_ => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
return Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "float".to_string(),
|
||||
from_type: "integer".to_string(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
Value::String { val, .. } => {
|
||||
if radix == 10 {
|
||||
match int_from_string(val, span) {
|
||||
Ok(val) => Value::Int { val, span },
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span,
|
||||
},
|
||||
Ok(val) => Value::int(val, span),
|
||||
Err(error) => Value::error(error, span),
|
||||
}
|
||||
} else {
|
||||
convert_int(input, span, radix)
|
||||
@ -273,15 +273,12 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
}
|
||||
Value::Bool { val, .. } => {
|
||||
if *val {
|
||||
Value::Int { val: 1, span }
|
||||
Value::int(1, span)
|
||||
} else {
|
||||
Value::Int { val: 0, span }
|
||||
Value::int(0, span)
|
||||
}
|
||||
}
|
||||
Value::Date {
|
||||
val,
|
||||
span: val_span,
|
||||
} => {
|
||||
Value::Date { val, .. } => {
|
||||
if val
|
||||
< &FixedOffset::east_opt(0)
|
||||
.expect("constant")
|
||||
@ -293,23 +290,20 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
.with_ymd_and_hms(2262, 4, 11, 23, 47, 16)
|
||||
.unwrap()
|
||||
{
|
||||
Value::Error {
|
||||
error: Box::new(ShellError::IncorrectValue {
|
||||
Value::error (
|
||||
ShellError::IncorrectValue {
|
||||
msg: "DateTime out of range for timestamp: 1677-09-21T00:12:43Z to 2262-04-11T23:47:16".to_string(),
|
||||
val_span: *val_span,
|
||||
val_span,
|
||||
call_span: span,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Value::Int {
|
||||
val: val.timestamp_nanos(),
|
||||
span,
|
||||
}
|
||||
Value::int(val.timestamp_nanos(), span)
|
||||
}
|
||||
}
|
||||
Value::Duration { val, .. } => Value::Int { val: *val, span },
|
||||
Value::Binary { val, span } => {
|
||||
Value::Duration { val, .. } => Value::int(*val, span),
|
||||
Value::Binary { val, .. } => {
|
||||
use byteorder::{BigEndian, ByteOrder, LittleEndian};
|
||||
|
||||
let mut val = val.to_vec();
|
||||
@ -320,28 +314,28 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
}
|
||||
val.resize(8, 0);
|
||||
|
||||
Value::int(LittleEndian::read_i64(&val), *span)
|
||||
Value::int(LittleEndian::read_i64(&val), val_span)
|
||||
} else {
|
||||
while val.len() < 8 {
|
||||
val.insert(0, 0);
|
||||
}
|
||||
val.resize(8, 0);
|
||||
|
||||
Value::int(BigEndian::read_i64(&val), *span)
|
||||
Value::int(BigEndian::read_i64(&val), val_span)
|
||||
}
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "integer, float, filesize, date, string, binary, duration or bool"
|
||||
.into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,27 +351,22 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
|
||||
{
|
||||
match int_from_string(val, head) {
|
||||
Ok(x) => return Value::int(x, head),
|
||||
Err(e) => {
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span: head,
|
||||
}
|
||||
}
|
||||
Err(e) => return Value::error(e, head),
|
||||
}
|
||||
} else if val.starts_with("00") {
|
||||
// It's a padded string
|
||||
match i64::from_str_radix(val, radix) {
|
||||
Ok(n) => return Value::int(n, head),
|
||||
Err(e) => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
return Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "string".to_string(),
|
||||
from_type: "int".to_string(),
|
||||
span: head,
|
||||
help: Some(e.to_string()),
|
||||
}),
|
||||
span: head,
|
||||
}
|
||||
},
|
||||
head,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -386,28 +375,28 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => return input.clone(),
|
||||
other => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
return Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string and integer".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
span: head,
|
||||
};
|
||||
},
|
||||
head,
|
||||
);
|
||||
}
|
||||
};
|
||||
match i64::from_str_radix(i.trim(), radix) {
|
||||
Ok(n) => Value::int(n, head),
|
||||
Err(_reason) => Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
Err(_reason) => Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "string".to_string(),
|
||||
from_type: "int".to_string(),
|
||||
span: head,
|
||||
help: None,
|
||||
}),
|
||||
span: head,
|
||||
},
|
||||
},
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,9 @@ impl Command for SubCommand {
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["0".to_string(), "1".to_string(), "2".to_string()],
|
||||
vals: vec![
|
||||
Value::Int { val: 1, span },
|
||||
Value::Int { val: 2, span },
|
||||
Value::Int { val: 3, span },
|
||||
Value::int(1, span),
|
||||
Value::int(2, span),
|
||||
Value::int(3, span),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -74,9 +74,9 @@ impl Command for SubCommand {
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["0".to_string(), "1".to_string(), "2".to_string()],
|
||||
vals: vec![
|
||||
Value::Int { val: 0, span },
|
||||
Value::Int { val: 1, span },
|
||||
Value::Int { val: 2, span },
|
||||
Value::int(0, span),
|
||||
Value::int(1, span),
|
||||
Value::int(2, span),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -92,14 +92,11 @@ impl Command for SubCommand {
|
||||
"sign".into(),
|
||||
],
|
||||
vals: vec![
|
||||
Value::Int { val: 71, span },
|
||||
Value::Int { val: 3, span },
|
||||
Value::Int { val: 4, span },
|
||||
Value::Int { val: 5, span },
|
||||
Value::String {
|
||||
val: "-".into(),
|
||||
span,
|
||||
},
|
||||
Value::int(71, span),
|
||||
Value::int(3, span),
|
||||
Value::int(4, span),
|
||||
Value::int(5, span),
|
||||
Value::string("-", span),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -108,7 +105,7 @@ impl Command for SubCommand {
|
||||
example: "{a: 1, b: 2} | into record",
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["a".to_string(), "b".to_string()],
|
||||
vals: vec![Value::Int { val: 1, span }, Value::Int { val: 2, span }],
|
||||
vals: vec![Value::int(1, span), Value::int(2, span)],
|
||||
})),
|
||||
},
|
||||
Example {
|
||||
@ -125,16 +122,13 @@ impl Command for SubCommand {
|
||||
"timezone".into(),
|
||||
],
|
||||
vals: vec![
|
||||
Value::Int { val: 2020, span },
|
||||
Value::Int { val: 4, span },
|
||||
Value::Int { val: 12, span },
|
||||
Value::Int { val: 22, span },
|
||||
Value::Int { val: 10, span },
|
||||
Value::Int { val: 57, span },
|
||||
Value::String {
|
||||
val: "+02:00".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::int(2020, span),
|
||||
Value::int(4, span),
|
||||
Value::int(12, span),
|
||||
Value::int(22, span),
|
||||
Value::int(10, span),
|
||||
Value::int(57, span),
|
||||
Value::string("+02:00".to_string(), span),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -149,10 +143,11 @@ fn into_record(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let input = input.into_value(call.head);
|
||||
let input_type = input.get_type();
|
||||
let span = input.span();
|
||||
let res = match input {
|
||||
Value::Date { val, span } => parse_date_into_record(val, span),
|
||||
Value::Duration { val, span } => parse_duration_into_record(val, span),
|
||||
Value::List { mut vals, span } => match input_type {
|
||||
Value::Date { val, .. } => parse_date_into_record(val, span),
|
||||
Value::Duration { val, .. } => parse_duration_into_record(val, span),
|
||||
Value::List { mut vals, .. } => match input_type {
|
||||
Type::Table(..) if vals.len() == 1 => vals.pop().expect("already checked 1 item"),
|
||||
_ => Value::record(
|
||||
vals.into_iter()
|
||||
@ -162,24 +157,24 @@ fn into_record(
|
||||
span,
|
||||
),
|
||||
},
|
||||
Value::Range { val, span } => Value::record(
|
||||
Value::Range { val, .. } => Value::record(
|
||||
val.into_range_iter(engine_state.ctrlc.clone())?
|
||||
.enumerate()
|
||||
.map(|(idx, val)| (format!("{idx}"), val))
|
||||
.collect(),
|
||||
span,
|
||||
),
|
||||
Value::Record { val, span } => Value::Record { val, span },
|
||||
Value::Record { val, .. } => Value::record(val, span),
|
||||
Value::Error { .. } => input,
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: call.head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
span: call.head,
|
||||
},
|
||||
},
|
||||
call.head,
|
||||
),
|
||||
};
|
||||
Ok(res.into_pipeline_data())
|
||||
}
|
||||
|
@ -182,22 +182,16 @@ fn string_helper(
|
||||
};
|
||||
|
||||
match input {
|
||||
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::String {
|
||||
val: String::new(),
|
||||
span: head,
|
||||
PipelineData::ExternalStream { stdout: None, .. } => {
|
||||
Ok(Value::string(String::new(), head).into_pipeline_data())
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
PipelineData::ExternalStream {
|
||||
stdout: Some(stream),
|
||||
..
|
||||
} => {
|
||||
// TODO: in the future, we may want this to stream out, converting each to bytes
|
||||
let output = stream.into_string()?;
|
||||
Ok(Value::String {
|
||||
val: output.item,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::string(output.item, head).into_pipeline_data())
|
||||
}
|
||||
_ => operate(action, args, input, head, engine_state.ctrlc.clone()),
|
||||
}
|
||||
@ -211,80 +205,53 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
Value::Int { val, .. } => {
|
||||
let decimal_value = digits.unwrap_or(0) as usize;
|
||||
let res = format_int(*val, false, decimal_value);
|
||||
Value::String { val: res, span }
|
||||
Value::string(res, span)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
if decimals {
|
||||
let decimal_value = digits.unwrap_or(2) as usize;
|
||||
Value::String {
|
||||
val: format!("{val:.decimal_value$}"),
|
||||
span,
|
||||
}
|
||||
Value::string(format!("{val:.decimal_value$}"), span)
|
||||
} else {
|
||||
Value::String {
|
||||
val: val.to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(val.to_string(), span)
|
||||
}
|
||||
}
|
||||
Value::Bool { val, .. } => Value::String {
|
||||
val: val.to_string(),
|
||||
span,
|
||||
},
|
||||
Value::Date { val, .. } => Value::String {
|
||||
val: val.format("%c").to_string(),
|
||||
span,
|
||||
},
|
||||
Value::String { val, .. } => Value::String {
|
||||
val: val.to_string(),
|
||||
span,
|
||||
},
|
||||
Value::Bool { val, .. } => Value::string(val.to_string(), span),
|
||||
Value::Date { val, .. } => Value::string(val.format("%c").to_string(), span),
|
||||
Value::String { val, .. } => Value::string(val.to_string(), span),
|
||||
|
||||
Value::Filesize { val: _, .. } => Value::String {
|
||||
val: input.into_string(", ", config),
|
||||
span,
|
||||
},
|
||||
Value::Duration { val: _, .. } => Value::String {
|
||||
val: input.into_string("", config),
|
||||
span,
|
||||
},
|
||||
Value::Filesize { val: _, .. } => Value::string(input.into_string(", ", config), span),
|
||||
Value::Duration { val: _, .. } => Value::string(input.into_string("", config), span),
|
||||
|
||||
Value::Error { error, .. } => Value::String {
|
||||
val: into_code(error).unwrap_or_default(),
|
||||
span,
|
||||
},
|
||||
Value::Nothing { .. } => Value::String {
|
||||
val: "".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::Record { .. } => Value::Error {
|
||||
Value::Error { error, .. } => Value::string(into_code(error).unwrap_or_default(), span),
|
||||
Value::Nothing { .. } => Value::string("".to_string(), span),
|
||||
Value::Record { .. } => Value::error(
|
||||
// Watch out for CantConvert's argument order
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
ShellError::CantConvert {
|
||||
to_type: "string".into(),
|
||||
from_type: "record".into(),
|
||||
span,
|
||||
help: Some("try using the `to nuon` command".into()),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
Value::Binary { .. } => Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
),
|
||||
Value::Binary { .. } => Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: "string".into(),
|
||||
from_type: "binary".into(),
|
||||
span,
|
||||
help: Some("try using the `decode` command".into()),
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
x => Value::Error {
|
||||
error: Box::new(ShellError::CantConvert {
|
||||
),
|
||||
x => Value::error(
|
||||
ShellError::CantConvert {
|
||||
to_type: String::from("string"),
|
||||
from_type: x.get_type().to_string(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,9 @@ fn action(
|
||||
"main".to_string()
|
||||
};
|
||||
|
||||
let val_span = input.span();
|
||||
match input {
|
||||
Value::List { vals, span } => {
|
||||
Value::List { vals, .. } => {
|
||||
// find the column names, and sqlite data types
|
||||
let columns = get_columns_with_sqlite_types(vals);
|
||||
|
||||
@ -135,11 +136,10 @@ fn action(
|
||||
.join(",")
|
||||
}
|
||||
// Number formats so keep them without quotes
|
||||
Value::Int { val: _, span: _ }
|
||||
| Value::Float { val: _, span: _ }
|
||||
| Value::Filesize { val: _, span: _ }
|
||||
| Value::Duration { val: _, span: _ } =>
|
||||
nu_value_to_string(list_value.clone(), ""),
|
||||
Value::Int { .. }
|
||||
| Value::Float { .. }
|
||||
| Value::Filesize { .. }
|
||||
| Value::Duration { .. } => nu_value_to_string(list_value.clone(), ""),
|
||||
_ =>
|
||||
// String formats so add quotes around them
|
||||
format!("'{}'", nu_value_to_string(list_value.clone(), "")),
|
||||
@ -210,7 +210,7 @@ fn action(
|
||||
})?;
|
||||
|
||||
// and we're done
|
||||
Ok(Value::Nothing { span: *span })
|
||||
Ok(Value::nothing(val_span))
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error.clone()),
|
||||
|
@ -56,8 +56,9 @@ impl SQLiteDatabase {
|
||||
}
|
||||
|
||||
pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
|
||||
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
|
||||
Some(db) => Ok(Self {
|
||||
path: db.path.clone(),
|
||||
ctrlc: db.ctrlc.clone(),
|
||||
@ -84,10 +85,7 @@ impl SQLiteDatabase {
|
||||
}
|
||||
|
||||
pub fn into_value(self, span: Span) -> Value {
|
||||
Value::CustomValue {
|
||||
val: Box::new(self),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(self), span)
|
||||
}
|
||||
|
||||
pub fn query(&self, sql: &Spanned<String>, call_span: Span) -> Result<Value, ShellError> {
|
||||
@ -280,10 +278,7 @@ impl CustomValue for SQLiteDatabase {
|
||||
ctrlc: self.ctrlc.clone(),
|
||||
};
|
||||
|
||||
Value::CustomValue {
|
||||
val: Box::new(cloned),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(cloned), span)
|
||||
}
|
||||
|
||||
fn value_string(&self) -> String {
|
||||
@ -393,10 +388,7 @@ fn prepared_statement_to_nu_list(
|
||||
for row_result in row_results {
|
||||
if nu_utils::ctrl_c::was_pressed(&ctrlc) {
|
||||
// return whatever we have so far, let the caller decide whether to use it
|
||||
return Ok(Value::List {
|
||||
vals: row_values,
|
||||
span: call_span,
|
||||
});
|
||||
return Ok(Value::list(row_values, call_span));
|
||||
}
|
||||
|
||||
if let Ok(row_value) = row_result {
|
||||
@ -404,10 +396,7 @@ fn prepared_statement_to_nu_list(
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::List {
|
||||
vals: row_values,
|
||||
span: call_span,
|
||||
})
|
||||
Ok(Value::list(row_values, call_span))
|
||||
}
|
||||
|
||||
fn read_entire_sqlite_db(
|
||||
@ -450,28 +439,17 @@ pub fn convert_sqlite_row_to_nu_value(row: &Row, span: Span, column_names: Vec<S
|
||||
|
||||
pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value {
|
||||
match value {
|
||||
ValueRef::Null => Value::Nothing { span },
|
||||
ValueRef::Integer(i) => Value::Int { val: i, span },
|
||||
ValueRef::Real(f) => Value::Float { val: f, span },
|
||||
ValueRef::Null => Value::nothing(span),
|
||||
ValueRef::Integer(i) => Value::int(i, span),
|
||||
ValueRef::Real(f) => Value::float(f, span),
|
||||
ValueRef::Text(buf) => {
|
||||
let s = match std::str::from_utf8(buf) {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::NonUtf8(span)),
|
||||
span,
|
||||
}
|
||||
}
|
||||
Err(_) => return Value::error(ShellError::NonUtf8(span), span),
|
||||
};
|
||||
Value::String {
|
||||
val: s.to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(s.to_string(), span)
|
||||
}
|
||||
ValueRef::Blob(u) => Value::Binary {
|
||||
val: u.to_vec(),
|
||||
span,
|
||||
},
|
||||
ValueRef::Blob(u) => Value::binary(u.to_vec(), span),
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,10 +484,7 @@ mod test {
|
||||
|
||||
let expected = Value::test_record(Record {
|
||||
cols: vec!["person".to_string()],
|
||||
vals: vec![Value::List {
|
||||
vals: vec![],
|
||||
span: Span::test_data(),
|
||||
}],
|
||||
vals: vec![Value::list(vec![], Span::test_data())],
|
||||
});
|
||||
|
||||
assert_eq!(converted_db, expected);
|
||||
@ -539,25 +514,22 @@ mod test {
|
||||
|
||||
let expected = Value::test_record(Record {
|
||||
cols: vec!["item".to_string()],
|
||||
vals: vec![Value::List {
|
||||
vals: vec![
|
||||
vals: vec![Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["id".to_string(), "name".to_string()],
|
||||
vals: vec![Value::Int { val: 123, span }, Value::Nothing { span }],
|
||||
vals: vec![Value::int(123, span), Value::nothing(span)],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["id".to_string(), "name".to_string()],
|
||||
vals: vec![
|
||||
Value::Int { val: 456, span },
|
||||
Value::String {
|
||||
val: "foo bar".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::int(456, span),
|
||||
Value::string("foo bar".to_string(), span),
|
||||
],
|
||||
}),
|
||||
],
|
||||
span,
|
||||
}],
|
||||
)],
|
||||
});
|
||||
|
||||
assert_eq!(converted_db, expected);
|
||||
|
@ -58,15 +58,15 @@ fn date(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&Date.signature(),
|
||||
&Date.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
false,
|
||||
),
|
||||
span: head,
|
||||
}
|
||||
head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
|
@ -64,35 +64,24 @@ impl Command for SubCommand {
|
||||
}
|
||||
|
||||
fn helper(value: Value, head: Span) -> Value {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Nothing { span: _ } => {
|
||||
Value::Nothing { .. } => {
|
||||
let dt = Local::now();
|
||||
Value::String {
|
||||
val: humanize_date(dt.with_timezone(dt.offset())),
|
||||
span: head,
|
||||
}
|
||||
Value::string(humanize_date(dt.with_timezone(dt.offset())), head)
|
||||
}
|
||||
Value::String {
|
||||
val,
|
||||
span: val_span,
|
||||
} => {
|
||||
let dt = parse_date_from_string(&val, val_span);
|
||||
Value::String { val, .. } => {
|
||||
let dt = parse_date_from_string(&val, span);
|
||||
match dt {
|
||||
Ok(x) => Value::String {
|
||||
val: humanize_date(x),
|
||||
span: head,
|
||||
},
|
||||
Ok(x) => Value::string(humanize_date(x), head),
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
Value::Date { val, span: _ } => Value::String {
|
||||
val: humanize_date(val),
|
||||
span: head,
|
||||
},
|
||||
_ => Value::Error {
|
||||
error: Box::new(ShellError::DatetimeParseError(value.debug_value(), head)),
|
||||
span: head,
|
||||
},
|
||||
Value::Date { val, .. } => Value::string(humanize_date(val), head),
|
||||
_ => Value::error(
|
||||
ShellError::DatetimeParseError(value.debug_value(), head),
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,13 +52,13 @@ impl Command for SubCommand {
|
||||
vec![Example {
|
||||
example: "date list-timezone | where timezone =~ Shanghai",
|
||||
description: "Show timezone(s) that contains 'Shanghai'",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["timezone".into()],
|
||||
vals: vec![Value::test_string("Asia/Shanghai")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
@ -35,11 +35,7 @@ impl Command for SubCommand {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let dt = Local::now();
|
||||
Ok(Value::Date {
|
||||
val: dt.with_timezone(dt.offset()),
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::date(dt.with_timezone(dt.offset()), head).into_pipeline_data())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -62,20 +62,14 @@ impl Command for SubCommand {
|
||||
"timezone".into(),
|
||||
];
|
||||
let vals = vec![
|
||||
Value::Int { val: 2020, span },
|
||||
Value::Int { val: 4, span },
|
||||
Value::Int { val: 12, span },
|
||||
Value::Int { val: 22, span },
|
||||
Value::Int { val: 10, span },
|
||||
Value::Int { val: 57, span },
|
||||
Value::Int {
|
||||
val: 123_000_000,
|
||||
span,
|
||||
},
|
||||
Value::String {
|
||||
val: "+02:00".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::int(2020, span),
|
||||
Value::int(4, span),
|
||||
Value::int(12, span),
|
||||
Value::int(22, span),
|
||||
Value::int(10, span),
|
||||
Value::int(57, span),
|
||||
Value::int(123_000_000, span),
|
||||
Value::string("+02:00", span),
|
||||
];
|
||||
Some(Value::test_record(Record { cols, vals }))
|
||||
};
|
||||
@ -93,17 +87,14 @@ impl Command for SubCommand {
|
||||
"timezone".into(),
|
||||
];
|
||||
let vals = vec![
|
||||
Value::Int { val: 2020, span },
|
||||
Value::Int { val: 4, span },
|
||||
Value::Int { val: 12, span },
|
||||
Value::Int { val: 22, span },
|
||||
Value::Int { val: 10, span },
|
||||
Value::Int { val: 57, span },
|
||||
Value::Int { val: 0, span },
|
||||
Value::String {
|
||||
val: "+02:00".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::int(2020, span),
|
||||
Value::int(4, span),
|
||||
Value::int(12, span),
|
||||
Value::int(22, span),
|
||||
Value::int(10, span),
|
||||
Value::int(57, span),
|
||||
Value::int(0, span),
|
||||
Value::string("+02:00", span),
|
||||
];
|
||||
Some(Value::test_record(Record { cols, vals }))
|
||||
};
|
||||
@ -150,24 +141,19 @@ fn parse_date_into_table(date: DateTime<FixedOffset>, head: Span) -> Value {
|
||||
}
|
||||
|
||||
fn helper(val: Value, head: Span) -> Value {
|
||||
let span = val.span();
|
||||
match val {
|
||||
Value::String {
|
||||
val,
|
||||
span: val_span,
|
||||
} => match parse_date_from_string(&val, val_span) {
|
||||
Value::String { val, .. } => match parse_date_from_string(&val, span) {
|
||||
Ok(date) => parse_date_into_table(date, head),
|
||||
Err(e) => e,
|
||||
},
|
||||
Value::Nothing { span: _ } => {
|
||||
Value::Nothing { .. } => {
|
||||
let now = Local::now();
|
||||
let n = now.with_timezone(now.offset());
|
||||
parse_date_into_table(n, head)
|
||||
}
|
||||
Value::Date { val, span: _ } => parse_date_into_table(val, head),
|
||||
_ => Value::Error {
|
||||
error: Box::new(DatetimeParseError(val.debug_value(), head)),
|
||||
span: head,
|
||||
},
|
||||
Value::Date { val, .. } => parse_date_into_table(val, head),
|
||||
_ => Value::error(DatetimeParseError(val.debug_value(), head), head),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,22 +62,19 @@ impl Command for SubCommand {
|
||||
"timezone".into(),
|
||||
];
|
||||
let vals = vec![
|
||||
Value::Int { val: 2020, span },
|
||||
Value::Int { val: 4, span },
|
||||
Value::Int { val: 12, span },
|
||||
Value::Int { val: 22, span },
|
||||
Value::Int { val: 10, span },
|
||||
Value::Int { val: 57, span },
|
||||
Value::Int { val: 789, span },
|
||||
Value::String {
|
||||
val: "+02:00".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::int(2020, span),
|
||||
Value::int(4, span),
|
||||
Value::int(12, span),
|
||||
Value::int(22, span),
|
||||
Value::int(10, span),
|
||||
Value::int(57, span),
|
||||
Value::int(789, span),
|
||||
Value::string("+02:00".to_string(), span),
|
||||
];
|
||||
Some(Value::List {
|
||||
vals: vec![Value::test_record(Record { cols, vals })],
|
||||
Some(Value::list(
|
||||
vec![Value::test_record(Record { cols, vals })],
|
||||
span,
|
||||
})
|
||||
))
|
||||
};
|
||||
|
||||
let example_result_2 = || {
|
||||
@ -93,22 +90,19 @@ impl Command for SubCommand {
|
||||
"timezone".into(),
|
||||
];
|
||||
let vals = vec![
|
||||
Value::Int { val: 2020, span },
|
||||
Value::Int { val: 4, span },
|
||||
Value::Int { val: 12, span },
|
||||
Value::Int { val: 22, span },
|
||||
Value::Int { val: 10, span },
|
||||
Value::Int { val: 57, span },
|
||||
Value::Int { val: 0, span },
|
||||
Value::String {
|
||||
val: "+02:00".to_string(),
|
||||
span,
|
||||
},
|
||||
Value::int(2020, span),
|
||||
Value::int(4, span),
|
||||
Value::int(12, span),
|
||||
Value::int(22, span),
|
||||
Value::int(10, span),
|
||||
Value::int(57, span),
|
||||
Value::int(0, span),
|
||||
Value::string("+02:00".to_string(), span),
|
||||
];
|
||||
Some(Value::List {
|
||||
vals: vec![Value::test_record(Record { cols, vals })],
|
||||
Some(Value::list(
|
||||
vec![Value::test_record(Record { cols, vals })],
|
||||
span,
|
||||
})
|
||||
))
|
||||
};
|
||||
|
||||
vec![
|
||||
@ -152,24 +146,19 @@ fn parse_date_into_table(date: DateTime<FixedOffset>, head: Span) -> Value {
|
||||
}
|
||||
|
||||
fn helper(val: Value, head: Span) -> Value {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::String {
|
||||
val,
|
||||
span: val_span,
|
||||
} => match parse_date_from_string(&val, val_span) {
|
||||
Value::String { val, .. } => match parse_date_from_string(&val, val_span) {
|
||||
Ok(date) => parse_date_into_table(date, head),
|
||||
Err(e) => e,
|
||||
},
|
||||
Value::Nothing { span: _ } => {
|
||||
Value::Nothing { .. } => {
|
||||
let now = Local::now();
|
||||
let n = now.with_timezone(now.offset());
|
||||
parse_date_into_table(n, head)
|
||||
}
|
||||
Value::Date { val, span: _ } => parse_date_into_table(val, head),
|
||||
_ => Value::Error {
|
||||
error: Box::new(DatetimeParseError(val.debug_value(), head)),
|
||||
span: head,
|
||||
},
|
||||
Value::Date { val, .. } => parse_date_into_table(val, head),
|
||||
_ => Value::error(DatetimeParseError(val.debug_value(), head), head),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,10 +71,7 @@ impl Command for SubCommand {
|
||||
.expect("to timezone: help example is invalid")
|
||||
.with_ymd_and_hms(2020, 10, 10, 13, 00, 00)
|
||||
{
|
||||
LocalResult::Single(dt) => Some(Value::Date {
|
||||
val: dt,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
LocalResult::Single(dt) => Some(Value::date(dt, Span::test_data())),
|
||||
_ => panic!("to timezone: help example is invalid"),
|
||||
};
|
||||
|
||||
@ -109,12 +106,10 @@ impl Command for SubCommand {
|
||||
}
|
||||
|
||||
fn helper(value: Value, head: Span, timezone: &Spanned<String>) -> Value {
|
||||
let val_span = value.span();
|
||||
match value {
|
||||
Value::Date { val, span: _ } => _to_timezone(val, timezone, head),
|
||||
Value::String {
|
||||
val,
|
||||
span: val_span,
|
||||
} => {
|
||||
Value::Date { val, .. } => _to_timezone(val, timezone, head),
|
||||
Value::String { val, .. } => {
|
||||
let time = parse_date_from_string(&val, val_span);
|
||||
match time {
|
||||
Ok(dt) => _to_timezone(dt, timezone, head),
|
||||
@ -122,27 +117,27 @@ fn helper(value: Value, head: Span, timezone: &Spanned<String>) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
Value::Nothing { span: _ } => {
|
||||
Value::Nothing { .. } => {
|
||||
let dt = Local::now();
|
||||
_to_timezone(dt.with_timezone(dt.offset()), timezone, head)
|
||||
}
|
||||
_ => Value::Error {
|
||||
error: Box::new(ShellError::DatetimeParseError(value.debug_value(), head)),
|
||||
span: head,
|
||||
},
|
||||
_ => Value::error(
|
||||
ShellError::DatetimeParseError(value.debug_value(), head),
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn _to_timezone(dt: DateTime<FixedOffset>, timezone: &Spanned<String>, span: Span) -> Value {
|
||||
match datetime_in_timezone(&dt, timezone.item.as_str()) {
|
||||
Ok(dt) => Value::Date { val: dt, span },
|
||||
Err(_) => Value::Error {
|
||||
error: Box::new(ShellError::TypeMismatch {
|
||||
Ok(dt) => Value::date(dt, span),
|
||||
Err(_) => Value::error(
|
||||
ShellError::TypeMismatch {
|
||||
err_message: String::from("invalid time zone"),
|
||||
span: timezone.span,
|
||||
}),
|
||||
span: timezone.span,
|
||||
},
|
||||
},
|
||||
timezone.span,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,16 +14,16 @@ pub(crate) fn parse_date_from_string(
|
||||
match offset.from_local_datetime(&native_dt) {
|
||||
LocalResult::Single(d) => Ok(d),
|
||||
LocalResult::Ambiguous(d, _) => Ok(d),
|
||||
LocalResult::None => Err(Value::Error {
|
||||
error: Box::new(ShellError::DatetimeParseError(input.to_string(), span)),
|
||||
LocalResult::None => Err(Value::error(
|
||||
ShellError::DatetimeParseError(input.to_string(), span),
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
}
|
||||
}
|
||||
Err(_) => Err(Value::Error {
|
||||
error: Box::new(ShellError::DatetimeParseError(input.to_string(), span)),
|
||||
Err(_) => Err(Value::error(
|
||||
ShellError::DatetimeParseError(input.to_string(), span),
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,8 +289,5 @@ pub(crate) fn generate_strftime_list(head: Span, show_parse_only_formats: bool)
|
||||
));
|
||||
}
|
||||
|
||||
Value::List {
|
||||
vals: records,
|
||||
span: head,
|
||||
}
|
||||
Value::list(records, head)
|
||||
}
|
||||
|
@ -97,22 +97,22 @@ impl Command for Ast {
|
||||
);
|
||||
Ok(output_record.into_pipeline_data())
|
||||
} else {
|
||||
let block_value = Value::String {
|
||||
val: if minify {
|
||||
let block_value = Value::string(
|
||||
if minify {
|
||||
format!("{block_output:?}")
|
||||
} else {
|
||||
format!("{block_output:#?}")
|
||||
},
|
||||
span: pipeline.span,
|
||||
};
|
||||
let error_value = Value::String {
|
||||
val: if minify {
|
||||
pipeline.span,
|
||||
);
|
||||
let error_value = Value::string(
|
||||
if minify {
|
||||
format!("{error_output:?}")
|
||||
} else {
|
||||
format!("{error_output:#?}")
|
||||
},
|
||||
span: pipeline.span,
|
||||
};
|
||||
pipeline.span,
|
||||
);
|
||||
let output_record = Value::record(
|
||||
record! {
|
||||
"block" => block_value,
|
||||
|
@ -44,15 +44,9 @@ impl Command for Debug {
|
||||
input.map(
|
||||
move |x| {
|
||||
if raw {
|
||||
Value::String {
|
||||
val: x.debug_value(),
|
||||
span: head,
|
||||
}
|
||||
Value::string(x.debug_value(), head)
|
||||
} else {
|
||||
Value::String {
|
||||
val: x.debug_string(", ", &config),
|
||||
span: head,
|
||||
}
|
||||
Value::string(x.debug_string(", ", &config), head)
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
@ -69,23 +63,23 @@ impl Command for Debug {
|
||||
Example {
|
||||
description: "Debug print a list",
|
||||
example: "['hello'] | debug",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("hello")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("hello")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Debug print a table",
|
||||
example:
|
||||
"[[version patch]; ['0.1.0' false] ['0.1.1' true] ['0.2.0' false]] | debug",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("{version: 0.1.0, patch: false}"),
|
||||
Value::test_string("{version: 0.1.1, patch: true}"),
|
||||
Value::test_string("{version: 0.2.0, patch: false}"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -213,10 +213,7 @@ fn get_expression_as_value(
|
||||
) -> Value {
|
||||
match eval_expression(engine_state, stack, inner_expr) {
|
||||
Ok(v) => v,
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span: inner_expr.span,
|
||||
},
|
||||
Err(error) => Value::error(error, inner_expr.span),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +198,7 @@ mod util {
|
||||
|
||||
/// Try to build column names and a table grid.
|
||||
pub fn collect_input(value: Value) -> (Vec<String>, Vec<Vec<String>>) {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Record { val: record, .. } => (
|
||||
record.cols,
|
||||
@ -217,13 +218,10 @@ mod util {
|
||||
|
||||
(columns, data)
|
||||
}
|
||||
Value::String { val, span } => {
|
||||
Value::String { val, .. } => {
|
||||
let lines = val
|
||||
.lines()
|
||||
.map(|line| Value::String {
|
||||
val: line.to_string(),
|
||||
span,
|
||||
})
|
||||
.map(|line| Value::string(line.to_string(), span))
|
||||
.map(|val| vec![debug_string_without_formatting(&val)])
|
||||
.collect();
|
||||
|
||||
|
@ -79,10 +79,7 @@ impl Command for TimeIt {
|
||||
|
||||
let end_time = Instant::now();
|
||||
|
||||
let output = Value::Duration {
|
||||
val: (end_time - start_time).as_nanos() as i64,
|
||||
span: call.head,
|
||||
};
|
||||
let output = Value::duration((end_time - start_time).as_nanos() as i64, call.head);
|
||||
|
||||
Ok(output.into_pipeline_data())
|
||||
}
|
||||
|
@ -34,16 +34,16 @@ impl Command for View {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&View.signature(),
|
||||
&View.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -47,11 +47,7 @@ impl Command for ViewFiles {
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Value::List {
|
||||
vals: records,
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::list(records, call.head).into_pipeline_data())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
8
crates/nu-command/src/env/config/config_.rs
vendored
8
crates/nu-command/src/env/config/config_.rs
vendored
@ -34,16 +34,16 @@ impl Command for ConfigMeta {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&ConfigMeta.signature(),
|
||||
&ConfigMeta.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
|
||||
|
4
crates/nu-command/src/env/export_env.rs
vendored
4
crates/nu-command/src/env/export_env.rs
vendored
@ -58,9 +58,7 @@ impl Command for ExportEnv {
|
||||
Example {
|
||||
description: "Set an environment variable",
|
||||
example: r#"export-env { $env.SPAM = 'eggs' }"#,
|
||||
result: Some(Value::Nothing {
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::nothing(Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Set an environment variable and examine its value",
|
||||
|
@ -159,10 +159,7 @@ impl Command for Cd {
|
||||
}
|
||||
};
|
||||
|
||||
let path_value = Value::String {
|
||||
val: path.clone(),
|
||||
span,
|
||||
};
|
||||
let path_value = Value::string(path.clone(), span);
|
||||
|
||||
if let Some(oldpwd) = stack.get_env_var(engine_state, "PWD") {
|
||||
stack.add_env_var("OLDPWD".into(), oldpwd)
|
||||
|
@ -394,19 +394,13 @@ fn interactive_copy(
|
||||
format!("cp: overwrite '{}'? ", dst.to_string_lossy()),
|
||||
);
|
||||
if let Err(e) = interaction {
|
||||
Value::Error {
|
||||
error: Box::new(ShellError::GenericError(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Value::error(
|
||||
ShellError::GenericError(e.to_string(), e.to_string(), Some(span), None, Vec::new()),
|
||||
span,
|
||||
}
|
||||
)
|
||||
} else if !confirmed {
|
||||
let msg = format!("{:} not copied to {:}", src.display(), dst.display());
|
||||
Value::String { val: msg, span }
|
||||
Value::string(msg, span)
|
||||
} else {
|
||||
copy_impl(src, dst, span, &None)
|
||||
}
|
||||
@ -425,7 +419,7 @@ fn copy_file(
|
||||
match std::fs::copy(&src, &dst) {
|
||||
Ok(_) => {
|
||||
let msg = format!("copied {:} to {:}", src.display(), dst.display());
|
||||
Value::String { val: msg, span }
|
||||
Value::string(msg, span)
|
||||
}
|
||||
Err(e) => convert_io_error(e, src, dst, span),
|
||||
}
|
||||
@ -521,7 +515,7 @@ fn copy_file_with_progressbar(
|
||||
let msg = format!("copied {:} to {:}", src.display(), dst.display());
|
||||
bar.finished_msg(format!(" {} copied!", &file_name));
|
||||
|
||||
Value::String { val: msg, span }
|
||||
Value::string(msg, span)
|
||||
}
|
||||
|
||||
fn copy_symlink(
|
||||
@ -534,16 +528,16 @@ fn copy_symlink(
|
||||
let target_path = match target_path {
|
||||
Ok(p) => p,
|
||||
Err(err) => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::GenericError(
|
||||
return Value::error(
|
||||
ShellError::GenericError(
|
||||
err.to_string(),
|
||||
err.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
vec![],
|
||||
)),
|
||||
),
|
||||
span,
|
||||
}
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
@ -566,18 +560,12 @@ fn copy_symlink(
|
||||
match create_symlink(target_path.as_path(), dst.as_path()) {
|
||||
Ok(_) => {
|
||||
let msg = format!("copied {:} to {:}", src.display(), dst.display());
|
||||
Value::String { val: msg, span }
|
||||
Value::string(msg, span)
|
||||
}
|
||||
Err(e) => Value::Error {
|
||||
error: Box::new(ShellError::GenericError(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
vec![],
|
||||
)),
|
||||
Err(e) => Value::error(
|
||||
ShellError::GenericError(e.to_string(), e.to_string(), Some(span), None, vec![]),
|
||||
span,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,8 +606,5 @@ fn convert_io_error(error: std::io::Error, src: PathBuf, dst: PathBuf, span: Spa
|
||||
_ => ShellError::IOErrorSpanned(message_src, span),
|
||||
};
|
||||
|
||||
Value::Error {
|
||||
error: Box::new(shell_error),
|
||||
span,
|
||||
}
|
||||
Value::error(shell_error, span)
|
||||
}
|
||||
|
@ -142,16 +142,19 @@ impl Command for Glob {
|
||||
let no_files = call.has_flag("no-file");
|
||||
let no_symlinks = call.has_flag("no-symlink");
|
||||
|
||||
let (not_patterns, not_pattern_span): (Vec<String>, Span) = if let Some(Value::List {
|
||||
vals: pats,
|
||||
span: pat_span,
|
||||
}) =
|
||||
call.get_flag(engine_state, stack, "not")?
|
||||
{
|
||||
let p = convert_patterns(pats.as_slice())?;
|
||||
(p, pat_span)
|
||||
} else {
|
||||
(vec![], span)
|
||||
let not_flag: Option<Value> = call.get_flag(engine_state, stack, "not")?;
|
||||
let (not_patterns, not_pattern_span): (Vec<String>, Span) = match not_flag {
|
||||
None => (vec![], span),
|
||||
Some(f) => {
|
||||
let pat_span = f.span();
|
||||
match f {
|
||||
Value::List { vals: pats, .. } => {
|
||||
let p = convert_patterns(pats.as_slice())?;
|
||||
(p, pat_span)
|
||||
}
|
||||
_ => (vec![], span),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if glob_pattern.item.is_empty() {
|
||||
@ -261,10 +264,10 @@ fn glob_to_value<'a>(
|
||||
|| no_files && file_type.is_file()
|
||||
|| no_symlinks && file_type.is_symlink())
|
||||
{
|
||||
result.push(Value::String {
|
||||
val: entry.into_path().to_string_lossy().to_string(),
|
||||
result.push(Value::string(
|
||||
entry.into_path().to_string_lossy().to_string(),
|
||||
span,
|
||||
});
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,19 +255,13 @@ impl Command for Ls {
|
||||
);
|
||||
match entry {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => Some(Value::Error {
|
||||
error: Box::new(err),
|
||||
span: call_span,
|
||||
}),
|
||||
Err(err) => Some(Value::error(err, call_span)),
|
||||
}
|
||||
}
|
||||
Err(err) => Some(Value::Error {
|
||||
error: Box::new(err),
|
||||
span: call_span,
|
||||
}),
|
||||
Err(err) => Some(Value::error(err, call_span)),
|
||||
}
|
||||
}
|
||||
_ => Some(Value::Nothing { span: call_span }),
|
||||
_ => Some(Value::nothing(call_span)),
|
||||
})
|
||||
.into_pipeline_data_with_metadata(
|
||||
Box::new(PipelineMetadata {
|
||||
|
@ -79,7 +79,7 @@ impl Command for Mkdir {
|
||||
|
||||
if is_verbose {
|
||||
let val = format!("{:}", dir.to_string_lossy());
|
||||
stream.push_back(Value::String { val, span });
|
||||
stream.push_back(Value::string(val, span));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,10 +200,7 @@ impl Command for Mv {
|
||||
update_mode,
|
||||
);
|
||||
if let Err(error) = result {
|
||||
Some(Value::Error {
|
||||
error: Box::new(error),
|
||||
span: spanned_source.span,
|
||||
})
|
||||
Some(Value::error(error, spanned_source.span))
|
||||
} else if verbose {
|
||||
let val = match result {
|
||||
Ok(true) => format!(
|
||||
@ -217,7 +214,7 @@ impl Command for Mv {
|
||||
destination.to_string_lossy()
|
||||
),
|
||||
};
|
||||
Some(Value::String { val, span })
|
||||
Some(Value::string(val, span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -428,10 +428,7 @@ fn rm(
|
||||
|
||||
if let Err(e) = result {
|
||||
let msg = format!("Could not delete {:}: {e:}", f.to_string_lossy());
|
||||
Value::Error {
|
||||
error: Box::new(ShellError::RemoveNotPossible(msg, span)),
|
||||
span,
|
||||
}
|
||||
Value::error(ShellError::RemoveNotPossible(msg, span), span)
|
||||
} else if verbose {
|
||||
let msg = if interactive && !confirmed {
|
||||
"not deleted"
|
||||
@ -439,35 +436,35 @@ fn rm(
|
||||
"deleted"
|
||||
};
|
||||
let val = format!("{} {:}", msg, f.to_string_lossy());
|
||||
Value::String { val, span }
|
||||
Value::string(val, span)
|
||||
} else {
|
||||
Value::Nothing { span }
|
||||
Value::nothing(span)
|
||||
}
|
||||
} else {
|
||||
let msg = format!("Cannot remove {:}. try --recursive", f.to_string_lossy());
|
||||
Value::Error {
|
||||
error: Box::new(ShellError::GenericError(
|
||||
Value::error(
|
||||
ShellError::GenericError(
|
||||
msg,
|
||||
"cannot remove non-empty directory".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
),
|
||||
span,
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let msg = format!("no such file or directory: {:}", f.to_string_lossy());
|
||||
Value::Error {
|
||||
error: Box::new(ShellError::GenericError(
|
||||
Value::error(
|
||||
ShellError::GenericError(
|
||||
msg,
|
||||
"no such file or directory".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
),
|
||||
span,
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
.filter(|x| !matches!(x.get_type(), Type::Nothing))
|
||||
|
@ -213,7 +213,7 @@ impl Command for Watch {
|
||||
engine_state,
|
||||
stack,
|
||||
&block,
|
||||
Value::Nothing { span: call.span() }.into_pipeline_data(),
|
||||
Value::nothing(call.span()).into_pipeline_data(),
|
||||
call.redirect_stdout,
|
||||
call.redirect_stderr,
|
||||
);
|
||||
|
@ -42,57 +42,57 @@ only unwrap the outer list, and leave the variable's contents untouched."#
|
||||
Example {
|
||||
example: "[0,1,2,3] | append 4",
|
||||
description: "Append one integer to a list",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
Value::test_int(4),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "0 | append [1 2 3]",
|
||||
description: "Append a list to an item",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: r#""a" | append ["b"] "#,
|
||||
description: "Append a list of string to a string",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("a"), Value::test_string("b")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("a"), Value::test_string("b")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1] | append [2,3,4]",
|
||||
description: "Append three integer items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
Value::test_int(4),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1] | append [2,nu,4,shell]",
|
||||
description: "Append integers and strings",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
@ -100,8 +100,8 @@ only unwrap the outer list, and leave the variable's contents untouched."#
|
||||
Value::test_int(4),
|
||||
Value::test_string("shell"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -128,8 +128,7 @@ only unwrap the outer list, and leave the variable's contents untouched."#
|
||||
fn process_value(val: Value) -> Vec<Value> {
|
||||
match val {
|
||||
Value::List {
|
||||
vals: input_vals,
|
||||
span: _,
|
||||
vals: input_vals, ..
|
||||
} => {
|
||||
let mut output = vec![];
|
||||
for input_val in input_vals {
|
||||
|
@ -36,22 +36,22 @@ impl Command for Columns {
|
||||
Example {
|
||||
example: "{ acronym:PWD, meaning:'Print Working Directory' } | columns",
|
||||
description: "Get the columns from the record",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("acronym"), Value::test_string("meaning")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("acronym"), Value::test_string("meaning")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[[name,age,grade]; [bill,20,a]] | columns",
|
||||
description: "Get the columns from the table",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("name"),
|
||||
Value::test_string("age"),
|
||||
Value::test_string("grade"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[[name,age,grade]; [bill,20,a]] | columns | first",
|
||||
@ -87,30 +87,57 @@ fn getcol(
|
||||
let metadata = input.metadata();
|
||||
match input {
|
||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
||||
PipelineData::Value(
|
||||
Value::List {
|
||||
vals: input_vals,
|
||||
span,
|
||||
},
|
||||
..,
|
||||
) => {
|
||||
let input_cols = get_columns(&input_vals);
|
||||
Ok(input_cols
|
||||
.into_iter()
|
||||
.map(move |x| Value::String { val: x, span })
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
PipelineData::Value(Value::CustomValue { val, span }, ..) => {
|
||||
// TODO: should we get CustomValue to expose columns in a more efficient way?
|
||||
// Would be nice to be able to get columns without generating the whole value
|
||||
let input_as_base_value = val.to_base_value(span)?;
|
||||
let input_cols = get_columns(&[input_as_base_value]);
|
||||
Ok(input_cols
|
||||
.into_iter()
|
||||
.map(move |x| Value::String { val: x, span })
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
PipelineData::Value(v, ..) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::List {
|
||||
vals: input_vals, ..
|
||||
} => {
|
||||
let input_cols = get_columns(&input_vals);
|
||||
Ok(input_cols
|
||||
.into_iter()
|
||||
.map(move |x| Value::string(x, span))
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
Value::CustomValue { val, .. } => {
|
||||
// TODO: should we get CustomValue to expose columns in a more efficient way?
|
||||
// Would be nice to be able to get columns without generating the whole value
|
||||
let input_as_base_value = val.to_base_value(span)?;
|
||||
let input_cols = get_columns(&[input_as_base_value]);
|
||||
Ok(input_cols
|
||||
.into_iter()
|
||||
.map(move |x| Value::string(x, span))
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
Value::LazyRecord { val, .. } => {
|
||||
Ok({
|
||||
// Unfortunate casualty to LazyRecord's column_names not generating 'static strs
|
||||
let cols: Vec<_> =
|
||||
val.column_names().iter().map(|s| s.to_string()).collect();
|
||||
|
||||
cols.into_iter()
|
||||
.map(move |x| Value::string(x, head))
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)
|
||||
})
|
||||
}
|
||||
Value::Record { val, .. } => Ok(val
|
||||
.cols
|
||||
.into_iter()
|
||||
.map(move |x| Value::string(x, head))
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)),
|
||||
// Propagate errors
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
other => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record or table".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
PipelineData::ListStream(stream, ..) => {
|
||||
let v: Vec<_> = stream.into_iter().collect();
|
||||
@ -118,33 +145,10 @@ fn getcol(
|
||||
|
||||
Ok(input_cols
|
||||
.into_iter()
|
||||
.map(move |x| Value::String { val: x, span: head })
|
||||
.map(move |x| Value::string(x, head))
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
PipelineData::Value(Value::LazyRecord { val, .. }, ..) => Ok({
|
||||
// Unfortunate casualty to LazyRecord's column_names not generating 'static strs
|
||||
let cols: Vec<_> = val.column_names().iter().map(|s| s.to_string()).collect();
|
||||
|
||||
cols.into_iter()
|
||||
.map(move |x| Value::String { val: x, span: head })
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)
|
||||
}),
|
||||
PipelineData::Value(Value::Record { val, .. }, ..) => Ok(val
|
||||
.cols
|
||||
.into_iter()
|
||||
.map(move |x| Value::String { val: x, span: head })
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)),
|
||||
// Propagate errors
|
||||
PipelineData::Value(Value::Error { error, .. }, ..) => Err(*error),
|
||||
PipelineData::Value(other, ..) => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record or table".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
PipelineData::ExternalStream { .. } => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record or table".into(),
|
||||
wrong_type: "raw data".into(),
|
||||
|
@ -54,29 +54,26 @@ impl Command for Compact {
|
||||
Example {
|
||||
description: "Filter out all records where 'Hello' is null (returns nothing)",
|
||||
example: r#"[["Hello" "World"]; [null 3]] | compact Hello"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(vec![], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Filter out all records where 'World' is null (Returns the table)",
|
||||
example: r#"[["Hello" "World"]; [null 3]] | compact World"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["Hello".into(), "World".into()],
|
||||
vals: vec![Value::nothing(Span::test_data()), Value::test_int(3)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Filter out all instances of nothing from a list (Returns [1,2])",
|
||||
example: r#"[1, null, 2] | compact"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -57,15 +57,15 @@ impl Command for Default {
|
||||
Example {
|
||||
description: "Replace the `null` value in a list",
|
||||
example: "[1, 2, null, 4] | default 3",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
Value::test_int(4),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -84,31 +84,33 @@ fn default(
|
||||
|
||||
if let Some(column) = column {
|
||||
input.map(
|
||||
move |item| match item {
|
||||
Value::Record {
|
||||
val: mut record,
|
||||
span,
|
||||
} => {
|
||||
let mut idx = 0;
|
||||
let mut found = false;
|
||||
move |item| {
|
||||
let span = item.span();
|
||||
match item {
|
||||
Value::Record {
|
||||
val: mut record, ..
|
||||
} => {
|
||||
let mut idx = 0;
|
||||
let mut found = false;
|
||||
|
||||
while idx < record.len() {
|
||||
if record.cols[idx] == column.item {
|
||||
found = true;
|
||||
if matches!(record.vals[idx], Value::Nothing { .. }) {
|
||||
record.vals[idx] = value.clone();
|
||||
while idx < record.len() {
|
||||
if record.cols[idx] == column.item {
|
||||
found = true;
|
||||
if matches!(record.vals[idx], Value::Nothing { .. }) {
|
||||
record.vals[idx] = value.clone();
|
||||
}
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
if !found {
|
||||
record.push(column.item.clone(), value.clone());
|
||||
}
|
||||
if !found {
|
||||
record.push(column.item.clone(), value.clone());
|
||||
}
|
||||
|
||||
Value::record(record, span)
|
||||
Value::record(record, span)
|
||||
}
|
||||
_ => item,
|
||||
}
|
||||
_ => item,
|
||||
},
|
||||
ctrlc,
|
||||
)
|
||||
|
@ -64,8 +64,8 @@ impl Command for DropColumn {
|
||||
vec![Example {
|
||||
description: "Remove the last column of a table",
|
||||
example: "[[lib, extension]; [nu-lib, rs] [nu-core, rb]] | drop column",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["lib".into()],
|
||||
vals: vec![Value::test_string("nu-lib")],
|
||||
@ -75,8 +75,8 @@ impl Command for DropColumn {
|
||||
vals: vec![Value::test_string("nu-core")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
@ -90,32 +90,6 @@ fn dropcol(
|
||||
let mut keep_columns = vec![];
|
||||
|
||||
match input {
|
||||
PipelineData::Value(
|
||||
Value::List {
|
||||
vals: input_vals,
|
||||
span,
|
||||
},
|
||||
..,
|
||||
) => {
|
||||
let mut output = vec![];
|
||||
let input_cols = get_input_cols(input_vals.clone());
|
||||
let kc = get_keep_columns(input_cols, columns);
|
||||
keep_columns = get_cellpath_columns(kc, span);
|
||||
|
||||
for input_val in input_vals {
|
||||
let mut record = Record::new();
|
||||
|
||||
for path in &keep_columns {
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members, false)?;
|
||||
record.push(path.into_string(), fetcher);
|
||||
}
|
||||
output.push(Value::record(record, span))
|
||||
}
|
||||
|
||||
Ok(output
|
||||
.into_iter()
|
||||
.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
}
|
||||
PipelineData::ListStream(stream, ..) => {
|
||||
let mut output = vec![];
|
||||
|
||||
@ -139,14 +113,39 @@ fn dropcol(
|
||||
.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
}
|
||||
PipelineData::Value(v, ..) => {
|
||||
let mut record = Record::new();
|
||||
let val_span = v.span();
|
||||
if let Value::List {
|
||||
vals: input_vals, ..
|
||||
} = v
|
||||
{
|
||||
let mut output = vec![];
|
||||
let input_cols = get_input_cols(input_vals.clone());
|
||||
let kc = get_keep_columns(input_cols, columns);
|
||||
keep_columns = get_cellpath_columns(kc, val_span);
|
||||
|
||||
for cell_path in &keep_columns {
|
||||
let result = v.clone().follow_cell_path(&cell_path.members, false)?;
|
||||
record.push(cell_path.into_string(), result);
|
||||
for input_val in input_vals {
|
||||
let mut record = Record::new();
|
||||
|
||||
for path in &keep_columns {
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members, false)?;
|
||||
record.push(path.into_string(), fetcher);
|
||||
}
|
||||
output.push(Value::record(record, val_span))
|
||||
}
|
||||
|
||||
Ok(output
|
||||
.into_iter()
|
||||
.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
} else {
|
||||
let mut record = Record::new();
|
||||
|
||||
for cell_path in &keep_columns {
|
||||
let result = v.clone().follow_cell_path(&cell_path.members, false)?;
|
||||
record.push(cell_path.into_string(), result);
|
||||
}
|
||||
|
||||
Ok(Value::record(record, span).into_pipeline_data())
|
||||
}
|
||||
|
||||
Ok(Value::record(record, span).into_pipeline_data())
|
||||
}
|
||||
x => Ok(x),
|
||||
}
|
||||
@ -163,10 +162,7 @@ fn get_input_cols(input: Vec<Value>) -> Vec<String> {
|
||||
fn get_cellpath_columns(keep_cols: Vec<String>, span: Span) -> Vec<CellPath> {
|
||||
let mut output = vec![];
|
||||
for keep_col in keep_cols {
|
||||
let val = Value::String {
|
||||
val: keep_col,
|
||||
span,
|
||||
};
|
||||
let val = Value::string(keep_col, span);
|
||||
let cell_path = match CellPath::from_value(&val) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return vec![],
|
||||
|
@ -41,42 +41,42 @@ impl Command for Drop {
|
||||
Example {
|
||||
example: "[0,1,2,3] | drop",
|
||||
description: "Remove the last item of a list",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3] | drop 0",
|
||||
description: "Remove zero item of a list",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3] | drop 2",
|
||||
description: "Remove the last two items of a list",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Remove the last row in a table",
|
||||
example: "[[a, b]; [1, 2] [3, 4]] | drop 1",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
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(2)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -44,58 +44,55 @@ impl Command for DropNth {
|
||||
Example {
|
||||
example: "[sam,sarah,2,3,4,5] | drop nth 0 1 2",
|
||||
description: "Drop the first, second, and third row",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(3), Value::test_int(4), Value::test_int(5)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(3), Value::test_int(4), Value::test_int(5)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | drop nth 0 1 2",
|
||||
description: "Drop the first, second, and third row",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(3), Value::test_int(4), Value::test_int(5)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(3), Value::test_int(4), Value::test_int(5)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | drop nth 0 2 4",
|
||||
description: "Drop rows 0 2 4",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | drop nth 2 0 4",
|
||||
description: "Drop rows 2 0 4",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Drop range rows from second to fourth",
|
||||
example: "[first second third fourth fifth] | drop nth (1..3)",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("first"), Value::test_string("fifth")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("first"), Value::test_string("fifth")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | drop nth 1..",
|
||||
description: "Drop all rows except first row",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(vec![Value::test_int(0)], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | drop nth 3..",
|
||||
description: "Drop rows 3,4,5",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -145,7 +142,7 @@ impl Command for DropNth {
|
||||
let mut to = to as usize;
|
||||
let from = from as usize;
|
||||
|
||||
if let PipelineData::Value(Value::List { ref vals, span: _ }, _) = input {
|
||||
if let PipelineData::Value(Value::List { ref vals, .. }, _) = input {
|
||||
let max = from + vals.len() - 1;
|
||||
if to > max {
|
||||
to = max;
|
||||
|
@ -57,60 +57,50 @@ with 'transpose' first."#
|
||||
let stream_test_1 = vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)];
|
||||
|
||||
let stream_test_2 = vec![
|
||||
Value::Nothing {
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::nothing(Span::test_data()),
|
||||
Value::test_string("found 2!"),
|
||||
Value::Nothing {
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::nothing(Span::test_data()),
|
||||
];
|
||||
|
||||
vec![
|
||||
Example {
|
||||
example: "[1 2 3] | each {|e| 2 * $e }",
|
||||
description: "Multiplies elements in the list",
|
||||
result: Some(Value::List {
|
||||
vals: stream_test_1,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(stream_test_1, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
example: "{major:2, minor:1, patch:4} | values | each {|| into string }",
|
||||
description: "Produce a list of values in the record, converted to string",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("2"),
|
||||
Value::test_string("1"),
|
||||
Value::test_string("4"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: r#"[1 2 3 2] | each {|e| if $e == 2 { "two" } }"#,
|
||||
description: "Produce a list that has \"two\" for each 2 in the input",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("two"), Value::test_string("two")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("two"), Value::test_string("two")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: r#"[1 2 3] | enumerate | each {|e| if $e.item == 2 { $"found 2 at ($e.index)!"} }"#,
|
||||
description:
|
||||
"Iterate over each element, producing a list showing indexes of any 2s",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("found 2 at 1!")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("found 2 at 1!")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: r#"[1 2 3] | each --keep-empty {|e| if $e == 2 { "found 2!"} }"#,
|
||||
description: "Iterate over each element, keeping null results",
|
||||
result: Some(Value::List {
|
||||
vals: stream_test_2,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(stream_test_2, Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -171,10 +161,7 @@ with 'transpose' first."#
|
||||
Err(ShellError::Break(_)) => None,
|
||||
Err(error) => {
|
||||
let error = chain_error_with_input(error, x_is_error, input_span);
|
||||
Some(Value::Error {
|
||||
error: Box::new(error),
|
||||
span: input_span,
|
||||
})
|
||||
Some(Value::error(error, input_span))
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -195,12 +182,7 @@ with 'transpose' first."#
|
||||
Ok(x) => x,
|
||||
Err(ShellError::Continue(v)) => return Some(Value::nothing(v)),
|
||||
Err(ShellError::Break(_)) => return None,
|
||||
Err(err) => {
|
||||
return Some(Value::Error {
|
||||
error: Box::new(err),
|
||||
span,
|
||||
})
|
||||
}
|
||||
Err(err) => return Some(Value::error(err, span)),
|
||||
};
|
||||
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
@ -224,12 +206,8 @@ with 'transpose' first."#
|
||||
Err(ShellError::Continue(v)) => Some(Value::nothing(v)),
|
||||
Err(ShellError::Break(_)) => None,
|
||||
Err(error) => {
|
||||
let error =
|
||||
Box::new(chain_error_with_input(error, x_is_error, input_span));
|
||||
Some(Value::Error {
|
||||
error,
|
||||
span: input_span,
|
||||
})
|
||||
let error = chain_error_with_input(error, x_is_error, input_span);
|
||||
Some(Value::error(error, input_span))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -31,8 +31,8 @@ impl Command for Enumerate {
|
||||
vec![Example {
|
||||
description: "Add an index to each element of a list",
|
||||
example: r#"[a, b, c] | enumerate "#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["index".into(), "item".into()],
|
||||
vals: vec![Value::test_int(0), Value::test_string("a")],
|
||||
@ -46,8 +46,8 @@ impl Command for Enumerate {
|
||||
vals: vec![Value::test_int(2), Value::test_string("c")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -43,18 +43,18 @@ impl Command for Every {
|
||||
Example {
|
||||
example: "[1 2 3 4 5] | every 2",
|
||||
description: "Get every second row",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[1 2 3 4 5] | every 2 --skip",
|
||||
description: "Skip every second row",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(4)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(4)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -101,10 +101,10 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(error) => Some(Value::Error {
|
||||
error: Box::new(chain_error_with_input(error, x.is_error(), x.span())),
|
||||
span: x.span(),
|
||||
}),
|
||||
Err(error) => Some(Value::error(
|
||||
chain_error_with_input(error, x.is_error(), x.span()),
|
||||
x.span(),
|
||||
)),
|
||||
}
|
||||
})
|
||||
.into_pipeline_data(ctrlc)),
|
||||
@ -120,12 +120,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
|
||||
|
||||
let x = match x {
|
||||
Ok(x) => x,
|
||||
Err(err) => {
|
||||
return Some(Value::Error {
|
||||
error: Box::new(err),
|
||||
span,
|
||||
})
|
||||
}
|
||||
Err(err) => return Some(Value::error(err, span)),
|
||||
};
|
||||
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
@ -150,10 +145,10 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(error) => Some(Value::Error {
|
||||
error: Box::new(chain_error_with_input(error, x.is_error(), x.span())),
|
||||
span: x.span(),
|
||||
}),
|
||||
Err(error) => Some(Value::error(
|
||||
chain_error_with_input(error, x.is_error(), x.span()),
|
||||
x.span(),
|
||||
)),
|
||||
}
|
||||
})
|
||||
.into_pipeline_data(ctrlc)),
|
||||
@ -184,10 +179,10 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(error) => Some(Value::Error {
|
||||
error: Box::new(chain_error_with_input(error, x.is_error(), x.span())),
|
||||
span: x.span(),
|
||||
}),
|
||||
Err(error) => Some(Value::error(
|
||||
chain_error_with_input(error, x.is_error(), x.span()),
|
||||
x.span(),
|
||||
)),
|
||||
}
|
||||
.into_pipeline_data(ctrlc))
|
||||
}
|
||||
@ -200,57 +195,54 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
|
||||
Example {
|
||||
description: "Filter items of a list according to a condition",
|
||||
example: "[1 2] | filter {|x| $x > 1}",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(vec![Value::test_int(2)], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Filter rows of a table according to a condition",
|
||||
example: "[{a: 1} {a: 2}] | filter {|x| $x.a > 1}",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["a".to_string()],
|
||||
vals: vec![Value::test_int(2)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Filter rows of a table according to a stored condition",
|
||||
example: "let cond = {|x| $x.a > 1}; [{a: 1} {a: 2}] | filter $cond",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["a".to_string()],
|
||||
vals: vec![Value::test_int(2)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Filter items of a range according to a condition",
|
||||
example: "9..13 | filter {|el| $el mod 2 != 0}",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(9), Value::test_int(11), Value::test_int(13)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(9), Value::test_int(11), Value::test_int(13)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "List all numbers above 3, using an existing closure condition",
|
||||
example: "let a = {$in > 3}; [1, 2, 5, 6] | filter $a",
|
||||
result: None, // TODO: This should work
|
||||
// result: Some(Value::List {
|
||||
// vals: vec![
|
||||
// result: Some(Value::list(
|
||||
// vec![
|
||||
// Value::Int {
|
||||
// val: 5,
|
||||
// span: Span::test_data(),
|
||||
// Span::test_data(),
|
||||
// },
|
||||
// Value::Int {
|
||||
// val: 6,
|
||||
// span: Span::test_data(),
|
||||
// },
|
||||
// ],
|
||||
// span: Span::test_data(),
|
||||
// Span::test_data(),
|
||||
// }),
|
||||
},
|
||||
]
|
||||
|
@ -87,60 +87,60 @@ impl Command for Find {
|
||||
Example {
|
||||
description: "Search a number or a file size in a list of numbers",
|
||||
example: r#"[1 5 3kb 4 3Mb] | find 5 3kb"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(5), Value::test_filesize(3000)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(5), Value::test_filesize(3000)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Search a char in a list of string",
|
||||
example: r#"[moe larry curly] | find l"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("larry"), Value::test_string("curly")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("larry"), Value::test_string("curly")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find using regex",
|
||||
example: r#"[abc bde arc abf] | find --regex "ab""#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("abc".to_string()),
|
||||
Value::test_string("abf".to_string()),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find using regex case insensitive",
|
||||
example: r#"[aBc bde Arc abf] | find --regex "ab" -i"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("aBc".to_string()),
|
||||
Value::test_string("abf".to_string()),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find value in records using regex",
|
||||
example: r#"[[version name]; ['0.1.0' nushell] ['0.1.1' fish] ['0.2.0' zsh]] | find -r "nu""#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["version".to_string(), "name".to_string()],
|
||||
vals: vec![
|
||||
Value::test_string("0.1.0"),
|
||||
Value::test_string("nushell".to_string()),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find inverted values in records using regex",
|
||||
example: r#"[[version name]; ['0.1.0' nushell] ['0.1.1' fish] ['0.2.0' zsh]] | find -r "nu" --invert"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["version".to_string(), "name".to_string()],
|
||||
vals: vec![
|
||||
@ -156,30 +156,30 @@ impl Command for Find {
|
||||
],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find value in list using regex",
|
||||
example: r#"[["Larry", "Moe"], ["Victor", "Marina"]] | find -r "rr""#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::List {
|
||||
vals: vec![Value::test_string("Larry"), Value::test_string("Moe")],
|
||||
span: Span::test_data(),
|
||||
}],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::list(
|
||||
vec![Value::test_string("Larry"), Value::test_string("Moe")],
|
||||
Span::test_data(),
|
||||
)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Find inverted values in records using regex",
|
||||
example: r#"[["Larry", "Moe"], ["Victor", "Marina"]] | find -r "rr" --invert"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::List {
|
||||
vals: vec![Value::test_string("Victor"), Value::test_string("Marina")],
|
||||
span: Span::test_data(),
|
||||
}],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::list(
|
||||
vec![Value::test_string("Victor"), Value::test_string("Marina")],
|
||||
Span::test_data(),
|
||||
)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Remove ANSI sequences from result",
|
||||
@ -190,8 +190,8 @@ impl Command for Find {
|
||||
description: "Find and highlight text in specific columns",
|
||||
example:
|
||||
"[[col1 col2 col3]; [moe larry curly] [larry curly moe]] | find moe -c [col1]",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["col1".to_string(), "col2".to_string(), "col3".to_string()],
|
||||
vals: vec![
|
||||
Value::test_string(
|
||||
@ -202,8 +202,8 @@ impl Command for Find {
|
||||
Value::test_string("curly".to_string()),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -224,7 +224,7 @@ impl Command for Find {
|
||||
if let Some(regex) = regex {
|
||||
find_with_regex(regex, engine_state, stack, call, input)
|
||||
} else {
|
||||
let input = split_string_if_multiline(input);
|
||||
let input = split_string_if_multiline(input, call.head);
|
||||
find_with_rest_and_highlight(engine_state, stack, call, input)
|
||||
}
|
||||
}
|
||||
@ -331,10 +331,7 @@ fn highlight_terms_in_record_with_search_columns(
|
||||
highlight_search_string(&val_str, term_str, &string_style, &highlight_style)
|
||||
.unwrap_or_else(|_| string_style.paint(term_str).to_string());
|
||||
|
||||
Value::String {
|
||||
val: highlighted_str,
|
||||
span,
|
||||
}
|
||||
Value::string(highlighted_str, span)
|
||||
})
|
||||
.map(|v| v.unwrap_or_else(|v| v));
|
||||
|
||||
@ -388,17 +385,20 @@ fn find_with_rest_and_highlight(
|
||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
||||
PipelineData::Value(_, _) => input
|
||||
.map(
|
||||
move |mut x| match &mut x {
|
||||
Value::Record { val, span } => highlight_terms_in_record_with_search_columns(
|
||||
&cols_to_search_in_map,
|
||||
val,
|
||||
*span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
highlight_style,
|
||||
),
|
||||
_ => x,
|
||||
move |mut x| {
|
||||
let span = x.span();
|
||||
match &mut x {
|
||||
Value::Record { val, .. } => highlight_terms_in_record_with_search_columns(
|
||||
&cols_to_search_in_map,
|
||||
val,
|
||||
span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
highlight_style,
|
||||
),
|
||||
_ => x,
|
||||
}
|
||||
},
|
||||
ctrlc.clone(),
|
||||
)?
|
||||
@ -417,17 +417,20 @@ fn find_with_rest_and_highlight(
|
||||
),
|
||||
PipelineData::ListStream(stream, meta) => Ok(ListStream::from_stream(
|
||||
stream
|
||||
.map(move |mut x| match &mut x {
|
||||
Value::Record { val, span } => highlight_terms_in_record_with_search_columns(
|
||||
&cols_to_search_in_map,
|
||||
val,
|
||||
*span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
highlight_style,
|
||||
),
|
||||
_ => x,
|
||||
.map(move |mut x| {
|
||||
let span = x.span();
|
||||
match &mut x {
|
||||
Value::Record { val, .. } => highlight_terms_in_record_with_search_columns(
|
||||
&cols_to_search_in_map,
|
||||
val,
|
||||
span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
highlight_style,
|
||||
),
|
||||
_ => x,
|
||||
}
|
||||
})
|
||||
.filter(move |value| {
|
||||
value_should_be_printed(
|
||||
@ -451,42 +454,45 @@ fn find_with_rest_and_highlight(
|
||||
let mut output: Vec<Value> = vec![];
|
||||
for filter_val in stream {
|
||||
match filter_val {
|
||||
Ok(value) => match value {
|
||||
Value::String { val, span } => {
|
||||
let split_char = if val.contains("\r\n") { "\r\n" } else { "\n" };
|
||||
Ok(value) => {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::String { val, .. } => {
|
||||
let split_char = if val.contains("\r\n") { "\r\n" } else { "\n" };
|
||||
|
||||
for line in val.split(split_char) {
|
||||
for term in lower_terms.iter() {
|
||||
let term_str = term.into_string("", &filter_config);
|
||||
let lower_val = line.to_lowercase();
|
||||
if lower_val
|
||||
.contains(&term.into_string("", &config).to_lowercase())
|
||||
{
|
||||
output.push(Value::String {
|
||||
val: highlight_search_string(
|
||||
line,
|
||||
&term_str,
|
||||
&string_style,
|
||||
&highlight_style,
|
||||
)?,
|
||||
span,
|
||||
})
|
||||
for line in val.split(split_char) {
|
||||
for term in lower_terms.iter() {
|
||||
let term_str = term.into_string("", &filter_config);
|
||||
let lower_val = line.to_lowercase();
|
||||
if lower_val
|
||||
.contains(&term.into_string("", &config).to_lowercase())
|
||||
{
|
||||
output.push(Value::string(
|
||||
highlight_search_string(
|
||||
line,
|
||||
&term_str,
|
||||
&string_style,
|
||||
&highlight_style,
|
||||
)?,
|
||||
span,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => return Err(*error),
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
"unsupported type from raw stream".into(),
|
||||
format!("input: {:?}", other.get_type()),
|
||||
span,
|
||||
// This line requires the Value::Error match above.
|
||||
other.span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => return Err(*error),
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
"unsupported type from raw stream".into(),
|
||||
format!("input: {:?}", other.get_type()),
|
||||
span,
|
||||
// This line requires the Value::Error match above.
|
||||
other.span(),
|
||||
));
|
||||
}
|
||||
},
|
||||
}
|
||||
// Propagate any errors that were in the stream
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
@ -593,21 +599,17 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn split_string_if_multiline(input: PipelineData) -> PipelineData {
|
||||
fn split_string_if_multiline(input: PipelineData, head_span: Span) -> PipelineData {
|
||||
let span = input.span().unwrap_or(head_span);
|
||||
match input {
|
||||
PipelineData::Value(Value::String { ref val, span }, _) => {
|
||||
PipelineData::Value(Value::String { ref val, .. }, _) => {
|
||||
if val.contains('\n') {
|
||||
Value::List {
|
||||
vals: {
|
||||
val.lines()
|
||||
.map(|s| Value::String {
|
||||
val: s.to_string(),
|
||||
span,
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
Value::list(
|
||||
val.lines()
|
||||
.map(|s| Value::string(s.to_string(), span))
|
||||
.collect(),
|
||||
span,
|
||||
}
|
||||
)
|
||||
.into_pipeline_data()
|
||||
.set_metadata(input.metadata())
|
||||
} else {
|
||||
|
@ -68,18 +68,15 @@ impl Command for First {
|
||||
Example {
|
||||
description: "Return the first 2 items of a list/table",
|
||||
example: "[1 2 3] | first 2",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Return the first 2 bytes of a binary value",
|
||||
example: "0x[01 23 45] | first 2",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x01, 0x23],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0x01, 0x23], Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -115,63 +112,60 @@ fn first_helper(
|
||||
}
|
||||
|
||||
match input {
|
||||
PipelineData::Value(val, _) => match val {
|
||||
Value::List { vals, .. } => {
|
||||
if return_single_element {
|
||||
if vals.is_empty() {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
PipelineData::Value(val, _) => {
|
||||
let span = val.span();
|
||||
match val {
|
||||
Value::List { vals, .. } => {
|
||||
if return_single_element {
|
||||
if vals.is_empty() {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
} else {
|
||||
Ok(vals[0].clone().into_pipeline_data())
|
||||
}
|
||||
} else {
|
||||
Ok(vals[0].clone().into_pipeline_data())
|
||||
Ok(vals
|
||||
.into_iter()
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
} else {
|
||||
Ok(vals
|
||||
.into_iter()
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
Value::Binary { val, span } => {
|
||||
if return_single_element {
|
||||
if val.is_empty() {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
Value::Binary { val, .. } => {
|
||||
if return_single_element {
|
||||
if val.is_empty() {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
} else {
|
||||
Ok(PipelineData::Value(
|
||||
Value::int(val[0] as i64, span),
|
||||
metadata,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(PipelineData::Value(
|
||||
Value::Int {
|
||||
val: val[0] as i64,
|
||||
span,
|
||||
},
|
||||
metadata,
|
||||
))
|
||||
let slice: Vec<u8> = val.into_iter().take(rows_desired).collect();
|
||||
Ok(PipelineData::Value(Value::binary(slice, span), metadata))
|
||||
}
|
||||
} else {
|
||||
let slice: Vec<u8> = val.into_iter().take(rows_desired).collect();
|
||||
Ok(PipelineData::Value(
|
||||
Value::Binary { val: slice, span },
|
||||
metadata,
|
||||
))
|
||||
}
|
||||
}
|
||||
Value::Range { val, .. } => {
|
||||
if return_single_element {
|
||||
Ok(val.from.into_pipeline_data())
|
||||
} else {
|
||||
Ok(val
|
||||
.into_range_iter(ctrlc.clone())?
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
Value::Range { val, .. } => {
|
||||
if return_single_element {
|
||||
Ok(val.from.into_pipeline_data())
|
||||
} else {
|
||||
Ok(val
|
||||
.into_range_iter(ctrlc.clone())?
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
other => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, binary or range".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
other => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, binary or range".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
}
|
||||
PipelineData::ListStream(mut ls, metadata) => {
|
||||
if return_single_element {
|
||||
if let Some(v) = ls.next() {
|
||||
|
@ -52,8 +52,8 @@ impl Command for Flatten {
|
||||
Example {
|
||||
description: "flatten a table",
|
||||
example: "[[N, u, s, h, e, l, l]] | flatten ",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("N"),
|
||||
Value::test_string("u"),
|
||||
Value::test_string("s"),
|
||||
@ -61,8 +61,8 @@ impl Command for Flatten {
|
||||
Value::test_string("e"),
|
||||
Value::test_string("l"),
|
||||
Value::test_string("l")],
|
||||
span: Span::test_data()
|
||||
})
|
||||
Span::test_data()
|
||||
))
|
||||
},
|
||||
Example {
|
||||
description: "flatten a table, get the first item",
|
||||
@ -82,17 +82,17 @@ impl Command for Flatten {
|
||||
Example {
|
||||
description: "Flatten inner table",
|
||||
example: "{ a: b, d: [ 1 2 3 4 ], e: [ 4 3 ] } | flatten d --all",
|
||||
result: Some(Value::List{
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["a".to_string(), "d".to_string(), "e".to_string()],
|
||||
vals: vec![
|
||||
Value::test_string("b"),
|
||||
Value::test_int(1),
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(3)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(3)],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
@ -100,10 +100,10 @@ impl Command for Flatten {
|
||||
vals: vec![
|
||||
Value::test_string("b"),
|
||||
Value::test_int(2),
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(3)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(3)],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
@ -111,10 +111,10 @@ impl Command for Flatten {
|
||||
vals: vec![
|
||||
Value::test_string("b"),
|
||||
Value::test_int(3),
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(3)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(3)],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
@ -122,15 +122,15 @@ impl Command for Flatten {
|
||||
vals: vec![
|
||||
Value::test_string("b"),
|
||||
Value::test_int(4),
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(3)],
|
||||
span: Span::test_data()
|
||||
}
|
||||
Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(3)],
|
||||
Span::test_data()
|
||||
)
|
||||
],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -187,15 +187,15 @@ fn flat_value(columns: &[CellPath], item: &Value, name_tag: Span, all: bool) ->
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => return vec![item.clone()],
|
||||
other => {
|
||||
return vec![Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
return vec![Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: name_tag,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
span: name_tag,
|
||||
}];
|
||||
},
|
||||
name_tag,
|
||||
)];
|
||||
}
|
||||
};
|
||||
|
||||
@ -204,6 +204,7 @@ fn flat_value(columns: &[CellPath], item: &Value, name_tag: Span, all: bool) ->
|
||||
for (column_index, (column, value)) in record.iter().enumerate() {
|
||||
let column_requested = columns.iter().find(|c| c.into_string() == *column);
|
||||
let need_flatten = { columns.is_empty() || column_requested.is_some() };
|
||||
let span = value.span();
|
||||
|
||||
match value {
|
||||
Value::Record { val, .. } => {
|
||||
@ -221,14 +222,14 @@ fn flat_value(columns: &[CellPath], item: &Value, name_tag: Span, all: bool) ->
|
||||
out.insert(column.to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
Value::List { vals, span } if all && vals.iter().all(|f| f.as_record().is_ok()) => {
|
||||
Value::List { vals, .. } if all && vals.iter().all(|f| f.as_record().is_ok()) => {
|
||||
if need_flatten && inner_table.is_some() {
|
||||
return vec![Value::Error{ error: Box::new(ShellError::UnsupportedInput(
|
||||
return vec![Value::error( ShellError::UnsupportedInput(
|
||||
"can only flatten one inner list at a time. tried flattening more than one column with inner lists... but is flattened already".to_string(),
|
||||
"value originates from here".into(),
|
||||
s,
|
||||
*span
|
||||
)), span: *span}
|
||||
span
|
||||
), span)
|
||||
];
|
||||
}
|
||||
// it's a table (a list of record, we can flatten inner record)
|
||||
@ -257,15 +258,15 @@ fn flat_value(columns: &[CellPath], item: &Value, name_tag: Span, all: bool) ->
|
||||
out.insert(column.to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
Value::List { vals: values, span } => {
|
||||
Value::List { vals: values, .. } => {
|
||||
if need_flatten && inner_table.is_some() {
|
||||
return vec![Value::Error{ error: Box::new(ShellError::UnsupportedInput(
|
||||
"can only flatten one inner list at a time. tried flattening more than one column with inner lists... but is flattened already".to_string(),
|
||||
"value originates from here".into(),
|
||||
s,
|
||||
*span
|
||||
)), span: *span}
|
||||
];
|
||||
return vec![Value::error( ShellError::UnsupportedInput(
|
||||
"can only flatten one inner list at a time. tried flattening more than one column with inner lists... but is flattened already".to_string(),
|
||||
"value originates from here".into(),
|
||||
s,
|
||||
span
|
||||
), span)
|
||||
];
|
||||
}
|
||||
|
||||
if !columns.is_empty() {
|
||||
@ -370,7 +371,7 @@ fn flat_value(columns: &[CellPath], item: &Value, name_tag: Span, all: bool) ->
|
||||
}
|
||||
expanded
|
||||
} else if item.as_list().is_ok() {
|
||||
if let Value::List { vals, span: _ } = item {
|
||||
if let Value::List { vals, .. } = item {
|
||||
vals.to_vec()
|
||||
} else {
|
||||
vec![]
|
||||
|
@ -106,10 +106,10 @@ If multiple cell paths are given, this will produce a list of values."#
|
||||
Example {
|
||||
description: "Get a column from a table",
|
||||
example: "[{A: A0}] | get A",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("A0")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("A0")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Get a cell from a table",
|
||||
|
@ -34,23 +34,20 @@ impl Command for Group {
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
let stream_test_1 = vec![
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::List {
|
||||
vals: vec![Value::test_int(3), Value::test_int(4)],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::list(
|
||||
vec![Value::test_int(3), Value::test_int(4)],
|
||||
Span::test_data(),
|
||||
),
|
||||
];
|
||||
|
||||
vec![Example {
|
||||
example: "[1 2 3 4] | group 2",
|
||||
description: "Group the a list by pairs",
|
||||
result: Some(Value::List {
|
||||
vals: stream_test_1,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(stream_test_1, Span::test_data())),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -112,10 +109,7 @@ impl Iterator for EachGroupIterator {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Value::List {
|
||||
vals: group,
|
||||
span: self.span,
|
||||
})
|
||||
Some(Value::list(group, self.span))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,17 +71,17 @@ impl Command for GroupBy {
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["txt".to_string(), "csv".to_string()],
|
||||
vals: vec![
|
||||
Value::List {
|
||||
vals: vec![
|
||||
Value::list(
|
||||
vec![
|
||||
Value::test_string("foo.txt"),
|
||||
Value::test_string("baz.txt"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::List {
|
||||
vals: vec![Value::test_string("bar.csv")],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::list(
|
||||
vec![Value::test_string("bar.csv")],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -92,23 +92,23 @@ impl Command for GroupBy {
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["1".to_string(), "3".to_string(), "2".to_string()],
|
||||
vals: vec![
|
||||
Value::List {
|
||||
vals: vec![
|
||||
Value::list(
|
||||
vec![
|
||||
Value::test_string("1"),
|
||||
Value::test_string("1"),
|
||||
Value::test_string("1"),
|
||||
Value::test_string("1"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::List {
|
||||
vals: vec![Value::test_string("3"), Value::test_string("3")],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::List {
|
||||
vals: vec![Value::test_string("2")],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::list(
|
||||
vec![Value::test_string("3"), Value::test_string("3")],
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::list(
|
||||
vec![Value::test_string("2")],
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -138,18 +138,24 @@ pub fn group_by(
|
||||
}
|
||||
|
||||
let group_value = match grouper {
|
||||
Some(Value::CellPath { val, span }) => group_cell_path(val, values, span)?,
|
||||
Some(Value::Block { .. }) | Some(Value::Closure { .. }) => {
|
||||
let block: Option<Closure> = call.opt(engine_state, stack, 0)?;
|
||||
group_closure(&values, span, block, stack, engine_state, call)?
|
||||
Some(v) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::CellPath { val, .. } => group_cell_path(val, values, span)?,
|
||||
Value::Block { .. } | Value::Closure { .. } => {
|
||||
let block: Option<Closure> = call.opt(engine_state, stack, 0)?;
|
||||
group_closure(&values, span, block, stack, engine_state, call)?
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "unsupported grouper type".to_string(),
|
||||
span,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
None => group_no_grouper(values, span)?,
|
||||
_ => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "unsupported grouper type".to_string(),
|
||||
span,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(PipelineData::Value(group_value, None))
|
||||
@ -213,10 +219,7 @@ fn group_closure(
|
||||
) -> Result<Value, ShellError> {
|
||||
let error_key = "error";
|
||||
let mut keys: Vec<Result<String, ShellError>> = vec![];
|
||||
let value_list = Value::List {
|
||||
vals: values.clone(),
|
||||
span,
|
||||
};
|
||||
let value_list = Value::list(values.clone(), span);
|
||||
|
||||
for value in values {
|
||||
if let Some(capture_block) = &block {
|
||||
|
@ -36,8 +36,8 @@ impl Command for Headers {
|
||||
Example {
|
||||
description: "Sets the column names for a table created by `split column`",
|
||||
example: r#""a b c|1 2 3" | split row "|" | split column " " | headers"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: columns.clone(),
|
||||
vals: vec![
|
||||
Value::test_string("1"),
|
||||
@ -45,14 +45,14 @@ impl Command for Headers {
|
||||
Value::test_string("3"),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Columns which don't have data in their first row are removed",
|
||||
example: r#""a b c|1 2 3|1 2 3 4" | split row "|" | split column " " | headers"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: columns.clone(),
|
||||
vals: vec![
|
||||
@ -70,8 +70,8 @@ impl Command for Headers {
|
||||
],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -98,8 +98,9 @@ fn replace_headers(
|
||||
old_headers: &[String],
|
||||
new_headers: &[String],
|
||||
) -> Result<Value, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Record { val, span } => Ok(Value::record(
|
||||
Value::Record { val, .. } => Ok(Value::record(
|
||||
val.into_iter()
|
||||
.filter_map(|(col, val)| {
|
||||
old_headers
|
||||
@ -110,14 +111,14 @@ fn replace_headers(
|
||||
.collect(),
|
||||
span,
|
||||
)),
|
||||
Value::List { vals, span } => {
|
||||
Value::List { vals, .. } => {
|
||||
let vals = vals
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.map(|value| replace_headers(value, old_headers, new_headers))
|
||||
.collect::<Result<Vec<Value>, ShellError>>()?;
|
||||
|
||||
Ok(Value::List { vals, span })
|
||||
Ok(Value::list(vals, span))
|
||||
}
|
||||
_ => Err(ShellError::TypeMismatch {
|
||||
err_message: "record".to_string(),
|
||||
@ -129,11 +130,11 @@ fn replace_headers(
|
||||
fn is_valid_header(value: &Value) -> bool {
|
||||
matches!(
|
||||
value,
|
||||
Value::Nothing { span: _ }
|
||||
| Value::String { val: _, span: _ }
|
||||
| Value::Bool { val: _, span: _ }
|
||||
| Value::Float { val: _, span: _ }
|
||||
| Value::Int { val: _, span: _ }
|
||||
Value::Nothing { .. }
|
||||
| Value::String { val: _, .. }
|
||||
| Value::Bool { val: _, .. }
|
||||
| Value::Float { val: _, .. }
|
||||
| Value::Int { val: _, .. }
|
||||
)
|
||||
}
|
||||
|
||||
@ -141,6 +142,7 @@ fn extract_headers(
|
||||
value: &Value,
|
||||
config: &Config,
|
||||
) -> Result<(Vec<String>, Vec<String>), ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Record { val: record, .. } => {
|
||||
for v in &record.vals {
|
||||
@ -170,7 +172,7 @@ fn extract_headers(
|
||||
|
||||
Ok((old_headers, new_headers))
|
||||
}
|
||||
Value::List { vals, span } => vals
|
||||
Value::List { vals, .. } => vals
|
||||
.iter()
|
||||
.map(|value| extract_headers(value, config))
|
||||
.next()
|
||||
@ -178,7 +180,7 @@ fn extract_headers(
|
||||
ShellError::GenericError(
|
||||
"Found empty list".to_string(),
|
||||
"unable to extract headers".to_string(),
|
||||
Some(*span),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
|
@ -72,19 +72,19 @@ impl Command for Insert {
|
||||
Example {
|
||||
description: "Insert a new column into a table, populating all rows",
|
||||
example: "[[project, lang]; ['Nushell', 'Rust']] | insert type 'shell'",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list (
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["project".into(), "lang".into(), "type".into()],
|
||||
vals: vec![Value::test_string("Nushell"), Value::test_string("Rust"), Value::test_string("shell")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Insert a column with values equal to their row index, plus the value of 'foo' in each row",
|
||||
example: "[[foo]; [7] [8] [9]] | enumerate | insert bar {|e| $e.item.foo + $e.index } | flatten",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list (
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["index".into(), "foo".into(), "bar".into()],
|
||||
vals: vec![
|
||||
@ -110,8 +110,8 @@ impl Command for Insert {
|
||||
],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
@ -173,18 +173,12 @@ fn insert(
|
||||
pd.into_value(span),
|
||||
span,
|
||||
) {
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
};
|
||||
return Value::error(e, span);
|
||||
}
|
||||
|
||||
input
|
||||
}
|
||||
Err(e) => Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
},
|
||||
Err(e) => Value::error(e, span),
|
||||
}
|
||||
},
|
||||
ctrlc,
|
||||
@ -198,7 +192,7 @@ fn insert(
|
||||
if let Some(v) = input.next() {
|
||||
pre_elems.push(v);
|
||||
} else {
|
||||
pre_elems.push(Value::Nothing { span })
|
||||
pre_elems.push(Value::nothing(span))
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,10 +209,7 @@ fn insert(
|
||||
if let Err(e) =
|
||||
input.insert_data_at_cell_path(&cell_path.members, replacement, span)
|
||||
{
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
};
|
||||
return Value::error(e, span);
|
||||
}
|
||||
|
||||
input
|
||||
|
@ -87,10 +87,7 @@ impl Command for Items {
|
||||
Err(ShellError::Break(_)) => None,
|
||||
Err(error) => {
|
||||
let error = chain_error_with_input(error, false, input_span);
|
||||
Some(Value::Error {
|
||||
error: Box::new(error),
|
||||
span,
|
||||
})
|
||||
Some(Value::error(error, span))
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -129,13 +126,13 @@ impl Command for Items {
|
||||
example:
|
||||
"{ new: york, san: francisco } | items {|key, value| echo $'($key) ($value)' }",
|
||||
description: "Iterate over each key-value pair of a record",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("new york"),
|
||||
Value::test_string("san francisco"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
@ -110,26 +110,13 @@ impl Command for Join {
|
||||
vec![Example {
|
||||
description: "Join two tables",
|
||||
example: "[{a: 1 b: 2}] | join [{a: 1 c: 3}] a",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["a".into(), "b".into(), "c".into()],
|
||||
vals: vec![
|
||||
Value::Int {
|
||||
val: 1,
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Int {
|
||||
val: 2,
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Int {
|
||||
val: 3,
|
||||
span: Span::test_data(),
|
||||
},
|
||||
],
|
||||
vals: vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
@ -253,7 +240,7 @@ fn join(
|
||||
span,
|
||||
);
|
||||
}
|
||||
Value::List { vals: result, span }
|
||||
Value::list(result, span)
|
||||
}
|
||||
|
||||
// Join rows of `this` (a nushell table) to rows of `other` (a lookup-table
|
||||
|
@ -54,10 +54,10 @@ impl Command for Last {
|
||||
Example {
|
||||
example: "[1,2,3] | last 2",
|
||||
description: "Return the last 2 items of a list/table",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(3)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(3)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[1,2,3] | last",
|
||||
@ -67,10 +67,7 @@ impl Command for Last {
|
||||
Example {
|
||||
example: "0x[01 23 45] | last 2",
|
||||
description: "Return the last 2 bytes of a binary value",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x23, 0x45],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0x23, 0x45], Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -129,55 +126,56 @@ impl Command for Last {
|
||||
Ok(buf.into_pipeline_data(ctrlc).set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
PipelineData::Value(val, _) => match val {
|
||||
Value::List { vals, .. } => {
|
||||
if return_single_element {
|
||||
if let Some(v) = vals.last() {
|
||||
Ok(v.clone().into_pipeline_data())
|
||||
PipelineData::Value(val, _) => {
|
||||
let val_span = val.span();
|
||||
|
||||
match val {
|
||||
Value::List { vals, .. } => {
|
||||
if return_single_element {
|
||||
if let Some(v) = vals.last() {
|
||||
Ok(v.clone().into_pipeline_data())
|
||||
} else {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
Ok(vals
|
||||
.into_iter()
|
||||
.rev()
|
||||
.take(rows_desired)
|
||||
.rev()
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
} else {
|
||||
Ok(vals
|
||||
.into_iter()
|
||||
.rev()
|
||||
.take(rows_desired)
|
||||
.rev()
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
Value::Binary { val, span } => {
|
||||
if return_single_element {
|
||||
if let Some(b) = val.last() {
|
||||
Value::Binary { val, .. } => {
|
||||
if return_single_element {
|
||||
if let Some(b) = val.last() {
|
||||
Ok(PipelineData::Value(
|
||||
Value::int(*b as i64, val_span),
|
||||
metadata,
|
||||
))
|
||||
} else {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
}
|
||||
} else {
|
||||
let slice: Vec<u8> =
|
||||
val.into_iter().rev().take(rows_desired).rev().collect();
|
||||
Ok(PipelineData::Value(
|
||||
Value::Int {
|
||||
val: *b as i64,
|
||||
span,
|
||||
},
|
||||
Value::binary(slice, val_span),
|
||||
metadata,
|
||||
))
|
||||
} else {
|
||||
Err(ShellError::AccessEmptyContent { span: head })
|
||||
}
|
||||
} else {
|
||||
let slice: Vec<u8> =
|
||||
val.into_iter().rev().take(rows_desired).rev().collect();
|
||||
Ok(PipelineData::Value(
|
||||
Value::Binary { val: slice, span },
|
||||
metadata,
|
||||
))
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
other => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, binary or range".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
other => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, binary or range".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
}
|
||||
PipelineData::ExternalStream { span, .. } => {
|
||||
Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, binary or range".into(),
|
||||
|
@ -56,13 +56,14 @@ impl Command for Length {
|
||||
}
|
||||
|
||||
fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
|
||||
let span = input.span().unwrap_or(call.head);
|
||||
match input {
|
||||
PipelineData::Value(Value::Nothing { .. }, ..) => {
|
||||
Ok(Value::int(0, call.head).into_pipeline_data())
|
||||
}
|
||||
// I added this here because input_output_type() wasn't catching a record
|
||||
// being sent in as input from echo. e.g. "echo {a:1 b:2} | length"
|
||||
PipelineData::Value(Value::Record { span, .. }, ..) => {
|
||||
PipelineData::Value(Value::Record { .. }, ..) => {
|
||||
Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, and table".into(),
|
||||
wrong_type: "record".into(),
|
||||
|
@ -27,7 +27,6 @@ impl Command for Lines {
|
||||
.switch("skip-empty", "skip empty lines", Some('s'))
|
||||
.category(Category::Filters)
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
@ -42,12 +41,13 @@ impl Command for Lines {
|
||||
// match \r\n or \n
|
||||
static LINE_BREAK_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"\r\n|\n").expect("unable to compile regex"));
|
||||
let span = input.span().unwrap_or(call.head);
|
||||
match input {
|
||||
#[allow(clippy::needless_collect)]
|
||||
// Collect is needed because the string may not live long enough for
|
||||
// the Rc structure to continue using it. If split could take ownership
|
||||
// of the split values, then this wouldn't be needed
|
||||
PipelineData::Value(Value::String { val, span }, ..) => {
|
||||
PipelineData::Value(Value::String { val, .. }, ..) => {
|
||||
let mut lines = LINE_BREAK_REGEX
|
||||
.split(&val)
|
||||
.map(|s| s.to_string())
|
||||
@ -76,7 +76,8 @@ impl Command for Lines {
|
||||
let iter = stream
|
||||
.into_iter()
|
||||
.filter_map(move |value| {
|
||||
if let Value::String { val, span } = value {
|
||||
let span = value.span();
|
||||
if let Value::String { val, .. } = value {
|
||||
let mut lines = LINE_BREAK_REGEX
|
||||
.split(&val)
|
||||
.filter_map(|s| {
|
||||
@ -96,11 +97,7 @@ impl Command for Lines {
|
||||
}
|
||||
}
|
||||
|
||||
Some(
|
||||
lines
|
||||
.into_iter()
|
||||
.map(move |x| Value::String { val: x, span }),
|
||||
)
|
||||
Some(lines.into_iter().map(move |x| Value::string(x, span)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -129,10 +126,7 @@ impl Command for Lines {
|
||||
.enumerate()
|
||||
.map(move |(_idx, x)| match x {
|
||||
Ok(x) => x,
|
||||
Err(err) => Value::Error {
|
||||
error: Box::new(err),
|
||||
span: head,
|
||||
},
|
||||
Err(err) => Value::error(err, head),
|
||||
})
|
||||
.into_pipeline_data(ctrlc)),
|
||||
}
|
||||
@ -142,10 +136,10 @@ impl Command for Lines {
|
||||
vec![Example {
|
||||
description: "Split multi-line string into lines",
|
||||
example: r#"$"two\nlines" | lines"#,
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("two"), Value::test_string("lines")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("two"), Value::test_string("lines")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
@ -175,10 +169,7 @@ impl Iterator for RawStreamLinesAdapter {
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(Ok(Value::String {
|
||||
val: s,
|
||||
span: self.span,
|
||||
}));
|
||||
return Some(Ok(Value::string(s, self.span)));
|
||||
} else {
|
||||
// inner is complete, feed out remaining state
|
||||
if self.inner_complete {
|
||||
@ -198,9 +189,10 @@ impl Iterator for RawStreamLinesAdapter {
|
||||
if let Some(result) = self.inner.next() {
|
||||
match result {
|
||||
Ok(v) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
// TODO: Value::Binary support required?
|
||||
Value::String { val, span } => {
|
||||
Value::String { val, .. } => {
|
||||
self.span = span;
|
||||
|
||||
let mut lines = LINE_BREAK_REGEX
|
||||
|
@ -46,8 +46,8 @@ repeating this process with row 1, and so on."#
|
||||
Example {
|
||||
example: "[a b c] | wrap name | merge ( [1 2 3] | wrap index )",
|
||||
description: "Add an 'index' column to the input table",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["name".to_string(), "index".to_string()],
|
||||
vals: vec![Value::test_string("a"), Value::test_int(1)],
|
||||
@ -61,8 +61,8 @@ repeating this process with row 1, and so on."#
|
||||
vals: vec![Value::test_string("c"), Value::test_int(3)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "{a: 1, b: 2} | merge {c: 3}",
|
||||
@ -75,13 +75,13 @@ repeating this process with row 1, and so on."#
|
||||
Example {
|
||||
example: "[{columnA: A0 columnB: B0}] | merge [{columnA: 'A0*'}]",
|
||||
description: "Merge two tables, overwriting overlapping columns",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["columnA".to_string(), "columnB".to_string()],
|
||||
vals: vec![Value::test_string("A0*"), Value::test_string("B0")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -113,16 +113,10 @@ repeating this process with row 1, and so on."#
|
||||
.map(move |inp| match (inp.as_record(), table_iter.next()) {
|
||||
(Ok(inp), Some(to_merge)) => match to_merge.as_record() {
|
||||
Ok(to_merge) => Value::record(do_merge(inp, to_merge), call.head),
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span: call.head,
|
||||
},
|
||||
Err(error) => Value::error(error, call.head),
|
||||
},
|
||||
(_, None) => inp,
|
||||
(Err(error), _) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span: call.head,
|
||||
},
|
||||
(Err(error), _) => Value::error(error, call.head),
|
||||
});
|
||||
|
||||
if let Some(md) = metadata {
|
||||
|
@ -52,8 +52,8 @@ impl Command for Move {
|
||||
example: "[[name value index]; [foo a 1] [bar b 2] [baz c 3]] | move index --before name",
|
||||
description: "Move a column before the first column",
|
||||
result:
|
||||
Some(Value::List {
|
||||
vals: vec![
|
||||
Some(Value::list (
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["index".to_string(), "name".to_string(), "value".to_string()],
|
||||
vals: vec![Value::test_int(1), Value::test_string("foo"), Value::test_string("a")],
|
||||
@ -67,15 +67,15 @@ impl Command for Move {
|
||||
vals: vec![Value::test_int(3), Value::test_string("baz"), Value::test_string("c")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
})
|
||||
Span::test_data(),
|
||||
))
|
||||
},
|
||||
Example {
|
||||
example: "[[name value index]; [foo a 1] [bar b 2] [baz c 3]] | move value name --after index",
|
||||
description: "Move multiple columns after the last column and reorder them",
|
||||
result:
|
||||
Some(Value::List {
|
||||
vals: vec![
|
||||
Some(Value::list (
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["index".to_string(), "value".to_string(), "name".to_string()],
|
||||
vals: vec![Value::test_int(1), Value::test_string("a"), Value::test_string("foo")],
|
||||
@ -89,8 +89,8 @@ impl Command for Move {
|
||||
vals: vec![Value::test_int(3), Value::test_string("c"), Value::test_string("baz")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
})
|
||||
Span::test_data(),
|
||||
))
|
||||
},
|
||||
Example {
|
||||
example: "{ name: foo, value: a, index: 1 } | move name --before index",
|
||||
@ -153,16 +153,10 @@ impl Command for Move {
|
||||
Ok(record) => {
|
||||
match move_record_columns(record, &columns, &before_or_after, call.head) {
|
||||
Ok(val) => val,
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span: call.head,
|
||||
},
|
||||
Err(error) => Value::error(error, call.head),
|
||||
}
|
||||
}
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span: call.head,
|
||||
},
|
||||
Err(error) => Value::error(error, call.head),
|
||||
});
|
||||
|
||||
if let Some(md) = metadata {
|
||||
|
@ -57,31 +57,31 @@ impl Command for ParEach {
|
||||
Example {
|
||||
example: r#"[foo bar baz] | par-each {|e| $e + '!' } | sort"#,
|
||||
description: "Output can still be sorted afterward",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("bar!"),
|
||||
Value::test_string("baz!"),
|
||||
Value::test_string("foo!"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: r#"1..3 | enumerate | par-each {|p| update item ($p.item * 2)} | sort-by item | get item"#,
|
||||
description: "Enumerate and sort-by can be used to reconstruct the original order",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: r#"[1 2 3] | enumerate | par-each { |e| if $e.item == 2 { $"found 2 at ($e.index)!"} }"#,
|
||||
description:
|
||||
"Iterate over each element, producing a list showing indexes of any 2s",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("found 2 at 1!")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("found 2 at 1!")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -154,12 +154,10 @@ impl Command for ParEach {
|
||||
) {
|
||||
Ok(v) => v.into_value(span),
|
||||
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(chain_error_with_input(
|
||||
error, x_is_error, val_span,
|
||||
)),
|
||||
span: val_span,
|
||||
},
|
||||
Err(error) => Value::error(
|
||||
chain_error_with_input(error, x_is_error, val_span),
|
||||
val_span,
|
||||
),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
@ -192,12 +190,10 @@ impl Command for ParEach {
|
||||
redirect_stderr,
|
||||
) {
|
||||
Ok(v) => v.into_value(span),
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(chain_error_with_input(
|
||||
error, x_is_error, val_span,
|
||||
)),
|
||||
span: val_span,
|
||||
},
|
||||
Err(error) => Value::error(
|
||||
chain_error_with_input(error, x_is_error, val_span),
|
||||
val_span,
|
||||
),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
@ -230,12 +226,10 @@ impl Command for ParEach {
|
||||
redirect_stderr,
|
||||
) {
|
||||
Ok(v) => v.into_value(span),
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(chain_error_with_input(
|
||||
error, x_is_error, val_span,
|
||||
)),
|
||||
span: val_span,
|
||||
},
|
||||
Err(error) => Value::error(
|
||||
chain_error_with_input(error, x_is_error, val_span),
|
||||
val_span,
|
||||
),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
@ -252,12 +246,7 @@ impl Command for ParEach {
|
||||
.map(move |x| {
|
||||
let x = match x {
|
||||
Ok(x) => x,
|
||||
Err(err) => {
|
||||
return Value::Error {
|
||||
error: Box::new(err),
|
||||
span,
|
||||
}
|
||||
}
|
||||
Err(err) => return Value::error(err, span),
|
||||
};
|
||||
|
||||
let block = engine_state.get_block(block_id);
|
||||
@ -279,10 +268,7 @@ impl Command for ParEach {
|
||||
redirect_stderr,
|
||||
) {
|
||||
Ok(v) => v.into_value(span),
|
||||
Err(error) => Value::Error {
|
||||
error: Box::new(error),
|
||||
span,
|
||||
},
|
||||
Err(error) => Value::error(error, span),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -45,57 +45,57 @@ only unwrap the outer list, and leave the variable's contents untouched."#
|
||||
Example {
|
||||
example: "0 | prepend [1 2 3]",
|
||||
description: "prepend a list to an item",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
Value::test_int(0),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: r#""a" | prepend ["b"] "#,
|
||||
description: "Prepend a list of strings to a string",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("b"), Value::test_string("a")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("b"), Value::test_string("a")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[1,2,3,4] | prepend 0",
|
||||
description: "Prepend one integer item",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
Value::test_int(4),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[2,3,4] | prepend [0,1]",
|
||||
description: "Prepend two integer items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
Value::test_int(4),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[2,nu,4,shell] | prepend [0,1,rocks]",
|
||||
description: "Prepend integers and strings",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(0),
|
||||
Value::test_int(1),
|
||||
Value::test_string("rocks"),
|
||||
@ -104,8 +104,8 @@ only unwrap the outer list, and leave the variable's contents untouched."#
|
||||
Value::test_int(4),
|
||||
Value::test_string("shell"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -132,8 +132,7 @@ only unwrap the outer list, and leave the variable's contents untouched."#
|
||||
fn process_value(val: Value) -> Vec<Value> {
|
||||
match val {
|
||||
Value::List {
|
||||
vals: input_vals,
|
||||
span: _,
|
||||
vals: input_vals, ..
|
||||
} => {
|
||||
let mut output = vec![];
|
||||
for input_val in input_vals {
|
||||
|
@ -38,26 +38,26 @@ impl Command for Range {
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | range 4..5",
|
||||
description: "Get the last 2 items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(5)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(5)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | range (-2)..",
|
||||
description: "Get the last 2 items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(5)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(5)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[0,1,2,3,4,5] | range (-3)..-2",
|
||||
description: "Get the next to last 2 items",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(3), Value::test_int(4)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(3), Value::test_int(4)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -99,10 +99,7 @@ impl Command for Range {
|
||||
};
|
||||
|
||||
if from > to {
|
||||
Ok(PipelineData::Value(
|
||||
Value::Nothing { span: call.head },
|
||||
None,
|
||||
))
|
||||
Ok(PipelineData::Value(Value::nothing(call.head), None))
|
||||
} else {
|
||||
let iter = v.into_iter().skip(from).take(to - from + 1);
|
||||
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
@ -112,10 +109,7 @@ impl Command for Range {
|
||||
let to = rows_to as usize;
|
||||
|
||||
if from > to {
|
||||
Ok(PipelineData::Value(
|
||||
Value::Nothing { span: call.head },
|
||||
None,
|
||||
))
|
||||
Ok(PipelineData::Value(Value::nothing(call.head), None))
|
||||
} else {
|
||||
let iter = input.into_iter().skip(from).take(to - from + 1);
|
||||
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
|
@ -62,13 +62,13 @@ impl Command for Reject {
|
||||
Example {
|
||||
description: "Reject a column in a table",
|
||||
example: "[[a, b]; [1, 2]] | reject a",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["b".to_string()],
|
||||
vals: vec![Value::test_int(2)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Reject the specified field in a record",
|
||||
|
@ -55,35 +55,35 @@ impl Command for Rename {
|
||||
Example {
|
||||
description: "Rename a column",
|
||||
example: "[[a, b]; [1, 2]] | rename my_column",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["my_column".to_string(), "b".to_string()],
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rename many columns",
|
||||
example: "[[a, b, c]; [1, 2, 3]] | rename eggs ham bacon",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["eggs".to_string(), "ham".to_string(), "bacon".to_string()],
|
||||
vals: vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rename a specific column",
|
||||
example: "[[a, b, c]; [1, 2, 3]] | rename -c [a ham]",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["ham".to_string(), "b".to_string(), "c".to_string()],
|
||||
vals: vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Rename the fields of a record",
|
||||
@ -113,19 +113,23 @@ fn rename(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let specified_column: Option<Vec<String>> = call.get_flag(engine_state, stack, "column")?;
|
||||
// get the span for the column's name to be changed and for the given list
|
||||
let (specified_col_span, list_span) = if let Some(Value::List {
|
||||
vals: columns,
|
||||
span: column_span,
|
||||
}) = call.get_flag(engine_state, stack, "column")?
|
||||
{
|
||||
if columns.is_empty() {
|
||||
return Err(ShellError::TypeMismatch { err_message: "The column list cannot be empty and must contain only two values: the column's name and its replacement value"
|
||||
let column_flag: Option<Value> = call.get_flag(engine_state, stack, "column")?;
|
||||
let (specified_col_span, list_span) = match column_flag {
|
||||
Some(column_flag) => {
|
||||
let column_span = column_flag.span();
|
||||
match column_flag {
|
||||
Value::List { vals: columns, .. } => {
|
||||
if columns.is_empty() {
|
||||
return Err(ShellError::TypeMismatch { err_message: "The column list cannot be empty and must contain only two values: the column's name and its replacement value"
|
||||
.to_string(), span: column_span });
|
||||
} else {
|
||||
(Some(columns[0].span()), column_span)
|
||||
} else {
|
||||
(Some(columns[0].span()), column_span)
|
||||
}
|
||||
}
|
||||
_ => (None, call.head),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(None, call.head)
|
||||
None => (None, call.head),
|
||||
};
|
||||
|
||||
if let Some(ref cols) = specified_column {
|
||||
@ -155,100 +159,92 @@ fn rename(
|
||||
let head_span = call.head;
|
||||
input
|
||||
.map(
|
||||
move |item| match item {
|
||||
Value::Record {
|
||||
val: mut record,
|
||||
span,
|
||||
} => {
|
||||
if let Some((engine_state, block, mut stack, env_vars, env_hidden)) =
|
||||
block_info.clone()
|
||||
{
|
||||
for c in &mut record.cols {
|
||||
stack.with_env(&env_vars, &env_hidden);
|
||||
move |item| {
|
||||
let span = item.span();
|
||||
match item {
|
||||
Value::Record {
|
||||
val: mut record, ..
|
||||
} => {
|
||||
if let Some((engine_state, block, mut stack, env_vars, env_hidden)) =
|
||||
block_info.clone()
|
||||
{
|
||||
for c in &mut record.cols {
|
||||
stack.with_env(&env_vars, &env_hidden);
|
||||
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
if let Some(var_id) = &var.var_id {
|
||||
stack.add_var(*var_id, Value::string(c.clone(), span))
|
||||
}
|
||||
}
|
||||
let eval_result = eval_block_with_early_return(
|
||||
&engine_state,
|
||||
&mut stack,
|
||||
&block,
|
||||
Value::string(c.clone(), span).into_pipeline_data(),
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
);
|
||||
match eval_result {
|
||||
Err(e) => {
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
if let Some(var_id) = &var.var_id {
|
||||
stack.add_var(*var_id, Value::string(c.clone(), span))
|
||||
}
|
||||
}
|
||||
Ok(res) => match res.collect_string_strict(span) {
|
||||
Err(e) => {
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
let eval_result = eval_block_with_early_return(
|
||||
&engine_state,
|
||||
&mut stack,
|
||||
&block,
|
||||
Value::string(c.clone(), span).into_pipeline_data(),
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
);
|
||||
match eval_result {
|
||||
Err(e) => return Value::error(e, span),
|
||||
Ok(res) => match res.collect_string_strict(span) {
|
||||
Err(e) => return Value::error(e, span),
|
||||
Ok(new_c) => *c = new_c.0,
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match &specified_column {
|
||||
Some(c) => {
|
||||
// check if the specified column to be renamed exists
|
||||
if !record.cols.contains(&c[0]) {
|
||||
return Value::error(
|
||||
ShellError::UnsupportedInput(
|
||||
format!(
|
||||
"The column '{}' does not exist in the input",
|
||||
&c[0]
|
||||
),
|
||||
"value originated from here".into(),
|
||||
// Arrow 1 points at the specified column name,
|
||||
specified_col_span.unwrap_or(head_span),
|
||||
// Arrow 2 points at the input value.
|
||||
span,
|
||||
),
|
||||
span,
|
||||
);
|
||||
}
|
||||
for (idx, val) in record.cols.iter_mut().enumerate() {
|
||||
if *val == c[0] {
|
||||
record.cols[idx] = c[1].to_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(new_c) => *c = new_c.0,
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match &specified_column {
|
||||
Some(c) => {
|
||||
// check if the specified column to be renamed exists
|
||||
if !record.cols.contains(&c[0]) {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
format!(
|
||||
"The column '{}' does not exist in the input",
|
||||
&c[0]
|
||||
),
|
||||
"value originated from here".into(),
|
||||
// Arrow 1 points at the specified column name,
|
||||
specified_col_span.unwrap_or(head_span),
|
||||
// Arrow 2 points at the input value.
|
||||
span,
|
||||
)),
|
||||
span,
|
||||
};
|
||||
}
|
||||
for (idx, val) in record.cols.iter_mut().enumerate() {
|
||||
if *val == c[0] {
|
||||
record.cols[idx] = c[1].to_string();
|
||||
break;
|
||||
None => {
|
||||
for (idx, val) in columns.iter().enumerate() {
|
||||
if idx >= record.len() {
|
||||
// skip extra new columns names if we already reached the final column
|
||||
break;
|
||||
}
|
||||
record.cols[idx] = val.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
for (idx, val) in columns.iter().enumerate() {
|
||||
if idx >= record.len() {
|
||||
// skip extra new columns names if we already reached the final column
|
||||
break;
|
||||
}
|
||||
record.cols[idx] = val.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value::record(record, span)
|
||||
Value::record(record, span)
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => item.clone(),
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head_span,
|
||||
src_span: other.span(),
|
||||
},
|
||||
head_span,
|
||||
),
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => item.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head_span,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
span: head_span,
|
||||
},
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
|
@ -38,21 +38,21 @@ impl Command for Reverse {
|
||||
Example {
|
||||
example: "[0,1,2,3] | reverse",
|
||||
description: "Reverse a list",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(3),
|
||||
Value::test_int(2),
|
||||
Value::test_int(1),
|
||||
Value::test_int(0),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[{a: 1} {a: 2}] | reverse",
|
||||
description: "Reverse a 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(2)],
|
||||
@ -62,8 +62,8 @@ impl Command for Reverse {
|
||||
vals: vec![Value::test_int(1)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -151,13 +151,13 @@ produce a table, a list will produce a list, and a record will produce a record.
|
||||
Example {
|
||||
description: "Select a column in a table",
|
||||
example: "[{a: a b: b}] | select a",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list (
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["a".to_string()],
|
||||
vals: vec![Value::test_string("a")]
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Select a field in a record",
|
||||
@ -250,44 +250,65 @@ fn select(
|
||||
};
|
||||
|
||||
match input {
|
||||
PipelineData::Value(
|
||||
Value::List {
|
||||
vals: input_vals,
|
||||
span,
|
||||
},
|
||||
metadata,
|
||||
..,
|
||||
) => {
|
||||
let mut output = vec![];
|
||||
let mut columns_with_value = Vec::new();
|
||||
for input_val in input_vals {
|
||||
if !columns.is_empty() {
|
||||
let mut record = Record::new();
|
||||
for path in &columns {
|
||||
//FIXME: improve implementation to not clone
|
||||
match input_val.clone().follow_cell_path(&path.members, false) {
|
||||
Ok(fetcher) => {
|
||||
record.push(path.into_string().replace('.', "_"), fetcher);
|
||||
if !columns_with_value.contains(&path) {
|
||||
columns_with_value.push(path);
|
||||
PipelineData::Value(v, metadata, ..) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::List {
|
||||
vals: input_vals, ..
|
||||
} => {
|
||||
let mut output = vec![];
|
||||
let mut columns_with_value = Vec::new();
|
||||
for input_val in input_vals {
|
||||
if !columns.is_empty() {
|
||||
let mut record = Record::new();
|
||||
for path in &columns {
|
||||
//FIXME: improve implementation to not clone
|
||||
match input_val.clone().follow_cell_path(&path.members, false) {
|
||||
Ok(fetcher) => {
|
||||
record.push(path.into_string().replace('.', "_"), fetcher);
|
||||
if !columns_with_value.contains(&path) {
|
||||
columns_with_value.push(path);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
output.push(Value::record(record, span))
|
||||
} else {
|
||||
output.push(input_val)
|
||||
}
|
||||
}
|
||||
|
||||
output.push(Value::record(record, span))
|
||||
} else {
|
||||
output.push(input_val)
|
||||
Ok(output
|
||||
.into_iter()
|
||||
.into_pipeline_data(engine_state.ctrlc.clone())
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
_ => {
|
||||
if !columns.is_empty() {
|
||||
let mut record = Record::new();
|
||||
|
||||
for cell_path in columns {
|
||||
// FIXME: remove clone
|
||||
match v.clone().follow_cell_path(&cell_path.members, false) {
|
||||
Ok(result) => {
|
||||
record.push(cell_path.into_string().replace('.', "_"), result);
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::record(record, call_span)
|
||||
.into_pipeline_data()
|
||||
.set_metadata(metadata))
|
||||
} else {
|
||||
Ok(v.into_pipeline_data().set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(output
|
||||
.into_iter()
|
||||
.into_pipeline_data(engine_state.ctrlc.clone())
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
PipelineData::ListStream(stream, metadata, ..) => {
|
||||
let mut values = vec![];
|
||||
@ -314,27 +335,6 @@ fn select(
|
||||
.into_pipeline_data(engine_state.ctrlc.clone())
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
PipelineData::Value(v, metadata, ..) => {
|
||||
if !columns.is_empty() {
|
||||
let mut record = Record::new();
|
||||
|
||||
for cell_path in columns {
|
||||
// FIXME: remove clone
|
||||
match v.clone().follow_cell_path(&cell_path.members, false) {
|
||||
Ok(result) => {
|
||||
record.push(cell_path.into_string().replace('.', "_"), result);
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::record(record, call_span)
|
||||
.into_pipeline_data()
|
||||
.set_metadata(metadata))
|
||||
} else {
|
||||
Ok(v.into_pipeline_data().set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
_ => Ok(PipelineData::empty()),
|
||||
}
|
||||
}
|
||||
|
@ -46,25 +46,24 @@ impl Command for Skip {
|
||||
Example {
|
||||
description: "Skip the first value of a list",
|
||||
example: "[2 4 6 8] | skip 1",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(4), Value::test_int(6), Value::test_int(8)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(4), Value::test_int(6), Value::test_int(8)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Skip two rows of a table",
|
||||
example: "[[editions]; [2015] [2018] [2021]] | skip 2",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["editions".to_owned()],
|
||||
vals: vec![Value::test_int(2021)],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
@ -73,27 +72,33 @@ impl Command for Skip {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let n: Option<Value> = call.opt(engine_state, stack, 0)?;
|
||||
let span = call.head;
|
||||
let metadata = input.metadata();
|
||||
|
||||
let n: usize = match n {
|
||||
Some(Value::Int { val, span }) => {
|
||||
val.try_into().map_err(|err| ShellError::TypeMismatch {
|
||||
err_message: format!("Could not convert {val} to unsigned integer: {err}"),
|
||||
span,
|
||||
})?
|
||||
}
|
||||
Some(_) => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "expected integer".into(),
|
||||
span,
|
||||
})
|
||||
Some(v) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::Int { val, .. } => {
|
||||
val.try_into().map_err(|err| ShellError::TypeMismatch {
|
||||
err_message: format!(
|
||||
"Could not convert {val} to unsigned integer: {err}"
|
||||
),
|
||||
span,
|
||||
})?
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "expected integer".into(),
|
||||
span,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
None => 1,
|
||||
};
|
||||
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
|
||||
let input_span = input.span().unwrap_or(call.head);
|
||||
match input {
|
||||
PipelineData::ExternalStream {
|
||||
stdout: Some(stream),
|
||||
@ -130,17 +135,14 @@ impl Command for Skip {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Binary {
|
||||
val: output,
|
||||
span: bytes_span,
|
||||
}
|
||||
.into_pipeline_data()
|
||||
.set_metadata(metadata))
|
||||
Ok(Value::binary(output, bytes_span)
|
||||
.into_pipeline_data()
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
PipelineData::Value(Value::Binary { val, span }, metadata) => {
|
||||
PipelineData::Value(Value::Binary { val, .. }, metadata) => {
|
||||
let bytes = val.into_iter().skip(n).collect::<Vec<_>>();
|
||||
|
||||
Ok(Value::Binary { val: bytes, span }
|
||||
Ok(Value::binary(bytes, input_span)
|
||||
.into_pipeline_data()
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
|
@ -44,24 +44,24 @@ impl Command for SkipUntil {
|
||||
Example {
|
||||
description: "Skip until the element is positive",
|
||||
example: "[-2 0 2 -1] | skip until {|x| $x > 0 }",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(-1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(-1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Skip until the element is positive using stored condition",
|
||||
example: "let cond = {|x| $x > 0 }; [-2 0 2 -1] | skip until $cond",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(-1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(-1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Skip until the field value is positive",
|
||||
example: "[{a: -2} {a: 0} {a: 2} {a: -1}] | skip until {|x| $x.a > 0 }",
|
||||
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(2)],
|
||||
@ -71,8 +71,8 @@ impl Command for SkipUntil {
|
||||
vals: vec![Value::test_int(-1)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -44,24 +44,24 @@ impl Command for SkipWhile {
|
||||
Example {
|
||||
description: "Skip while the element is negative",
|
||||
example: "[-2 0 2 -1] | skip while {|x| $x < 0 }",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(2), Value::test_int(-1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(2), Value::test_int(-1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Skip while the element is negative using stored condition",
|
||||
example: "let cond = {|x| $x < 0 }; [-2 0 2 -1] | skip while $cond",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(2), Value::test_int(-1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(2), Value::test_int(-1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Skip while the field value is negative",
|
||||
example: "[{a: -2} {a: 0} {a: 2} {a: -1}] | skip while {|x| $x.a < 0 }",
|
||||
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(0)],
|
||||
@ -75,8 +75,8 @@ impl Command for SkipWhile {
|
||||
vals: vec![Value::test_int(-1)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -49,66 +49,66 @@ impl Command for Sort {
|
||||
Example {
|
||||
example: "[2 0 1] | sort",
|
||||
description: "sort the list by increasing value",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[2 0 1] | sort -r",
|
||||
description: "sort the list by decreasing value",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(1), Value::test_int(0)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(1), Value::test_int(0)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[betty amy sarah] | sort",
|
||||
description: "sort a list of strings",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("amy"),
|
||||
Value::test_string("betty"),
|
||||
Value::test_string("sarah"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "[betty amy sarah] | sort -r",
|
||||
description: "sort a list of strings in reverse",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("sarah"),
|
||||
Value::test_string("betty"),
|
||||
Value::test_string("amy"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Sort strings (case-insensitive)",
|
||||
example: "[airplane Truck Car] | sort -i",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("airplane"),
|
||||
Value::test_string("Car"),
|
||||
Value::test_string("Truck"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Sort strings (reversed case-insensitive)",
|
||||
example: "[airplane Truck Car] | sort -i -r",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("Truck"),
|
||||
Value::test_string("Car"),
|
||||
Value::test_string("airplane"),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Sort record by key (case-insensitive)",
|
||||
@ -141,9 +141,10 @@ impl Command for Sort {
|
||||
let natural = call.has_flag("natural");
|
||||
let metadata = &input.metadata();
|
||||
|
||||
let span = input.span().unwrap_or(call.head);
|
||||
match input {
|
||||
// Records have two sorting methods, toggled by presence or absence of -v
|
||||
PipelineData::Value(Value::Record { val, span }, ..) => {
|
||||
PipelineData::Value(Value::Record { val, .. }, ..) => {
|
||||
let sort_by_value = call.has_flag("values");
|
||||
let record = sort_record(val, span, sort_by_value, reverse, insensitive, natural);
|
||||
Ok(record.into_pipeline_data())
|
||||
@ -257,20 +258,20 @@ pub fn sort(
|
||||
}
|
||||
_ => {
|
||||
vec.sort_by(|a, b| {
|
||||
let span_a = a.span();
|
||||
let span_b = b.span();
|
||||
if insensitive {
|
||||
let lowercase_left = match a {
|
||||
Value::String { val, span } => Value::String {
|
||||
val: val.to_ascii_lowercase(),
|
||||
span: *span,
|
||||
},
|
||||
Value::String { val, .. } => {
|
||||
Value::string(val.to_ascii_lowercase(), span_a)
|
||||
}
|
||||
_ => a.clone(),
|
||||
};
|
||||
|
||||
let lowercase_right = match b {
|
||||
Value::String { val, span } => Value::String {
|
||||
val: val.to_ascii_lowercase(),
|
||||
span: *span,
|
||||
},
|
||||
Value::String { val, .. } => {
|
||||
Value::string(val.to_ascii_lowercase(), span_b)
|
||||
}
|
||||
_ => b.clone(),
|
||||
};
|
||||
|
||||
@ -311,30 +312,26 @@ pub fn process(
|
||||
|
||||
let left_res = match left_value {
|
||||
Some(left_res) => left_res,
|
||||
None => Value::Nothing { span },
|
||||
None => Value::nothing(span),
|
||||
};
|
||||
|
||||
let right_value = right.get_data_by_key(column);
|
||||
|
||||
let right_res = match right_value {
|
||||
Some(right_res) => right_res,
|
||||
None => Value::Nothing { span },
|
||||
None => Value::nothing(span),
|
||||
};
|
||||
|
||||
let result = if insensitive {
|
||||
let span_left = left_res.span();
|
||||
let span_right = right_res.span();
|
||||
let lowercase_left = match left_res {
|
||||
Value::String { val, span } => Value::String {
|
||||
val: val.to_ascii_lowercase(),
|
||||
span,
|
||||
},
|
||||
Value::String { val, .. } => Value::string(val.to_ascii_lowercase(), span_left),
|
||||
_ => left_res,
|
||||
};
|
||||
|
||||
let lowercase_right = match right_res {
|
||||
Value::String { val, span } => Value::String {
|
||||
val: val.to_ascii_lowercase(),
|
||||
span,
|
||||
},
|
||||
Value::String { val, .. } => Value::string(val.to_ascii_lowercase(), span_right),
|
||||
_ => right_res,
|
||||
};
|
||||
if natural {
|
||||
|
@ -58,8 +58,8 @@ impl Command for SortBy {
|
||||
Example {
|
||||
description: "Sort a table by a column (reversed order)",
|
||||
example: "[[fruit count]; [apple 9] [pear 3] [orange 7]] | sort-by fruit -r",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["fruit".to_string(), "count".to_string()],
|
||||
vals: vec![Value::test_string("pear"), Value::test_int(3)],
|
||||
@ -73,8 +73,8 @@ impl Command for SortBy {
|
||||
vals: vec![Value::test_string("apple"), Value::test_int(9)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ impl Command for SplitBy {
|
||||
vals: vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["2019".to_string()],
|
||||
vals: vec![Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
vals: vec![Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec![
|
||||
"name".to_string(),
|
||||
"lang".to_string(),
|
||||
@ -66,14 +66,14 @@ impl Command for SplitBy {
|
||||
Value::test_string("2019"),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}],
|
||||
Span::test_data(),
|
||||
)],
|
||||
}),
|
||||
Value::test_record(Record {
|
||||
cols: vec!["2019".to_string(), "2021".to_string()],
|
||||
vals: vec![
|
||||
Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec![
|
||||
"name".to_string(),
|
||||
"lang".to_string(),
|
||||
@ -85,10 +85,10 @@ impl Command for SplitBy {
|
||||
Value::test_string("2019"),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec![
|
||||
"name".to_string(),
|
||||
"lang".to_string(),
|
||||
@ -100,8 +100,8 @@ impl Command for SplitBy {
|
||||
Value::test_string("2021"),
|
||||
],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
}),
|
||||
],
|
||||
@ -215,20 +215,34 @@ pub fn data_split(
|
||||
let mut splits = indexmap::IndexMap::new();
|
||||
|
||||
match value {
|
||||
PipelineData::Value(Value::Record { val: grouped, span }, _) => {
|
||||
for (idx, list) in grouped.vals.iter().enumerate() {
|
||||
match data_group(list, splitter, span) {
|
||||
Ok(grouped_vals) => {
|
||||
if let Value::Record { val: sub, .. } = grouped_vals {
|
||||
for (inner_idx, subset) in sub.vals.iter().enumerate() {
|
||||
let s: &mut IndexMap<String, Value> =
|
||||
splits.entry(sub.cols[inner_idx].clone()).or_default();
|
||||
PipelineData::Value(v, _) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::Record { val: grouped, .. } => {
|
||||
for (idx, list) in grouped.vals.iter().enumerate() {
|
||||
match data_group(list, splitter, span) {
|
||||
Ok(grouped_vals) => {
|
||||
if let Value::Record { val: sub, .. } = grouped_vals {
|
||||
for (inner_idx, subset) in sub.vals.iter().enumerate() {
|
||||
let s: &mut IndexMap<String, Value> =
|
||||
splits.entry(sub.cols[inner_idx].clone()).or_default();
|
||||
|
||||
s.insert(grouped.cols[idx].clone(), subset.clone());
|
||||
s.insert(grouped.cols[idx].clone(), subset.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(reason) => return Err(reason),
|
||||
}
|
||||
}
|
||||
Err(reason) => return Err(reason),
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::GenericError(
|
||||
"unsupported input".into(),
|
||||
"requires a table with one row for splitting".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,33 +54,33 @@ impl Command for Take {
|
||||
let metadata = input.metadata();
|
||||
|
||||
match input {
|
||||
PipelineData::Value(val, _) => match val {
|
||||
Value::List { vals, .. } => Ok(vals
|
||||
.into_iter()
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)),
|
||||
Value::Binary { val, span } => {
|
||||
let slice: Vec<u8> = val.into_iter().take(rows_desired).collect();
|
||||
Ok(PipelineData::Value(
|
||||
Value::Binary { val: slice, span },
|
||||
metadata,
|
||||
))
|
||||
PipelineData::Value(val, _) => {
|
||||
let span = val.span();
|
||||
match val {
|
||||
Value::List { vals, .. } => Ok(vals
|
||||
.into_iter()
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)),
|
||||
Value::Binary { val, .. } => {
|
||||
let slice: Vec<u8> = val.into_iter().take(rows_desired).collect();
|
||||
Ok(PipelineData::Value(Value::binary(slice, span), metadata))
|
||||
}
|
||||
Value::Range { val, .. } => Ok(val
|
||||
.into_range_iter(ctrlc.clone())?
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
other => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, binary or range".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: call.head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
}
|
||||
Value::Range { val, .. } => Ok(val
|
||||
.into_range_iter(ctrlc.clone())?
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
.set_metadata(metadata)),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
other => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "list, binary or range".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: call.head,
|
||||
src_span: other.span(),
|
||||
}),
|
||||
},
|
||||
}
|
||||
PipelineData::ListStream(ls, metadata) => Ok(ls
|
||||
.take(rows_desired)
|
||||
.into_pipeline_data(ctrlc)
|
||||
@ -107,24 +107,21 @@ impl Command for Take {
|
||||
Example {
|
||||
description: "Return the first item of a list/table",
|
||||
example: "[1 2 3] | take 1",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(vec![Value::test_int(1)], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Return the first 2 items of a list/table",
|
||||
example: "[1 2 3] | take 2",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Return the first two rows of a table",
|
||||
example: "[[editions]; [2015] [2018] [2021]] | take 2",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["editions".to_string()],
|
||||
vals: vec![Value::test_int(2015)],
|
||||
@ -134,24 +131,21 @@ impl Command for Take {
|
||||
vals: vec![Value::test_int(2018)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Return the first 2 bytes of a binary value",
|
||||
example: "0x[01 23 45] | take 2",
|
||||
result: Some(Value::Binary {
|
||||
val: vec![0x01, 0x23],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::binary(vec![0x01, 0x23], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Return the first 3 elements of a range",
|
||||
example: "1..10 | take 3",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -40,24 +40,24 @@ impl Command for TakeUntil {
|
||||
Example {
|
||||
description: "Take until the element is positive",
|
||||
example: "[-1 -2 9 1] | take until {|x| $x > 0 }",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Take until the element is positive using stored condition",
|
||||
example: "let cond = {|x| $x > 0 }; [-1 -2 9 1] | take until $cond",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Take until the field value is positive",
|
||||
example: "[{a: -1} {a: -2} {a: 9} {a: 1}] | take until {|x| $x.a > 0 }",
|
||||
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)],
|
||||
@ -67,8 +67,8 @@ impl Command for TakeUntil {
|
||||
vals: vec![Value::test_int(-2)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -40,24 +40,24 @@ impl Command for TakeWhile {
|
||||
Example {
|
||||
description: "Take while the element is negative",
|
||||
example: "[-1 -2 9 1] | take while {|x| $x < 0 }",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Take while the element is negative using stored condition",
|
||||
example: "let cond = {|x| $x < 0 }; [-1 -2 9 1] | take while $cond",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(-1), Value::test_int(-2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Take while the field value is negative",
|
||||
example: "[{a: -1} {a: -2} {a: 9} {a: 1}] | take while {|x| $x.a < 0 }",
|
||||
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)],
|
||||
@ -67,8 +67,8 @@ impl Command for TakeWhile {
|
||||
vals: vec![Value::test_int(-2)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -88,8 +88,8 @@ impl Command for Transpose {
|
||||
Example {
|
||||
description: "Transposes the table contents with default column names",
|
||||
example: "[[c1 c2]; [1 2]] | transpose",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["column0".to_string(), "column1".to_string()],
|
||||
vals: vec![Value::test_string("c1"), Value::test_int(1)],
|
||||
@ -100,13 +100,13 @@ impl Command for Transpose {
|
||||
}),
|
||||
],
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Transposes the table contents with specified column names",
|
||||
example: "[[c1 c2]; [1 2]] | transpose key val",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["key".to_string(), "val".to_string()],
|
||||
vals: vec![Value::test_string("c1"), Value::test_int(1)],
|
||||
@ -117,14 +117,14 @@ impl Command for Transpose {
|
||||
}),
|
||||
],
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Transposes the table without column names and specify a new column name",
|
||||
example: "[[c1 c2]; [1 2]] | transpose -i val",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["val".to_string()],
|
||||
vals: vec![Value::test_int(1)],
|
||||
@ -135,7 +135,7 @@ impl Command for Transpose {
|
||||
}),
|
||||
],
|
||||
span,
|
||||
}),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Transfer back to record with -d flag",
|
||||
@ -260,19 +260,14 @@ pub fn transpose(
|
||||
.iter()
|
||||
.position(|y| y == &headers[column_num])
|
||||
.expect("value is contained.");
|
||||
let current_span = record.vals[index].span();
|
||||
let new_val = match &record.vals[index] {
|
||||
Value::List { vals, span } => {
|
||||
Value::List { vals, .. } => {
|
||||
let mut vals = vals.clone();
|
||||
vals.push(x.clone());
|
||||
Value::List {
|
||||
vals: vals.to_vec(),
|
||||
span: *span,
|
||||
}
|
||||
Value::list(vals.to_vec(), current_span)
|
||||
}
|
||||
v => Value::List {
|
||||
vals: vec![v.clone(), x.clone()],
|
||||
span: v.span(),
|
||||
},
|
||||
v => Value::list(vec![v.clone(), x.clone()], v.span()),
|
||||
};
|
||||
record.cols.remove(index);
|
||||
record.vals.remove(index);
|
||||
@ -298,19 +293,14 @@ pub fn transpose(
|
||||
.iter()
|
||||
.position(|y| y == &headers[column_num])
|
||||
.expect("value is contained.");
|
||||
let current_span = record.vals[index].span();
|
||||
let new_val = match &record.vals[index] {
|
||||
Value::List { vals, span } => {
|
||||
Value::List { vals, .. } => {
|
||||
let mut vals = vals.clone();
|
||||
vals.push(Value::nothing(name));
|
||||
Value::List {
|
||||
vals: vals.to_vec(),
|
||||
span: *span,
|
||||
}
|
||||
Value::list(vals.to_vec(), current_span)
|
||||
}
|
||||
v => Value::List {
|
||||
vals: vec![v.clone(), Value::nothing(name)],
|
||||
span: v.span(),
|
||||
},
|
||||
v => Value::list(vec![v.clone(), Value::nothing(name)], v.span()),
|
||||
};
|
||||
record.cols.remove(index);
|
||||
record.vals.remove(index);
|
||||
|
@ -88,40 +88,40 @@ impl Command for Uniq {
|
||||
Example {
|
||||
description: "Return the distinct values of a list/table (remove duplicates so that each value occurs once only)",
|
||||
example: "[2 3 3 4] | uniq",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(4)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(3), Value::test_int(4)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Return the input values that occur more than once",
|
||||
example: "[1 2 2] | uniq -d",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Return the input values that occur once only",
|
||||
example: "[1 2 2] | uniq -u",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(1)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(1)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Ignore differences in case when comparing input values",
|
||||
example: "['hello' 'goodbye' 'Hello'] | uniq -i",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("hello"), Value::test_string("goodbye")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("hello"), Value::test_string("goodbye")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Return a table containing the distinct input values together with their counts",
|
||||
example: "[1 2 2] | uniq -c",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["value".to_string(), "count".to_string()],
|
||||
vals: vec![Value::test_int(1), Value::test_int(1)],
|
||||
@ -131,8 +131,8 @@ impl Command for Uniq {
|
||||
vals: vec![Value::test_int(2), Value::test_int(2)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -185,29 +185,27 @@ impl ValueCounter {
|
||||
}
|
||||
|
||||
fn clone_to_lowercase(value: &Value) -> Value {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::String { val: s, span } => Value::String {
|
||||
val: s.clone().to_lowercase(),
|
||||
span: *span,
|
||||
},
|
||||
Value::List { vals: vec, span } => Value::List {
|
||||
vals: vec.iter().map(clone_to_lowercase).collect(),
|
||||
span: *span,
|
||||
},
|
||||
Value::Record { val: record, span } => Value::record(
|
||||
Value::String { val: s, .. } => Value::string(s.clone().to_lowercase(), span),
|
||||
Value::List { vals: vec, .. } => {
|
||||
Value::list(vec.iter().map(clone_to_lowercase).collect(), span)
|
||||
}
|
||||
Value::Record { val: record, .. } => Value::record(
|
||||
Record {
|
||||
cols: record.cols.clone(),
|
||||
vals: record.vals.iter().map(clone_to_lowercase).collect(),
|
||||
},
|
||||
*span,
|
||||
span,
|
||||
),
|
||||
other => other.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_attributes(val: Value) -> Value {
|
||||
let span = val.span();
|
||||
match val {
|
||||
Value::Record { val, span } => {
|
||||
Value::Record { val, .. } => {
|
||||
let sorted = val
|
||||
.into_iter()
|
||||
.sorted_by(|a, b| a.0.cmp(&b.0))
|
||||
@ -227,10 +225,9 @@ fn sort_attributes(val: Value) -> Value {
|
||||
span,
|
||||
)
|
||||
}
|
||||
Value::List { vals, span } => Value::List {
|
||||
vals: vals.into_iter().map(sort_attributes).collect_vec(),
|
||||
span,
|
||||
},
|
||||
Value::List { vals, .. } => {
|
||||
Value::list(vals.into_iter().map(sort_attributes).collect_vec(), span)
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
@ -321,12 +318,9 @@ pub fn uniq(
|
||||
uniq_values.into_iter().map(|v| v.val).collect()
|
||||
};
|
||||
|
||||
Ok(Value::List {
|
||||
vals: result,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data()
|
||||
.set_metadata(metadata))
|
||||
Ok(Value::list(result, head)
|
||||
.into_pipeline_data()
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
|
||||
fn sort(iter: IntoIter<String, ValueCounter>) -> Vec<ValueCounter> {
|
||||
|
@ -92,8 +92,8 @@ impl Command for UniqBy {
|
||||
vec![Example {
|
||||
description: "Get rows from table filtered by column uniqueness ",
|
||||
example: "[[fruit count]; [apple 9] [apple 2] [pear 3] [orange 7]] | uniq-by fruit",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["fruit".to_string(), "count".to_string()],
|
||||
vals: vec![Value::test_string("apple"), Value::test_int(9)],
|
||||
@ -107,35 +107,35 @@ impl Command for UniqBy {
|
||||
vals: vec![Value::test_string("orange"), Value::test_int(7)],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(vec: Vec<Value>, columns: &Vec<String>, span: Span) -> Result<(), ShellError> {
|
||||
if let Some(Value::Record {
|
||||
val: record,
|
||||
span: val_span,
|
||||
}) = vec.first()
|
||||
{
|
||||
if columns.is_empty() {
|
||||
// This uses the same format as the 'requires a column name' error in split_by.rs
|
||||
return Err(ShellError::GenericError(
|
||||
"expected name".into(),
|
||||
"requires a column name to filter table data".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
}
|
||||
let first = vec.first();
|
||||
if let Some(v) = first {
|
||||
let val_span = v.span();
|
||||
if let Value::Record { val: record, .. } = &v {
|
||||
if columns.is_empty() {
|
||||
// This uses the same format as the 'requires a column name' error in split_by.rs
|
||||
return Err(ShellError::GenericError(
|
||||
"expected name".into(),
|
||||
"requires a column name to filter table data".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(nonexistent) = nonexistent_column(columns.clone(), record.cols.clone()) {
|
||||
return Err(ShellError::CantFindColumn {
|
||||
col_name: nonexistent,
|
||||
span,
|
||||
src_span: *val_span,
|
||||
});
|
||||
if let Some(nonexistent) = nonexistent_column(columns.clone(), record.cols.clone()) {
|
||||
return Err(ShellError::CantFindColumn {
|
||||
col_name: nonexistent,
|
||||
span,
|
||||
src_span: val_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,10 +155,7 @@ fn item_mapper_by_col(cols: Vec<String>) -> impl Fn(crate::ItemMapperState) -> c
|
||||
Box::new(move |ms: crate::ItemMapperState| -> crate::ValueCounter {
|
||||
let item_column_values = get_data_by_columns(&columns, &ms.item);
|
||||
|
||||
let col_vals = Value::List {
|
||||
vals: item_column_values,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let col_vals = Value::list(item_column_values, Span::unknown());
|
||||
|
||||
crate::ValueCounter::new_vals_to_compare(ms.item, ms.flag_ignore_case, col_vals, ms.index)
|
||||
})
|
||||
|
@ -65,35 +65,35 @@ impl Command for Update {
|
||||
Example {
|
||||
description: "Use in closure form for more involved updating logic",
|
||||
example: "[[count fruit]; [1 'apple']] | enumerate | update item.count {|e| ($e.item.fruit | str length) + $e.index } | get item",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["count".into(), "fruit".into()],
|
||||
vals: vec![Value::test_int(5), Value::test_string("apple")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Alter each value in the 'authors' column to use a single string instead of a list",
|
||||
example: "[[project, authors]; ['nu', ['Andrés', 'JT', 'Yehuda']]] | update authors {|row| $row.authors | str join ','}",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["project".into(), "authors".into()],
|
||||
vals: vec![Value::test_string("nu"), Value::test_string("Andrés,JT,Yehuda")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "You can also use a simple command to update 'authors' to a single string",
|
||||
example: "[[project, authors]; ['nu', ['Andrés', 'JT', 'Yehuda']]] | update authors {|| str join ','}",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["project".into(), "authors".into()],
|
||||
vals: vec![Value::test_string("nu"), Value::test_string("Andrés,JT,Yehuda")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -140,12 +140,7 @@ fn update(
|
||||
|
||||
let input_at_path = match input.clone().follow_cell_path(&cell_path.members, false)
|
||||
{
|
||||
Err(e) => {
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
}
|
||||
}
|
||||
Err(e) => return Value::error(e, span),
|
||||
Ok(v) => v,
|
||||
};
|
||||
let output = eval_block(
|
||||
@ -162,18 +157,12 @@ fn update(
|
||||
if let Err(e) =
|
||||
input.update_data_at_cell_path(&cell_path.members, pd.into_value(span))
|
||||
{
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
};
|
||||
return Value::error(e, span);
|
||||
}
|
||||
|
||||
input
|
||||
}
|
||||
Err(e) => Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
},
|
||||
Err(e) => Value::error(e, span),
|
||||
}
|
||||
},
|
||||
ctrlc,
|
||||
@ -210,10 +199,7 @@ fn update(
|
||||
let replacement = replacement.clone();
|
||||
|
||||
if let Err(e) = input.update_data_at_cell_path(&cell_path.members, replacement) {
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
};
|
||||
return Value::error(e, span);
|
||||
}
|
||||
|
||||
input
|
||||
|
@ -68,8 +68,8 @@ impl Command for Upsert {
|
||||
Example {
|
||||
description: "Update each row of a table",
|
||||
example: "[[name lang]; [Nushell ''] [Reedline '']] | upsert lang 'Rust'",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_record(Record {
|
||||
cols: vec!["name".into(), "lang".into()],
|
||||
vals: vec![Value::test_string("Nushell"), Value::test_string("Rust")],
|
||||
@ -79,8 +79,8 @@ impl Command for Upsert {
|
||||
vals: vec![Value::test_string("Reedline"), Value::test_string("Rust")],
|
||||
}),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Insert a new entry into a single record",
|
||||
@ -92,34 +92,34 @@ impl Command for Upsert {
|
||||
}, Example {
|
||||
description: "Use in closure form for more involved updating logic",
|
||||
example: "[[count fruit]; [1 'apple']] | enumerate | upsert item.count {|e| ($e.item.fruit | str length) + $e.index } | get item",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_record(Record {
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_record(Record {
|
||||
cols: vec!["count".into(), "fruit".into()],
|
||||
vals: vec![Value::test_int(5), Value::test_string("apple")],
|
||||
})],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Upsert an int into a list, updating an existing value based on the index",
|
||||
example: "[1 2 3] | upsert 0 2",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(2), Value::test_int(2), Value::test_int(3)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(2), Value::test_int(2), Value::test_int(3)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Upsert an int into a list, inserting a new value based on the index",
|
||||
example: "[1 2 3] | upsert 3 4",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(1),
|
||||
Value::test_int(2),
|
||||
Value::test_int(3),
|
||||
Value::test_int(4),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -178,18 +178,12 @@ fn upsert(
|
||||
if let Err(e) =
|
||||
input.upsert_data_at_cell_path(&cell_path.members, pd.into_value(span))
|
||||
{
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
};
|
||||
return Value::error(e, span);
|
||||
}
|
||||
|
||||
input
|
||||
}
|
||||
Err(e) => Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
},
|
||||
Err(e) => Value::error(e, span),
|
||||
}
|
||||
},
|
||||
ctrlc,
|
||||
@ -225,10 +219,7 @@ fn upsert(
|
||||
let replacement = replacement.clone();
|
||||
|
||||
if let Err(e) = input.upsert_data_at_cell_path(&cell_path.members, replacement) {
|
||||
return Value::Error {
|
||||
error: Box::new(e),
|
||||
span,
|
||||
};
|
||||
return Value::error(e, span);
|
||||
}
|
||||
|
||||
input
|
||||
|
@ -62,19 +62,11 @@ pub fn boolean_fold(
|
||||
}
|
||||
Ok(pipeline_data) => {
|
||||
if pipeline_data.into_value(span).is_true() == accumulator {
|
||||
return Ok(Value::Bool {
|
||||
val: accumulator,
|
||||
span,
|
||||
}
|
||||
.into_pipeline_data());
|
||||
return Ok(Value::bool(accumulator, span).into_pipeline_data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Bool {
|
||||
val: !accumulator,
|
||||
span,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::bool(!accumulator, span).into_pipeline_data())
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user