Add NU_REPL_PREV_ERROR env variable

This commit is contained in:
Ian Manske 2024-09-29 13:23:13 -07:00
parent 8200831b07
commit 87843966fb
6 changed files with 72 additions and 26 deletions

View File

@ -121,7 +121,7 @@ fn bench_eval_source(
let mut engine = engine.clone();
let fname: &str = &fname.clone();
let source: &[u8] = &source.clone();
black_box(eval_source(
let _ = black_box(eval_source(
&mut engine,
&mut stack,
source,

View File

@ -299,7 +299,8 @@ pub fn migrate_old_plugin_file(engine_state: &EngineState, storage_path: &str) -
&old_plugin_file_path.to_string_lossy(),
PipelineData::Empty,
false,
) != 0
)
.is_err()
{
return false;
}

View File

@ -1,4 +1,4 @@
use crate::util::eval_source;
use crate::util::{eval_source, ParseOrShellError};
use log::{info, trace};
use nu_engine::{convert_env_values, eval_block};
use nu_parser::parse;
@ -106,7 +106,7 @@ pub fn evaluate_file(
engine_state.merge_delta(working_set.delta)?;
// Check if the file contains a main command.
let exit_code = if engine_state.find_decl(b"main", &[]).is_some() {
let result = if engine_state.find_decl(b"main", &[]).is_some() {
// Evaluate the file, but don't run main yet.
let pipeline =
match eval_block::<WithoutDebug>(engine_state, stack, &block, PipelineData::empty()) {
@ -136,7 +136,11 @@ pub fn evaluate_file(
eval_source(engine_state, stack, &file, file_path_str, input, true)
};
if exit_code != 0 {
if let Err(err) = result {
let exit_code = match err {
ParseOrShellError::ShellError(err) => err.exit_code(),
ParseOrShellError::ParseError(_) => 1,
};
std::process::exit(exit_code);
}

View File

@ -10,7 +10,7 @@ use crate::{
nu_highlight::NoOpHighlighter,
prompt_update,
reedline_config::{add_menus, create_keybindings, KeybindingsMode},
util::eval_source,
util::{eval_source, ParseOrShellError},
NuHighlighter, NuValidator, NushellPrompt,
};
use crossterm::cursor::SetCursorStyle;
@ -27,6 +27,7 @@ use nu_protocol::{
report_shell_error, HistoryConfig, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
Value,
};
use nu_protocol::{record, IntoValue};
use nu_utils::{
filesystem::{have_permission, PermissionResult},
perf,
@ -101,7 +102,8 @@ pub fn evaluate_repl(
let temp_file = temp_dir().join(format!("{}.nu", uuid::Uuid::new_v4()));
if let Some(s) = prerun_command {
eval_source(
// TODO: ignore this error?
let _ = eval_source(
engine_state,
&mut unique_stack,
s.item.as_bytes(),
@ -156,7 +158,8 @@ pub fn evaluate_repl(
engine_state.generate_nu_constant();
if load_std_lib.is_none() && engine_state.get_config().show_banner {
eval_source(
// TODO: ignore this error?
let _ = eval_source(
engine_state,
&mut unique_stack,
r#"use std banner; banner"#.as_bytes(),
@ -906,7 +909,7 @@ fn do_run_cmd(
run_shell_integration_osc2(Some(s), engine_state, stack, use_color);
}
eval_source(
let result = eval_source(
engine_state,
stack,
s.as_bytes(),
@ -915,6 +918,21 @@ fn do_run_cmd(
false,
);
if let Err(err) = result {
let span = Span::unknown();
let err = match err {
ParseOrShellError::ShellError(err) => err.into_value(span),
ParseOrShellError::ParseError(err) => record! {
"msg" => Value::string(err.to_string(), span),
"debug" => Value::string(format!("{err:?}"), span),
}
.into_value(span),
};
stack.add_env_var("NU_REPL_PREV_ERROR".into(), err);
} else {
stack.remove_env_var(engine_state, "NU_REPL_PREV_ERROR");
}
line_editor
}

View File

@ -5,8 +5,8 @@ use nu_protocol::{
cli_error::report_compile_error,
debugger::WithoutDebug,
engine::{EngineState, Stack, StateWorkingSet},
report_parse_error, report_parse_warning, report_shell_error, PipelineData, ShellError, Span,
Value,
report_parse_error, report_parse_warning, report_shell_error, ParseError, PipelineData,
ShellError, Span, Value,
};
#[cfg(windows)]
use nu_utils::enable_vt_processing;
@ -201,6 +201,24 @@ fn gather_env_vars(
}
}
#[derive(Clone, Debug)]
pub enum ParseOrShellError {
ParseError(ParseError),
ShellError(ShellError),
}
impl From<ParseError> for ParseOrShellError {
fn from(err: ParseError) -> Self {
Self::ParseError(err)
}
}
impl From<ShellError> for ParseOrShellError {
fn from(err: ShellError) -> Self {
Self::ShellError(err)
}
}
pub fn eval_source(
engine_state: &mut EngineState,
stack: &mut Stack,
@ -208,20 +226,22 @@ pub fn eval_source(
fname: &str,
input: PipelineData,
allow_return: bool,
) -> i32 {
) -> Result<(), ParseOrShellError> {
let start_time = std::time::Instant::now();
let exit_code = match evaluate_source(engine_state, stack, source, fname, input, allow_return) {
Ok(failed) => {
let code = failed.into();
stack.set_last_exit_code(code, Span::unknown());
code
let result = match evaluate_source(engine_state, stack, source, fname, input, allow_return) {
Ok(()) => {
stack.set_last_exit_code(0, Span::unknown());
Ok(())
}
Err(err) => {
Err(ParseOrShellError::ShellError(err)) => {
report_shell_error(engine_state, &err);
let code = err.exit_code();
stack.set_last_error(&err);
code
Err(ParseOrShellError::ShellError(err))
}
Err(ParseOrShellError::ParseError(err)) => {
stack.set_last_exit_code(1, Span::unknown());
Err(ParseOrShellError::ParseError(err))
}
};
@ -237,7 +257,7 @@ pub fn eval_source(
engine_state.get_config().use_ansi_coloring
);
exit_code
result
}
fn evaluate_source(
@ -247,7 +267,7 @@ fn evaluate_source(
fname: &str,
input: PipelineData,
allow_return: bool,
) -> Result<bool, ShellError> {
) -> Result<(), ParseOrShellError> {
let (block, delta) = {
let mut working_set = StateWorkingSet::new(engine_state);
let output = parse(
@ -262,7 +282,7 @@ fn evaluate_source(
if let Some(err) = working_set.parse_errors.first() {
report_parse_error(&working_set, err);
return Ok(true);
return Err(ParseOrShellError::ParseError(err.clone()));
}
if let Some(err) = working_set.compile_errors.first() {
@ -297,7 +317,7 @@ fn evaluate_source(
pipeline.print(engine_state, stack, true, false)
}?;
Ok(false)
Ok(())
}
#[cfg(test)]

View File

@ -155,7 +155,9 @@ pub(crate) fn read_loginshell_file(engine_state: &mut EngineState, stack: &mut S
pub(crate) fn read_default_env_file(engine_state: &mut EngineState, stack: &mut Stack) {
let config_file = get_default_env();
eval_source(
// TODO: ignore this error?
let _ = eval_source(
engine_state,
stack,
config_file.as_bytes(),
@ -236,7 +238,8 @@ fn eval_default_config(
&config_file, is_env_config
);
// Just use the contents of "default_config.nu" or "default_env.nu"
eval_source(
// TODO: ignore this error?
let _ = eval_source(
engine_state,
stack,
config_file.as_bytes(),