Skip to content

Commit

Permalink
Make append/prepend consistent for ranges (#10231)
Browse files Browse the repository at this point in the history
# Description
This PR makes `append`/`prepend` more consistent, in particular, it allows you to
work with ranges. Previously, you couldn't append a list by range:
```nu
> 0..1 | append 2..4
╭──────╮
│    0 │
│    1 │
│ 2..4 │
╰──────╯
```

Now it works:
```nu
> 0..1 | append 2..4
╭───╮
│ 0 │
│ 1 │
│ 2 │
│ 3 │
│ 4 │
╰───╯
```

# User-Facing Changes
If someone needs the old behavior, then it can be obtained like this:
```nu
> 0..1 | append [2..4]
╭──────╮
│    0 │
│    1 │
│ 2..4 │
╰──────╯
```
  • Loading branch information
nanoqsh authored Sep 4, 2023
1 parent 08aaa94 commit eca9f46
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 139 deletions.
119 changes: 50 additions & 69 deletions crates/nu-command/src/filters/append.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Type, Value,
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, SyntaxShape, Type, Value,
};

#[derive(Clone)]
Expand Down Expand Up @@ -40,68 +40,67 @@ only unwrap the outer list, and leave the variable's contents untouched."#
fn examples(&self) -> Vec<Example> {
vec![
Example {
example: "[0,1,2,3] | append 4",
example: "[0 1 2 3] | append 4",
description: "Append one integer to a list",
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::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(4),
])),
},
Example {
example: "0 | append [1 2 3]",
description: "Append a list to an item",
result: Some(Value::list(
vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
])),
},
Example {
example: r#""a" | append ["b"] "#,
description: "Append a list of string to a string",
result: Some(Value::list(
vec![Value::test_string("a"), Value::test_string("b")],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_string("a"),
Value::test_string("b"),
])),
},
Example {
example: "[0,1] | append [2,3,4]",
example: "[0 1] | append [2 3 4]",
description: "Append three integer items",
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::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(4),
])),
},
Example {
example: "[0,1] | append [2,nu,4,shell]",
example: "[0 1] | append [2 nu 4 shell]",
description: "Append integers and strings",
result: Some(Value::list(
vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_string("nu"),
Value::test_int(4),
Value::test_string("shell"),
],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_string("nu"),
Value::test_int(4),
Value::test_string("shell"),
])),
},
Example {
example: "[0 1] | append 2..4",
description: "Append a range of integers to a list",
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(4),
])),
},
]
}
Expand All @@ -113,35 +112,17 @@ only unwrap the outer list, and leave the variable's contents untouched."#
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let val: Value = call.req(engine_state, stack, 0)?;
let vec: Vec<Value> = process_value(val);
let other: Value = call.req(engine_state, stack, 0)?;
let metadata = input.metadata();

Ok(input
.into_iter()
.chain(vec)
.chain(other.into_pipeline_data())
.into_pipeline_data(engine_state.ctrlc.clone())
.set_metadata(metadata))
}
}

fn process_value(val: Value) -> Vec<Value> {
match val {
Value::List {
vals: input_vals, ..
} => {
let mut output = vec![];
for input_val in input_vals {
output.push(input_val);
}
output
}
_ => {
vec![val]
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
122 changes: 52 additions & 70 deletions crates/nu-command/src/filters/prepend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Type, Value,
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, SyntaxShape, Type, Value,
};

#[derive(Clone)]
Expand Down Expand Up @@ -45,67 +45,66 @@ 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(
vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(0),
],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(0),
])),
},
Example {
example: r#""a" | prepend ["b"] "#,
description: "Prepend a list of strings to a string",
result: Some(Value::list(
vec![Value::test_string("b"), Value::test_string("a")],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_string("b"),
Value::test_string("a"),
])),
},
Example {
example: "[1,2,3,4] | prepend 0",
example: "[1 2 3 4] | prepend 0",
description: "Prepend one integer item",
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::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(4),
])),
},
Example {
example: "[2,3,4] | prepend [0,1]",
example: "[2 3 4] | prepend [0 1]",
description: "Prepend two integer items",
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::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(4),
])),
},
Example {
example: "[2,nu,4,shell] | prepend [0,1,rocks]",
example: "[2 nu 4 shell] | prepend [0 1 rocks]",
description: "Prepend integers and strings",
result: Some(Value::list(
vec![
Value::test_int(0),
Value::test_int(1),
Value::test_string("rocks"),
Value::test_int(2),
Value::test_string("nu"),
Value::test_int(4),
Value::test_string("shell"),
],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_string("rocks"),
Value::test_int(2),
Value::test_string("nu"),
Value::test_int(4),
Value::test_string("shell"),
])),
},
Example {
example: "[3 4] | prepend 0..2",
description: "Prepend a range",
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
Value::test_int(4),
])),
},
]
}
Expand All @@ -117,35 +116,18 @@ only unwrap the outer list, and leave the variable's contents untouched."#
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let val: Value = call.req(engine_state, stack, 0)?;
let vec: Vec<Value> = process_value(val);
let other: Value = call.req(engine_state, stack, 0)?;
let metadata = input.metadata();

Ok(vec
Ok(other
.into_pipeline_data()
.into_iter()
.chain(input)
.into_pipeline_data(engine_state.ctrlc.clone())
.set_metadata(metadata))
}
}

fn process_value(val: Value) -> Vec<Value> {
match val {
Value::List {
vals: input_vals, ..
} => {
let mut output = vec![];
for input_val in input_vals {
output.push(input_val);
}
output
}
_ => {
vec![val]
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down

0 comments on commit eca9f46

Please sign in to comment.