allow update to use metadata (#10264)

# Description

This PR is an attempt to fix the `update` command so that it passes
along metadata. I'm not really sure I did this right, so please feel
free to point out where it's wrong.

The point is to be able to do something like this and have it respect
your LS_COLORS.
```
ls | update modified { format date }
```
### Before

![image](https://github.com/nushell/nushell/assets/343840/fc3eb207-4f6f-42b1-b5a4-87a1fe194399)

### After

![image](https://github.com/nushell/nushell/assets/343840/19d58443-7c88-4dd6-9532-1f45f615ac7b)


# 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.
-->
This commit is contained in:
Darren Schroeder 2023-09-09 13:47:42 -05:00 committed by GitHub
parent 7907dda8f7
commit 40eca52ed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -116,6 +116,10 @@ fn update(
let engine_state = engine_state.clone();
let ctrlc = engine_state.ctrlc.clone();
// Let's capture the metadata for ls_colors
let metadata = input.metadata();
let mdclone = metadata.clone();
// Replace is a block, so set it up and run it instead of using it as the replacement
if replacement.as_block().is_ok() {
let capture_block: Closure = FromValue::from_value(&replacement)?;
@ -125,48 +129,50 @@ fn update(
let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone();
input.map(
move |mut input| {
// with_env() is used here to ensure that each iteration uses
// a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop.
stack.with_env(&orig_env_vars, &orig_env_hidden);
Ok(input
.map(
move |mut input| {
// with_env() is used here to ensure that each iteration uses
// a different set of environment variables.
// Hence, a 'cd' in the first loop won't affect the next loop.
stack.with_env(&orig_env_vars, &orig_env_hidden);
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, input.clone())
}
}
let input_at_path = match input.clone().follow_cell_path(&cell_path.members, false)
{
Err(e) => return Value::error(e, span),
Ok(v) => v,
};
let output = eval_block(
&engine_state,
&mut stack,
&block,
input_at_path.into_pipeline_data(),
redirect_stdout,
redirect_stderr,
);
match output {
Ok(pd) => {
if let Err(e) =
input.update_data_at_cell_path(&cell_path.members, pd.into_value(span))
{
return Value::error(e, span);
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, input.clone())
}
input
}
Err(e) => Value::error(e, span),
}
},
ctrlc,
)
let input_at_path =
match input.clone().follow_cell_path(&cell_path.members, false) {
Err(e) => return Value::error(e, span),
Ok(v) => v,
};
let output = eval_block(
&engine_state,
&mut stack,
&block,
input_at_path.into_pipeline_data_with_metadata(metadata.clone()),
redirect_stdout,
redirect_stderr,
);
match output {
Ok(pd) => {
if let Err(e) = input
.update_data_at_cell_path(&cell_path.members, pd.into_value(span))
{
return Value::error(e, span);
}
input
}
Err(e) => Value::error(e, span),
}
},
ctrlc,
)?
.set_metadata(mdclone))
} else {
if let Some(PathMember::Int { val, span, .. }) = cell_path.members.get(0) {
let mut input = input.into_iter();
@ -192,20 +198,23 @@ fn update(
.into_iter()
.chain(vec![replacement])
.chain(input)
.into_pipeline_data(ctrlc));
.into_pipeline_data_with_metadata(metadata, ctrlc));
}
input.map(
move |mut input| {
let replacement = replacement.clone();
Ok(input
.map(
move |mut input| {
let replacement = replacement.clone();
if let Err(e) = input.update_data_at_cell_path(&cell_path.members, replacement) {
return Value::error(e, span);
}
if let Err(e) = input.update_data_at_cell_path(&cell_path.members, replacement)
{
return Value::error(e, span);
}
input
},
ctrlc,
)
input
},
ctrlc,
)?
.set_metadata(metadata))
}
}