diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index 817950a445..80e8833897 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -97,7 +97,7 @@ pub fn evaluate_repl( Value::string("0823", Span::unknown()), ); - unique_stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(0, Span::unknown())); + unique_stack.set_last_exit_code(0, Span::unknown()); let mut line_editor = get_line_editor(engine_state, nushell_path, use_color)?; let temp_file = temp_dir().join(format!("{}.nu", uuid::Uuid::new_v4())); @@ -837,7 +837,7 @@ fn do_auto_cd( "NUSHELL_LAST_SHELL".into(), Value::int(last_shell as i64, span), ); - stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(0, Span::unknown())); + stack.set_last_exit_code(0, Span::unknown()); } /// diff --git a/crates/nu-cli/src/util.rs b/crates/nu-cli/src/util.rs index 5ee0bdd3c0..8ab1b7bad9 100644 --- a/crates/nu-cli/src/util.rs +++ b/crates/nu-cli/src/util.rs @@ -211,17 +211,14 @@ pub fn eval_source( let exit_code = match evaluate_source(engine_state, stack, source, fname, input, allow_return) { Ok(failed) => { - let code = i32::from(failed); - stack.add_env_var( - "LAST_EXIT_CODE".into(), - Value::int(code.into(), Span::unknown()), - ); + let code = failed.into(); + stack.set_last_exit_code(code, Span::unknown()); code } Err(err) => { report_error_new(engine_state, &err); let code = err.exit_code(); - stack.set_last_exit_code(&err); + stack.set_last_error(&err); code } }; diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 9384931cf7..ccb494e68e 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -490,7 +490,7 @@ pub fn eval_block_with_early_return( } } -pub fn eval_block( +fn eval_block_inner( engine_state: &EngineState, stack: &mut Stack, block: &Block, @@ -501,8 +501,6 @@ pub fn eval_block( return eval_ir_block::(engine_state, stack, block, input); } - D::enter_block(engine_state, block); - let num_pipelines = block.len(); for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() { @@ -547,10 +545,10 @@ pub fn eval_block( PipelineData::ByteStream(stream, ..) => { let span = stream.span(); if let Err(err) = stream.drain() { - stack.set_last_exit_code(&err); + stack.set_last_error(&err); return Err(err); } else { - stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(0, span)); + stack.set_last_exit_code(0, span); } } PipelineData::ListStream(stream, ..) => stream.drain()?, @@ -560,11 +558,24 @@ pub fn eval_block( } } - D::leave_block(engine_state, block); - Ok(input) } +pub fn eval_block( + engine_state: &EngineState, + stack: &mut Stack, + block: &Block, + input: PipelineData, +) -> Result { + D::enter_block(engine_state, block); + let result = eval_block_inner::(engine_state, stack, block, input); + D::leave_block(engine_state, block); + if let Err(err) = &result { + stack.set_last_error(err); + } + result +} + pub fn eval_collect( engine_state: &EngineState, stack: &mut Stack, diff --git a/crates/nu-engine/src/eval_ir.rs b/crates/nu-engine/src/eval_ir.rs index d731b71ee9..2d142e4f3d 100644 --- a/crates/nu-engine/src/eval_ir.rs +++ b/crates/nu-engine/src/eval_ir.rs @@ -1356,11 +1356,10 @@ fn drain(ctx: &mut EvalContext<'_>, data: PipelineData) -> Result { let span = stream.span(); if let Err(err) = stream.drain() { - ctx.stack.set_last_exit_code(&err); + ctx.stack.set_last_error(&err); return Err(err); } else { - ctx.stack - .add_env_var("LAST_EXIT_CODE".into(), Value::int(0, span)); + ctx.stack.set_last_exit_code(0, span); } } PipelineData::ListStream(stream, ..) => stream.drain()?, diff --git a/crates/nu-protocol/src/engine/stack.rs b/crates/nu-protocol/src/engine/stack.rs index fd3bd70c1e..26e77f4444 100644 --- a/crates/nu-protocol/src/engine/stack.rs +++ b/crates/nu-protocol/src/engine/stack.rs @@ -279,12 +279,14 @@ impl Stack { } } - pub fn set_last_exit_code(&mut self, error: &ShellError) { - let code = error.exit_code_spanned(); - self.add_env_var( - "LAST_EXIT_CODE".into(), - Value::int(code.item.into(), code.span), - ); + pub fn set_last_exit_code(&mut self, code: i32, span: Span) { + self.add_env_var("LAST_EXIT_CODE".into(), Value::int(code.into(), span)); + } + + pub fn set_last_error(&mut self, error: &ShellError) { + if let Some(code) = error.external_exit_code() { + self.set_last_exit_code(code.item, code.span); + } } pub fn last_overlay_name(&self) -> Result { diff --git a/crates/nu-protocol/src/errors/shell_error.rs b/crates/nu-protocol/src/errors/shell_error.rs index 01be884044..da9aed6904 100644 --- a/crates/nu-protocol/src/errors/shell_error.rs +++ b/crates/nu-protocol/src/errors/shell_error.rs @@ -1437,18 +1437,18 @@ On Windows, this would be %USERPROFILE%\AppData\Roaming"# } impl ShellError { - pub fn exit_code_spanned(&self) -> Spanned { + pub fn external_exit_code(&self) -> Option> { let (item, span) = match *self { Self::NonZeroExitCode { exit_code, span } => (exit_code, span), Self::ProcessSignaled { signal, span, .. } | Self::ProcessCoreDumped { signal, span, .. } => (-signal, span), - _ => (1, Span::unknown()), // TODO: better span here + _ => return None, }; - Spanned { item, span } + Some(Spanned { item, span }) } pub fn exit_code(&self) -> i32 { - self.exit_code_spanned().item + self.external_exit_code().map(|e| e.item).unwrap_or(1) } // TODO: Implement as From trait