forked from extern/nushell
Debugger experiments (#11441)
<!-- if this PR closes one or more issues, you can automatically link the PR with them by using one of the [*linking keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword), e.g. - this PR should close #xxxx - fixes #xxxx you can also mention related issues, PRs or discussions! --> # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> This PR adds a new evaluator path with callbacks to a mutable trait object implementing a Debugger trait. The trait object can do anything, e.g., profiling, code coverage, step debugging. Currently, entering/leaving a block and a pipeline element is marked with callbacks, but more callbacks can be added as necessary. Not all callbacks need to be used by all debuggers; unused ones are simply empty calls. A simple profiler is implemented as a proof of concept. The debugging support is implementing by making `eval_xxx()` functions generic depending on whether we're debugging or not. This has zero computational overhead, but makes the binary slightly larger (see benchmarks below). `eval_xxx()` variants called from commands (like `eval_block_with_early_return()` in `each`) are chosen with a dynamic dispatch for two reasons: to not grow the binary size due to duplicating the code of many commands, and for the fact that it isn't possible because it would make Command trait objects object-unsafe. In the future, I hope it will be possible to allow plugin callbacks such that users would be able to implement their profiler plugins instead of having to recompile Nushell. [DAP](https://microsoft.github.io/debug-adapter-protocol/) would also be interesting to explore. Try `help debug profile`. ## Screenshots Basic output:  To profile with more granularity, increase the profiler depth (you'll see that repeated `is-windows` calls take a large chunk of total time, making it a good candidate for optimizing):  ## Benchmarks ### Binary size Binary size increase vs. main: **+40360 bytes**. _(Both built with `--release --features=extra,dataframe`.)_ ### Time ```nushell # bench_debug.nu use std bench let test = { 1..100 | each { ls | each {|row| $row.name | str length } } | flatten | math avg } print 'debug:' let res2 = bench { debug profile $test } --pretty print $res2 ``` ```nushell # bench_nodebug.nu use std bench let test = { 1..100 | each { ls | each {|row| $row.name | str length } } | flatten | math avg } print 'no debug:' let res1 = bench { do $test } --pretty print $res1 ``` `cargo run --release -- bench_debug.nu` is consistently 1--2 ms slower than `cargo run --release -- bench_nodebug.nu` due to the collection overhead + gathering the report. This is expected. When gathering more stuff, the overhead is obviously higher. `cargo run --release -- bench_nodebug.nu` vs. `nu bench_nodebug.nu` I didn't measure any difference. Both benchmarks report times between 97 and 103 ms randomly, without one being consistently higher than the other. This suggests that at least in this particular case, when not running any debugger, there is no runtime overhead. ## API changes This PR adds a generic parameter to all `eval_xxx` functions that forces you to specify whether you use the debugger. You can resolve it in two ways: * Use a provided helper that will figure it out for you. If you wanted to use `eval_block(&engine_state, ...)`, call `let eval_block = get_eval_block(&engine_state); eval_block(&engine_state, ...)` * If you know you're in an evaluation path that doesn't need debugger support, call `eval_block::<WithoutDebug>(&engine_state, ...)` (this is the case of hooks, for example). I tried to add more explanation in the docstring of `debugger_trait.rs`. ## TODO - [x] Better profiler output to reduce spam of iterative commands like `each` - [x] Resolve `TODO: DEBUG` comments - [x] Resolve unwraps - [x] Add doc comments - [x] Add usage and extra usage for `debug profile`, explaining all columns # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> Hopefully none. # 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:
@ -1,5 +1,6 @@
|
||||
use nu_engine::eval_expression;
|
||||
use nu_engine::get_eval_expression;
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||
@ -48,7 +49,10 @@ impl Command for BytesBuild {
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let mut output = vec![];
|
||||
for val in call.rest_iter_flattened(0, |expr| eval_expression(engine_state, stack, expr))? {
|
||||
for val in call.rest_iter_flattened(0, |expr| {
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
eval_expression(engine_state, stack, expr)
|
||||
})? {
|
||||
match val {
|
||||
Value::Binary { mut val, .. } => output.append(&mut val),
|
||||
// Explicitly propagate errors instead of dropping them.
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_expression, CallExt};
|
||||
use nu_engine::{get_eval_expression, CallExt};
|
||||
use nu_protocol::ast::{Argument, Block, Call, Expr, Expression};
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature,
|
||||
@ -43,7 +44,7 @@ impl Command for Explain {
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
let mut stack = stack.captures_to_stack(capture_block.captures);
|
||||
|
||||
let elements = get_pipeline_elements(engine_state, &mut stack, block)?;
|
||||
let elements = get_pipeline_elements(engine_state, &mut stack, block, call.head)?;
|
||||
|
||||
Ok(elements.into_pipeline_data(ctrlc))
|
||||
}
|
||||
@ -62,9 +63,11 @@ pub fn get_pipeline_elements(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
block: &Block,
|
||||
span: Span,
|
||||
) -> Result<Vec<Value>, ShellError> {
|
||||
let mut element_values = vec![];
|
||||
let span = Span::test_data();
|
||||
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
|
||||
for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() {
|
||||
let mut i = 0;
|
||||
@ -80,7 +83,7 @@ pub fn get_pipeline_elements(
|
||||
let command = engine_state.get_decl(call.decl_id);
|
||||
(
|
||||
command.name().to_string(),
|
||||
get_arguments(engine_state, stack, *call),
|
||||
get_arguments(engine_state, stack, *call, eval_expression),
|
||||
)
|
||||
} else {
|
||||
("no-op".to_string(), vec![])
|
||||
@ -106,7 +109,12 @@ pub fn get_pipeline_elements(
|
||||
Ok(element_values)
|
||||
}
|
||||
|
||||
fn get_arguments(engine_state: &EngineState, stack: &mut Stack, call: Call) -> Vec<Value> {
|
||||
fn get_arguments(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: Call,
|
||||
eval_expression_fn: fn(&EngineState, &mut Stack, &Expression) -> Result<Value, ShellError>,
|
||||
) -> Vec<Value> {
|
||||
let mut arg_value = vec![];
|
||||
let span = Span::test_data();
|
||||
for arg in &call.arguments {
|
||||
@ -145,8 +153,12 @@ fn get_arguments(engine_state: &EngineState, stack: &mut Stack, call: Call) -> V
|
||||
};
|
||||
|
||||
if let Some(expression) = opt_expr {
|
||||
let evaluated_expression =
|
||||
get_expression_as_value(engine_state, stack, expression);
|
||||
let evaluated_expression = get_expression_as_value(
|
||||
engine_state,
|
||||
stack,
|
||||
expression,
|
||||
eval_expression_fn,
|
||||
);
|
||||
let arg_type = "expr";
|
||||
let arg_value_name = debug_string_without_formatting(&evaluated_expression);
|
||||
let arg_value_type = &evaluated_expression.get_type().to_string();
|
||||
@ -166,7 +178,8 @@ fn get_arguments(engine_state: &EngineState, stack: &mut Stack, call: Call) -> V
|
||||
}
|
||||
Argument::Positional(inner_expr) => {
|
||||
let arg_type = "positional";
|
||||
let evaluated_expression = get_expression_as_value(engine_state, stack, inner_expr);
|
||||
let evaluated_expression =
|
||||
get_expression_as_value(engine_state, stack, inner_expr, eval_expression_fn);
|
||||
let arg_value_name = debug_string_without_formatting(&evaluated_expression);
|
||||
let arg_value_type = &evaluated_expression.get_type().to_string();
|
||||
let evaled_span = evaluated_expression.span();
|
||||
@ -184,7 +197,8 @@ fn get_arguments(engine_state: &EngineState, stack: &mut Stack, call: Call) -> V
|
||||
}
|
||||
Argument::Unknown(inner_expr) => {
|
||||
let arg_type = "unknown";
|
||||
let evaluated_expression = get_expression_as_value(engine_state, stack, inner_expr);
|
||||
let evaluated_expression =
|
||||
get_expression_as_value(engine_state, stack, inner_expr, eval_expression_fn);
|
||||
let arg_value_name = debug_string_without_formatting(&evaluated_expression);
|
||||
let arg_value_type = &evaluated_expression.get_type().to_string();
|
||||
let evaled_span = evaluated_expression.span();
|
||||
@ -202,7 +216,8 @@ fn get_arguments(engine_state: &EngineState, stack: &mut Stack, call: Call) -> V
|
||||
}
|
||||
Argument::Spread(inner_expr) => {
|
||||
let arg_type = "spread";
|
||||
let evaluated_expression = get_expression_as_value(engine_state, stack, inner_expr);
|
||||
let evaluated_expression =
|
||||
get_expression_as_value(engine_state, stack, inner_expr, eval_expression_fn);
|
||||
let arg_value_name = debug_string_without_formatting(&evaluated_expression);
|
||||
let arg_value_type = &evaluated_expression.get_type().to_string();
|
||||
let evaled_span = evaluated_expression.span();
|
||||
@ -228,8 +243,9 @@ fn get_expression_as_value(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
inner_expr: &Expression,
|
||||
eval_expression_fn: fn(&EngineState, &mut Stack, &Expression) -> Result<Value, ShellError>,
|
||||
) -> Value {
|
||||
match eval_expression(engine_state, stack, inner_expr) {
|
||||
match eval_expression_fn(engine_state, stack, inner_expr) {
|
||||
Ok(v) => v,
|
||||
Err(error) => Value::error(error, inner_expr.span),
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ mod info;
|
||||
mod inspect;
|
||||
mod inspect_table;
|
||||
mod metadata;
|
||||
mod profile;
|
||||
mod timeit;
|
||||
mod view;
|
||||
mod view_files;
|
||||
@ -18,6 +19,7 @@ pub use info::DebugInfo;
|
||||
pub use inspect::Inspect;
|
||||
pub use inspect_table::build_table;
|
||||
pub use metadata::Metadata;
|
||||
pub use profile::DebugProfile;
|
||||
pub use timeit::TimeIt;
|
||||
pub use view::View;
|
||||
pub use view_files::ViewFiles;
|
||||
|
169
crates/nu-command/src/debug/profile.rs
Normal file
169
crates/nu-command/src/debug/profile.rs
Normal file
@ -0,0 +1,169 @@
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::debugger::{Profiler, WithDebug};
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DebugProfile;
|
||||
|
||||
impl Command for DebugProfile {
|
||||
fn name(&self) -> &str {
|
||||
"debug profile"
|
||||
}
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("debug profile")
|
||||
.required(
|
||||
"closure",
|
||||
SyntaxShape::Closure(None),
|
||||
"The closure to profile.",
|
||||
)
|
||||
.switch("spans", "Collect spans of profiled elements", Some('s'))
|
||||
.switch(
|
||||
"expand-source",
|
||||
"Collect full source fragments of profiled elements",
|
||||
Some('e'),
|
||||
)
|
||||
.switch(
|
||||
"values",
|
||||
"Collect pipeline element output values",
|
||||
Some('v'),
|
||||
)
|
||||
.switch("expr", "Collect expression types", Some('x'))
|
||||
.named(
|
||||
"max-depth",
|
||||
SyntaxShape::Int,
|
||||
"How many blocks/closures deep to step into (default 2)",
|
||||
Some('m'),
|
||||
)
|
||||
.input_output_types(vec![(Type::Any, Type::Table(vec![]))])
|
||||
.category(Category::Debug)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Profile pipeline elements in a closure."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"The profiler profiles every evaluated pipeline element inside a closure, stepping into all
|
||||
commands calls and other blocks/closures.
|
||||
|
||||
The output can be heavily customized. By default, the following columns are included:
|
||||
- depth : Depth of the pipeline element. Each entered block adds one level of depth. How many
|
||||
blocks deep to step into is controlled with the --max-depth option.
|
||||
- id : ID of the pipeline element
|
||||
- parent_id : ID of the parent element
|
||||
- source : Source code of the pipeline element. If the element has multiple lines, only the
|
||||
first line is used and `...` is appended to the end. Full source code can be shown
|
||||
with the --expand-source flag.
|
||||
- duration_ms : How long it took to run the pipeline element in milliseconds.
|
||||
- (optional) span : Span of the element. Can be viewed via the `view span` command. Enabled with
|
||||
the --spans flag.
|
||||
- (optional) expr : The type of expression of the pipeline element. Enabled with the --expr flag.
|
||||
- (optional) output : The output value of the pipeline element. Enabled with the --values flag.
|
||||
|
||||
To illustrate the depth and IDs, consider `debug profile { if true { echo 'spam' } }`. There are
|
||||
three pipeline elements:
|
||||
|
||||
depth id parent_id
|
||||
0 0 0 debug profile { do { if true { 'spam' } } }
|
||||
1 1 0 if true { 'spam' }
|
||||
2 2 1 'spam'
|
||||
|
||||
Each block entered increments depth by 1 and each block left decrements it by one. This way you can
|
||||
control the profiling granularity. Passing --max-depth=1 to the above would stop at
|
||||
`if true { 'spam' }`. The id is used to identify each element. The parent_id tells you that 'spam'
|
||||
was spawned from `if true { 'spam' }` which was spawned from the root `debug profile { ... }`.
|
||||
|
||||
Note: In some cases, the ordering of piepeline elements might not be intuitive. For example,
|
||||
`[ a bb cc ] | each { $in | str length }` involves some implicit collects and lazy evaluation
|
||||
confusing the id/parent_id hierarchy. The --expr flag is helpful for investigating these issues."#
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
caller_stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let closure: Closure = call.req(engine_state, caller_stack, 0)?;
|
||||
let mut callee_stack = caller_stack.captures_to_stack(closure.captures);
|
||||
let block = engine_state.get_block(closure.block_id);
|
||||
|
||||
let default_max_depth = 2;
|
||||
let collect_spans = call.has_flag(engine_state, caller_stack, "spans")?;
|
||||
let collect_expanded_source =
|
||||
call.has_flag(engine_state, caller_stack, "expanded-source")?;
|
||||
let collect_values = call.has_flag(engine_state, caller_stack, "values")?;
|
||||
let collect_exprs = call.has_flag(engine_state, caller_stack, "expr")?;
|
||||
let max_depth = call
|
||||
.get_flag(engine_state, caller_stack, "max-depth")?
|
||||
.unwrap_or(default_max_depth);
|
||||
|
||||
let profiler = Profiler::new(
|
||||
max_depth,
|
||||
collect_spans,
|
||||
true,
|
||||
collect_expanded_source,
|
||||
collect_values,
|
||||
collect_exprs,
|
||||
call.span(),
|
||||
);
|
||||
|
||||
let lock_err = {
|
||||
|_| ShellError::GenericError {
|
||||
error: "Profiler Error".to_string(),
|
||||
msg: "could not lock debugger, poisoned mutex".to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}
|
||||
};
|
||||
|
||||
engine_state
|
||||
.activate_debugger(Box::new(profiler))
|
||||
.map_err(lock_err)?;
|
||||
|
||||
let result = eval_block_with_early_return::<WithDebug>(
|
||||
engine_state,
|
||||
&mut callee_stack,
|
||||
block,
|
||||
input,
|
||||
call.redirect_stdout,
|
||||
call.redirect_stdout,
|
||||
);
|
||||
|
||||
// TODO: See eval_source()
|
||||
match result {
|
||||
Ok(pipeline_data) => {
|
||||
let _ = pipeline_data.into_value(call.span());
|
||||
// pipeline_data.print(engine_state, caller_stack, true, false)
|
||||
}
|
||||
Err(_e) => (), // TODO: Report error
|
||||
}
|
||||
|
||||
let debugger = engine_state.deactivate_debugger().map_err(lock_err)?;
|
||||
let res = debugger.report(engine_state, call.span());
|
||||
|
||||
res.map(|val| val.into_pipeline_data())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Profile config evaluation",
|
||||
example: "debug profile { source $nu.config-path }",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Profile config evaluation with more granularity",
|
||||
example: "debug profile { source $nu.config-path } --max-depth 4",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
use nu_engine::{eval_block, eval_expression_with_input};
|
||||
use nu_engine::{get_eval_block, get_eval_expression_with_input};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
@ -52,6 +53,7 @@ impl Command for TimeIt {
|
||||
|
||||
if let Some(command_to_run) = command_to_run {
|
||||
if let Some(block_id) = command_to_run.as_block() {
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
let block = engine_state.get_block(block_id);
|
||||
eval_block(
|
||||
engine_state,
|
||||
@ -62,6 +64,7 @@ impl Command for TimeIt {
|
||||
call.redirect_stderr,
|
||||
)?
|
||||
} else {
|
||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
||||
eval_expression_with_input(
|
||||
engine_state,
|
||||
stack,
|
||||
|
@ -140,6 +140,7 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
||||
Ast,
|
||||
Debug,
|
||||
DebugInfo,
|
||||
DebugProfile,
|
||||
Explain,
|
||||
Inspect,
|
||||
Metadata,
|
||||
|
5
crates/nu-command/src/env/export_env.rs
vendored
5
crates/nu-command/src/env/export_env.rs
vendored
@ -1,4 +1,5 @@
|
||||
use nu_engine::{eval_block, redirect_env, CallExt};
|
||||
use nu_engine::{get_eval_block, redirect_env, CallExt};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -39,6 +40,8 @@ impl Command for ExportEnv {
|
||||
let block = engine_state.get_block(capture_block.block_id);
|
||||
let mut callee_stack = caller_stack.captures_to_stack(capture_block.captures);
|
||||
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
let _ = eval_block(
|
||||
engine_state,
|
||||
&mut callee_stack,
|
||||
|
6
crates/nu-command/src/env/source_env.rs
vendored
6
crates/nu-command/src/env/source_env.rs
vendored
@ -1,9 +1,11 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use nu_engine::{
|
||||
eval_block_with_early_return, find_in_dirs_env, get_dirs_var_from_call, redirect_env, CallExt,
|
||||
find_in_dirs_env, get_dirs_var_from_call, get_eval_block_with_early_return, redirect_env,
|
||||
CallExt,
|
||||
};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
||||
@ -76,6 +78,8 @@ impl Command for SourceEnv {
|
||||
let block = engine_state.get_block(block_id as usize).clone();
|
||||
let mut callee_stack = caller_stack.gather_captures(engine_state, &block.captures);
|
||||
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
let result = eval_block_with_early_return(
|
||||
engine_state,
|
||||
&mut callee_stack,
|
||||
|
3
crates/nu-command/src/env/with_env.rs
vendored
3
crates/nu-command/src/env/with_env.rs
vendored
@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_protocol::debugger::WithoutDebug;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -144,7 +145,7 @@ fn with_env(
|
||||
stack.add_env_var(k, v);
|
||||
}
|
||||
|
||||
eval_block(
|
||||
eval_block::<WithoutDebug>(
|
||||
engine_state,
|
||||
&mut stack,
|
||||
block,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::util::get_rest_for_glob_pattern;
|
||||
use nu_engine::{current_dir, eval_block, CallExt};
|
||||
use nu_engine::{current_dir, get_eval_block, CallExt};
|
||||
use nu_path::expand_to_real_path;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
@ -64,6 +64,7 @@ impl Command for Open {
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
let mut paths = get_rest_for_glob_pattern(engine_state, stack, call, 0)?;
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
if paths.is_empty() && call.rest_iter(0).next().is_none() {
|
||||
// try to use path from pipeline input if there were no positional or spread args
|
||||
|
@ -1,5 +1,5 @@
|
||||
use dialoguer::Input;
|
||||
use nu_engine::eval_expression;
|
||||
use nu_engine::get_eval_expression;
|
||||
use nu_protocol::ast::Expr;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
@ -221,6 +221,7 @@ pub fn get_rest_for_glob_pattern(
|
||||
starting_pos: usize,
|
||||
) -> Result<Vec<Spanned<NuGlob>>, ShellError> {
|
||||
let mut output = vec![];
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
|
||||
for result in call.rest_iter_flattened(starting_pos, |expr| {
|
||||
let result = eval_expression(engine_state, stack, expr);
|
||||
@ -261,6 +262,7 @@ pub fn opt_for_glob_pattern(
|
||||
pos: usize,
|
||||
) -> Result<Option<Spanned<NuGlob>>, ShellError> {
|
||||
if let Some(expr) = call.positional_nth(pos) {
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
let result = eval_expression(engine_state, stack, expr)?;
|
||||
let result_span = result.span();
|
||||
let result = match result {
|
||||
|
@ -9,8 +9,9 @@ use notify_debouncer_full::{
|
||||
EventKind, RecursiveMode, Watcher,
|
||||
},
|
||||
};
|
||||
use nu_engine::{current_dir, eval_block, CallExt};
|
||||
use nu_engine::{current_dir, get_eval_block, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack, StateWorkingSet};
|
||||
use nu_protocol::{
|
||||
format_error, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature,
|
||||
@ -168,6 +169,8 @@ impl Command for Watch {
|
||||
|
||||
eprintln!("Now watching files at {path:?}. Press ctrl+c to abort.");
|
||||
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
let event_handler =
|
||||
|operation: &str, path: PathBuf, new_path: Option<PathBuf>| -> Result<(), ShellError> {
|
||||
let glob_pattern = glob_pattern.clone();
|
||||
|
@ -1,12 +1,14 @@
|
||||
use super::utils::chain_error_with_input;
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
|
||||
Signature, Span, SyntaxShape, Type, Value,
|
||||
};
|
||||
|
||||
use super::utils::chain_error_with_input;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Each;
|
||||
|
||||
@ -112,6 +114,8 @@ with 'transpose' first."#
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
let capture_block: Closure = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let keep_empty = call.has_flag(engine_state, stack, "keep-empty")?;
|
||||
@ -155,6 +159,8 @@ with 'transpose' first."#
|
||||
x.into_pipeline_data(),
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
// WithoutDebug,
|
||||
// &None,
|
||||
) {
|
||||
Ok(v) => Some(v.into_value(span)),
|
||||
Err(ShellError::Continue { span }) => Some(Value::nothing(span)),
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::utils::chain_error_with_input;
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
|
||||
@ -63,6 +64,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
|
||||
let span = call.head;
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
let eval_block = get_eval_block(&engine_state);
|
||||
|
||||
match input {
|
||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
||||
@ -162,6 +164,7 @@ a variable. On the other hand, the "row condition" syntax is not supported."#
|
||||
stack.add_var(*var_id, x.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(match eval_block(
|
||||
&engine_state,
|
||||
&mut stack,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
use nu_protocol::ast::{Call, CellPath};
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
@ -238,12 +238,14 @@ fn group_closure(
|
||||
) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
||||
let error_key = "error";
|
||||
let mut groups: IndexMap<String, Vec<Value>> = IndexMap::new();
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
if let Some(capture_block) = &block {
|
||||
let block = engine_state.get_block(capture_block.block_id);
|
||||
|
||||
for value in values {
|
||||
let mut stack = stack.captures_to_stack(capture_block.captures.clone());
|
||||
|
||||
let pipeline = eval_block(
|
||||
engine_state,
|
||||
&mut stack,
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt, EvalBlockFn};
|
||||
use nu_protocol::ast::{Block, Call, CellPath, PathMember};
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData,
|
||||
@ -134,6 +135,8 @@ fn insert(
|
||||
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
match input {
|
||||
PipelineData::Value(mut value, metadata) => {
|
||||
if replacement.coerce_block().is_ok() {
|
||||
@ -155,6 +158,7 @@ fn insert(
|
||||
block,
|
||||
&cell_path.members,
|
||||
false,
|
||||
eval_block,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@ -168,6 +172,7 @@ fn insert(
|
||||
redirect_stderr,
|
||||
&cell_path.members,
|
||||
matches!(first, Some(PathMember::Int { .. })),
|
||||
eval_block,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@ -242,6 +247,7 @@ fn insert(
|
||||
redirect_stderr,
|
||||
path,
|
||||
true,
|
||||
eval_block,
|
||||
)?;
|
||||
} else {
|
||||
value.insert_data_at_cell_path(path, replacement, span)?;
|
||||
@ -281,6 +287,7 @@ fn insert(
|
||||
&block,
|
||||
&cell_path.members,
|
||||
false,
|
||||
eval_block,
|
||||
);
|
||||
|
||||
if let Err(e) = err {
|
||||
@ -328,6 +335,7 @@ fn insert_value_by_closure(
|
||||
block: &Block,
|
||||
cell_path: &[PathMember],
|
||||
first_path_member_int: bool,
|
||||
eval_block_fn: EvalBlockFn,
|
||||
) -> Result<(), ShellError> {
|
||||
let input_at_path = value.clone().follow_cell_path(cell_path, false);
|
||||
|
||||
@ -348,7 +356,7 @@ fn insert_value_by_closure(
|
||||
.map(IntoPipelineData::into_pipeline_data)
|
||||
.unwrap_or(PipelineData::Empty);
|
||||
|
||||
let output = eval_block(
|
||||
let output = eval_block_fn(
|
||||
engine_state,
|
||||
stack,
|
||||
block,
|
||||
@ -370,6 +378,7 @@ fn insert_single_value_by_closure(
|
||||
redirect_stderr: bool,
|
||||
cell_path: &[PathMember],
|
||||
first_path_member_int: bool,
|
||||
eval_block_fn: EvalBlockFn,
|
||||
) -> Result<(), ShellError> {
|
||||
let span = replacement.span();
|
||||
let capture_block = Closure::from_value(replacement)?;
|
||||
@ -386,6 +395,7 @@ fn insert_single_value_by_closure(
|
||||
block,
|
||||
cell_path,
|
||||
first_path_member_int,
|
||||
eval_block_fn,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{sync::mpsc, thread};
|
||||
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -118,6 +118,7 @@ interleave
|
||||
let (tx, rx) = mpsc::sync_channel(buffer_size);
|
||||
|
||||
let closures: Vec<Closure> = call.rest(engine_state, stack, 0)?;
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
// Spawn the threads for the input and closure outputs
|
||||
(!input.is_nothing())
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
|
||||
@ -54,6 +55,7 @@ impl Command for Items {
|
||||
let orig_env_hidden = stack.env_hidden.clone();
|
||||
let span = call.head;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(&engine_state);
|
||||
|
||||
let input_span = input.span().unwrap_or(call.head);
|
||||
let run_for_each_item = move |keyval: (String, Value)| -> Option<Value> {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
|
||||
@ -142,6 +143,8 @@ impl Command for ParEach {
|
||||
vec.into_iter().map(|(_, val)| val)
|
||||
};
|
||||
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
match input {
|
||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
||||
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(create_pool(max_threads)?
|
||||
|
@ -1,6 +1,7 @@
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type,
|
||||
@ -101,6 +102,7 @@ impl Command for Reduce {
|
||||
let mut stack = stack.captures_to_stack(capture_block.captures);
|
||||
let block = engine_state.get_block(capture_block.block_id);
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
let orig_env_vars = stack.env_vars.clone();
|
||||
let orig_env_hidden = stack.env_hidden.clone();
|
||||
|
@ -1,6 +1,7 @@
|
||||
use indexmap::IndexMap;
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Example, IntoPipelineData, PipelineData, Record, ShellError, Signature,
|
||||
@ -156,6 +157,8 @@ fn rename(
|
||||
let columns: Vec<String> = call.rest(engine_state, stack, 0)?;
|
||||
let metadata = input.metadata();
|
||||
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
let head_span = call.head;
|
||||
input
|
||||
.map(
|
||||
@ -176,6 +179,7 @@ fn rename(
|
||||
stack.add_var(*var_id, Value::string(c.clone(), span))
|
||||
}
|
||||
}
|
||||
|
||||
let eval_result = eval_block_with_early_return(
|
||||
&engine_state,
|
||||
&mut stack,
|
||||
@ -184,6 +188,7 @@ fn rename(
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
);
|
||||
|
||||
match eval_result {
|
||||
Err(e) => return Value::error(e, span),
|
||||
Ok(res) => match res.collect_string_strict(span) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -94,6 +95,8 @@ impl Command for SkipUntil {
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
|
||||
let eval_block = get_eval_block(&engine_state);
|
||||
|
||||
Ok(input
|
||||
.into_iter_strict(span)?
|
||||
.skip_while(move |value| {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -99,6 +100,8 @@ impl Command for SkipWhile {
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
|
||||
let eval_block = get_eval_block(&engine_state);
|
||||
|
||||
Ok(input
|
||||
.into_iter_strict(span)?
|
||||
.skip_while(move |value| {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -91,6 +92,8 @@ impl Command for TakeUntil {
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
|
||||
let eval_block = get_eval_block(&engine_state);
|
||||
|
||||
Ok(input
|
||||
.into_iter_strict(span)?
|
||||
.take_while(move |value| {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -91,6 +91,8 @@ impl Command for TakeWhile {
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
|
||||
let eval_block = get_eval_block(&engine_state);
|
||||
|
||||
Ok(input
|
||||
.into_iter_strict(span)?
|
||||
.take_while(move |value| {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{sync::mpsc, thread};
|
||||
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -83,6 +83,8 @@ use it in your pipeline."#
|
||||
let metadata = input.metadata();
|
||||
let metadata_clone = metadata.clone();
|
||||
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
match input {
|
||||
// Handle external streams specially, to make sure they pass through
|
||||
PipelineData::ExternalStream {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt, EvalBlockFn};
|
||||
use nu_protocol::ast::{Block, Call, CellPath, PathMember};
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData,
|
||||
@ -116,6 +117,8 @@ fn update(
|
||||
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
match input {
|
||||
PipelineData::Value(mut value, metadata) => {
|
||||
if replacement.coerce_block().is_ok() {
|
||||
@ -137,6 +140,7 @@ fn update(
|
||||
block,
|
||||
&cell_path.members,
|
||||
false,
|
||||
eval_block,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@ -150,6 +154,7 @@ fn update(
|
||||
redirect_stderr,
|
||||
&cell_path.members,
|
||||
matches!(first, Some(PathMember::Int { .. })),
|
||||
eval_block,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@ -196,6 +201,7 @@ fn update(
|
||||
redirect_stderr,
|
||||
path,
|
||||
true,
|
||||
eval_block,
|
||||
)?;
|
||||
} else {
|
||||
value.update_data_at_cell_path(path, replacement)?;
|
||||
@ -228,6 +234,7 @@ fn update(
|
||||
&block,
|
||||
&cell_path.members,
|
||||
false,
|
||||
eval_block,
|
||||
);
|
||||
|
||||
if let Err(e) = err {
|
||||
@ -273,6 +280,7 @@ fn update_value_by_closure(
|
||||
block: &Block,
|
||||
cell_path: &[PathMember],
|
||||
first_path_member_int: bool,
|
||||
eval_block_fn: EvalBlockFn,
|
||||
) -> Result<(), ShellError> {
|
||||
let input_at_path = value.clone().follow_cell_path(cell_path, false)?;
|
||||
|
||||
@ -289,7 +297,7 @@ fn update_value_by_closure(
|
||||
}
|
||||
}
|
||||
|
||||
let output = eval_block(
|
||||
let output = eval_block_fn(
|
||||
engine_state,
|
||||
stack,
|
||||
block,
|
||||
@ -311,6 +319,7 @@ fn update_single_value_by_closure(
|
||||
redirect_stderr: bool,
|
||||
cell_path: &[PathMember],
|
||||
first_path_member_int: bool,
|
||||
eval_block_fn: EvalBlockFn,
|
||||
) -> Result<(), ShellError> {
|
||||
let span = replacement.span();
|
||||
let capture_block = Closure::from_value(replacement)?;
|
||||
@ -327,6 +336,7 @@ fn update_single_value_by_closure(
|
||||
block,
|
||||
cell_path,
|
||||
first_path_member_int,
|
||||
eval_block_fn,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt, EvalBlockFn};
|
||||
use nu_protocol::ast::{Block, Call, CellPath, PathMember};
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData,
|
||||
@ -158,6 +159,7 @@ fn upsert(
|
||||
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
|
||||
@ -182,6 +184,7 @@ fn upsert(
|
||||
block,
|
||||
&cell_path.members,
|
||||
false,
|
||||
eval_block,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@ -195,6 +198,7 @@ fn upsert(
|
||||
redirect_stderr,
|
||||
&cell_path.members,
|
||||
matches!(first, Some(PathMember::Int { .. })),
|
||||
eval_block,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@ -264,6 +268,7 @@ fn upsert(
|
||||
redirect_stderr,
|
||||
path,
|
||||
true,
|
||||
eval_block,
|
||||
)?;
|
||||
} else {
|
||||
value.upsert_data_at_cell_path(path, replacement)?;
|
||||
@ -303,6 +308,7 @@ fn upsert(
|
||||
&block,
|
||||
&cell_path.members,
|
||||
false,
|
||||
eval_block,
|
||||
);
|
||||
|
||||
if let Err(e) = err {
|
||||
@ -348,6 +354,7 @@ fn upsert_value_by_closure(
|
||||
block: &Block,
|
||||
cell_path: &[PathMember],
|
||||
first_path_member_int: bool,
|
||||
eval_block_fn: EvalBlockFn,
|
||||
) -> Result<(), ShellError> {
|
||||
let input_at_path = value.clone().follow_cell_path(cell_path, false);
|
||||
|
||||
@ -368,7 +375,7 @@ fn upsert_value_by_closure(
|
||||
.map(IntoPipelineData::into_pipeline_data)
|
||||
.unwrap_or(PipelineData::Empty);
|
||||
|
||||
let output = eval_block(
|
||||
let output = eval_block_fn(
|
||||
engine_state,
|
||||
stack,
|
||||
block,
|
||||
@ -390,6 +397,7 @@ fn upsert_single_value_by_closure(
|
||||
redirect_stderr: bool,
|
||||
cell_path: &[PathMember],
|
||||
first_path_member_int: bool,
|
||||
eval_block_fn: EvalBlockFn,
|
||||
) -> Result<(), ShellError> {
|
||||
let span = replacement.span();
|
||||
let capture_block = Closure::from_value(replacement)?;
|
||||
@ -406,6 +414,7 @@ fn upsert_single_value_by_closure(
|
||||
block,
|
||||
cell_path,
|
||||
first_path_member_int,
|
||||
eval_block_fn,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, EngineState, Stack},
|
||||
@ -40,6 +41,10 @@ pub fn boolean_fold(
|
||||
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
|
||||
// TODO: This Clippy lint is incorrectly triggered in our CI for come reason
|
||||
#[allow(clippy::needless_borrow)]
|
||||
let eval_block = get_eval_block(&engine_state);
|
||||
|
||||
for value in input.into_interruptible_iter(ctrlc) {
|
||||
// with_env() is used here to ensure that each iteration uses
|
||||
// a different set of environment variables.
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_engine::{get_eval_block, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
|
||||
@ -70,6 +71,9 @@ not supported."#
|
||||
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
|
||||
let eval_block = get_eval_block(&engine_state);
|
||||
|
||||
Ok(input
|
||||
.into_iter_strict(span)?
|
||||
.filter_map(move |value| {
|
||||
@ -80,6 +84,7 @@ not supported."#
|
||||
stack.add_var(*var_id, value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let result = eval_block(
|
||||
&engine_state,
|
||||
&mut stack,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
@ -102,6 +102,7 @@ impl Command for Zip {
|
||||
let head = call.head;
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
let metadata = input.metadata();
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
let other: PipelineData = match call.req(engine_state, stack, 0)? {
|
||||
// If a closure was provided, evaluate it and consume its stream output
|
||||
|
@ -1,5 +1,6 @@
|
||||
use itertools::unfold;
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Closure, Command, EngineState, Stack},
|
||||
@ -107,6 +108,7 @@ used as the next argument to the closure, otherwise generation stops.
|
||||
let orig_env_hidden = stack.env_hidden.clone();
|
||||
let redirect_stdout = call.redirect_stdout;
|
||||
let redirect_stderr = call.redirect_stderr;
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(&engine_state);
|
||||
|
||||
// A type of Option<S> is used to represent state. Invocation
|
||||
// will stop on None. Using Option<S> allows functions to output
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||
use nu_engine::{get_eval_block_with_early_return, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
|
||||
|
||||
@ -46,8 +47,10 @@ impl Command for Source {
|
||||
// Note: this hidden positional is the block_id that corresponded to the 0th position
|
||||
// it is put here by the parser
|
||||
let block_id: i64 = call.req_parser_info(engine_state, stack, "block_id")?;
|
||||
|
||||
let block = engine_state.get_block(block_id as usize).clone();
|
||||
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
eval_block_with_early_return(
|
||||
engine_state,
|
||||
stack,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use nu_cmd_base::hook::eval_hook;
|
||||
use nu_engine::env_to_strings;
|
||||
use nu_engine::eval_expression;
|
||||
use nu_engine::get_eval_expression;
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::IntoSpanned;
|
||||
use nu_protocol::NuGlob;
|
||||
@ -133,6 +133,8 @@ pub fn create_external_command(
|
||||
})
|
||||
}
|
||||
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
|
||||
let mut spanned_args = vec![];
|
||||
let mut arg_keep_raw = vec![];
|
||||
for (arg, spread) in call.rest_iter(1) {
|
||||
|
Reference in New Issue
Block a user