mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 16:35:29 +02:00
Refactor using ClosureEval
types (#12541)
# Description Adds two new types in `nu-engine` for evaluating closures: `ClosureEval` and `ClosureEvalOnce`. This removed some duplicate code and centralizes our logic for setting up, running, and cleaning up closures. For example, in the future if we are able to reduce the cloning necessary to run a closure, then we only have to change the code related to these types. `ClosureEval` and `ClosureEvalOnce` are designed with a builder API. `ClosureEval` is used to run a closure multiple times whereas `ClosureEvalOnce` is used for a one-shot closure. # User-Facing Changes Should be none, unless I messed up one of the command migrations. Actually, this will fix any unreported environment bugs for commands that didn't reset the env after running a closure.
This commit is contained in:
@ -1,11 +1,10 @@
|
||||
use crate::{color_record_to_nustyle, lookup_ansi_color_style, text_style::Alignment, TextStyle};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_engine::{env::get_config, eval_block};
|
||||
use nu_engine::{env::get_config, ClosureEvalOnce};
|
||||
use nu_protocol::{
|
||||
cli_error::CliError,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
IntoPipelineData, Value,
|
||||
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||
Span, Value,
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@ -18,7 +17,7 @@ use std::{
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ComputableStyle {
|
||||
Static(Style),
|
||||
Closure(Value),
|
||||
Closure(Closure, Span),
|
||||
}
|
||||
|
||||
// An alias for the mapping used internally by StyleComputer.
|
||||
@ -56,51 +55,31 @@ impl<'a> StyleComputer<'a> {
|
||||
// Static values require no computation.
|
||||
Some(ComputableStyle::Static(s)) => *s,
|
||||
// Closures are run here.
|
||||
Some(ComputableStyle::Closure(v)) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::Closure { val, .. } => {
|
||||
let block = self.engine_state.get_block(val.block_id).clone();
|
||||
// Because captures_to_stack() clones, we don't need to use with_env() here
|
||||
// (contrast with_env() usage in `each` or `do`).
|
||||
let mut stack = self.stack.captures_to_stack(val.captures.clone());
|
||||
Some(ComputableStyle::Closure(closure, span)) => {
|
||||
let result = ClosureEvalOnce::new(self.engine_state, self.stack, closure.clone())
|
||||
.debug(false)
|
||||
.run_with_value(value.clone());
|
||||
|
||||
// Support 1-argument blocks as well as 0-argument blocks.
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
if let Some(var_id) = &var.var_id {
|
||||
stack.add_var(*var_id, value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Run the block.
|
||||
match eval_block::<WithoutDebug>(
|
||||
self.engine_state,
|
||||
&mut stack,
|
||||
&block,
|
||||
value.clone().into_pipeline_data(),
|
||||
) {
|
||||
Ok(v) => {
|
||||
let value = v.into_value(span);
|
||||
// These should be the same color data forms supported by color_config.
|
||||
match value {
|
||||
Value::Record { .. } => color_record_to_nustyle(&value),
|
||||
Value::String { val, .. } => lookup_ansi_color_style(&val),
|
||||
_ => Style::default(),
|
||||
}
|
||||
}
|
||||
// This is basically a copy of nu_cli::report_error(), but that isn't usable due to
|
||||
// dependencies. While crudely spitting out a bunch of errors like this is not ideal,
|
||||
// currently hook closure errors behave roughly the same.
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Error: {:?}",
|
||||
CliError(&e, &StateWorkingSet::new(self.engine_state))
|
||||
);
|
||||
Style::default()
|
||||
}
|
||||
match result {
|
||||
Ok(v) => {
|
||||
let value = v.into_value(*span);
|
||||
// These should be the same color data forms supported by color_config.
|
||||
match value {
|
||||
Value::Record { .. } => color_record_to_nustyle(&value),
|
||||
Value::String { val, .. } => lookup_ansi_color_style(&val),
|
||||
_ => Style::default(),
|
||||
}
|
||||
}
|
||||
_ => Style::default(),
|
||||
// This is basically a copy of nu_cli::report_error(), but that isn't usable due to
|
||||
// dependencies. While crudely spitting out a bunch of errors like this is not ideal,
|
||||
// currently hook closure errors behave roughly the same.
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Error: {:?}",
|
||||
CliError(&e, &StateWorkingSet::new(self.engine_state))
|
||||
);
|
||||
Style::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
// There should be no other kinds of values (due to create_map() in config.rs filtering them out)
|
||||
@ -165,9 +144,10 @@ impl<'a> StyleComputer<'a> {
|
||||
].into_iter().collect();
|
||||
|
||||
for (key, value) in &config.color_config {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Closure { .. } => {
|
||||
map.insert(key.to_string(), ComputableStyle::Closure(value.clone()));
|
||||
Value::Closure { val, .. } => {
|
||||
map.insert(key.to_string(), ComputableStyle::Closure(val.clone(), span));
|
||||
}
|
||||
Value::Record { .. } => {
|
||||
map.insert(
|
||||
|
Reference in New Issue
Block a user