mirror of
https://github.com/nushell/nushell.git
synced 2025-04-26 14:18:19 +02:00
Make catch block a closure w/ access to error (#7228)
A small follow-up to #7221. This changes the `catch` block from a block to a closure, so that it can access the error returned from the `try` block. This helps with a common scenario: "the `try` block failed, and I want to log why it failed." ### Example  ### Future Work Nu's closure syntax is a little awkward here; it might be nicer to allow something like `catch err { print $err }`. We discussed this on Discord and it will require special parser code similar to what's already done for `for`. I'm not feeling confident enough in my parser knowledge to make that change; I will spend some more time looking at the `for` code but I doubt I will be able to implement anything in the next few days. Volunteers welcome.
This commit is contained in:
parent
04612809ab
commit
ed1f0eb231
@ -1,6 +1,6 @@
|
|||||||
use nu_engine::{eval_block, CallExt};
|
use nu_engine::{eval_block, CallExt};
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Block, Command, EngineState, Stack};
|
use nu_protocol::engine::{Block, Closure, Command, EngineState, Stack};
|
||||||
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type, Value};
|
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type, Value};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -21,7 +21,10 @@ impl Command for Try {
|
|||||||
.required("try_block", SyntaxShape::Block, "block to run")
|
.required("try_block", SyntaxShape::Block, "block to run")
|
||||||
.optional(
|
.optional(
|
||||||
"else_expression",
|
"else_expression",
|
||||||
SyntaxShape::Keyword(b"catch".to_vec(), Box::new(SyntaxShape::Block)),
|
SyntaxShape::Keyword(
|
||||||
|
b"catch".to_vec(),
|
||||||
|
Box::new(SyntaxShape::Closure(Some(vec![SyntaxShape::Any]))),
|
||||||
|
),
|
||||||
"block to run if try block fails",
|
"block to run if try block fails",
|
||||||
)
|
)
|
||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
@ -44,16 +47,24 @@ impl Command for Try {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let try_block: Block = call.req(engine_state, stack, 0)?;
|
let try_block: Block = call.req(engine_state, stack, 0)?;
|
||||||
let catch_block: Option<Block> = call.opt(engine_state, stack, 1)?;
|
let catch_block: Option<Closure> = call.opt(engine_state, stack, 1)?;
|
||||||
|
|
||||||
let try_block = engine_state.get_block(try_block.block_id);
|
let try_block = engine_state.get_block(try_block.block_id);
|
||||||
|
|
||||||
let result = eval_block(engine_state, stack, try_block, input, false, false);
|
let result = eval_block(engine_state, stack, try_block, input, false, false);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(_) | Ok(PipelineData::Value(Value::Error { .. }, ..)) => {
|
Err(error) | Ok(PipelineData::Value(Value::Error { error }, ..)) => {
|
||||||
if let Some(catch_block) = catch_block {
|
if let Some(catch_block) = catch_block {
|
||||||
let catch_block = engine_state.get_block(catch_block.block_id);
|
let catch_block = engine_state.get_block(catch_block.block_id);
|
||||||
|
|
||||||
|
if let Some(var) = catch_block.signature.get_positional(0) {
|
||||||
|
if let Some(var_id) = &var.var_id {
|
||||||
|
let err_value = Value::Error { error };
|
||||||
|
stack.add_var(*var_id, err_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eval_block(
|
eval_block(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
|
@ -24,3 +24,15 @@ fn try_catch() {
|
|||||||
assert!(output.out.contains("hello"));
|
assert!(output.out.contains("hello"));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn catch_can_access_error() {
|
||||||
|
Playground::setup("try_catch_test", |dirs, _sandbox| {
|
||||||
|
let output = nu!(
|
||||||
|
cwd: dirs.test(),
|
||||||
|
"try { foobarbaz } catch { |err| $err }"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(output.err.contains("External command failed"));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user