diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index d4061f33d6..85b07d629d 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -5,13 +5,11 @@ use nu_engine::{convert_env_values, current_dir, eval_block}; use nu_parser::parse; use nu_path::canonicalize_with; use nu_protocol::{ - ast::Call, debugger::WithoutDebug, engine::{EngineState, Stack, StateWorkingSet}, report_error, Config, PipelineData, ShellError, Span, Value, }; -use nu_utils::stdout_write_all_and_flush; -use std::sync::Arc; +use std::{io::Write, sync::Arc}; /// Entry point for evaluating a file. /// @@ -210,29 +208,8 @@ pub(crate) fn print_table_or_error( std::process::exit(1); } - if let Some(decl_id) = engine_state.find_decl("table".as_bytes(), &[]) { - let command = engine_state.get_decl(decl_id); - if command.get_block_id().is_some() { - print_or_exit(pipeline_data, engine_state, config, no_newline); - } else { - // The final call on table command, it's ok to set redirect_output to false. - let call = Call::new(Span::new(0, 0)); - let table = command.run(engine_state, stack, &call, pipeline_data); - - match table { - Ok(table) => { - print_or_exit(table, engine_state, config, no_newline); - } - Err(error) => { - let working_set = StateWorkingSet::new(engine_state); - report_error(&working_set, &error); - std::process::exit(1); - } - } - } - } else { - print_or_exit(pipeline_data, engine_state, config, no_newline); - } + // We don't need to do anything special to print a table because print() handles it + print_or_exit(pipeline_data, engine_state, stack, no_newline); // Make sure everything has finished if let Some(exit_code) = exit_code { @@ -250,23 +227,19 @@ pub(crate) fn print_table_or_error( fn print_or_exit( pipeline_data: PipelineData, - engine_state: &mut EngineState, - config: &Config, + engine_state: &EngineState, + stack: &mut Stack, no_newline: bool, ) { - for item in pipeline_data { - if let Value::Error { error, .. } = item { - let working_set = StateWorkingSet::new(engine_state); + let result = pipeline_data.print(engine_state, stack, no_newline, false); - report_error(&working_set, &*error); + let _ = std::io::stdout().flush(); + let _ = std::io::stderr().flush(); - std::process::exit(1); - } - - let mut out = item.to_expanded_string("\n", config); - if !no_newline { - out.push('\n'); - } - let _ = stdout_write_all_and_flush(out).map_err(|err| eprintln!("{err}")); + if let Err(error) = result { + let working_set = StateWorkingSet::new(engine_state); + report_error(&working_set, &error); + let _ = std::io::stderr().flush(); + std::process::exit(1); } } diff --git a/crates/nu-command/src/filesystem/open.rs b/crates/nu-command/src/filesystem/open.rs index f671eef913..06c63e1532 100644 --- a/crates/nu-command/src/filesystem/open.rs +++ b/crates/nu-command/src/filesystem/open.rs @@ -145,7 +145,7 @@ impl Command for Open { let file_contents = PipelineData::ExternalStream { stdout: Some(RawStream::new( - Box::new(BufferedReader { input: buf_reader }), + Box::new(BufferedReader::new(buf_reader)), ctrlc.clone(), call_span, None, diff --git a/crates/nu-command/src/network/http/client.rs b/crates/nu-command/src/network/http/client.rs index dc5adbe0cd..2833f76a97 100644 --- a/crates/nu-command/src/network/http/client.rs +++ b/crates/nu-command/src/network/http/client.rs @@ -123,9 +123,7 @@ pub fn response_to_buffer( PipelineData::ExternalStream { stdout: Some(RawStream::new( - Box::new(BufferedReader { - input: buffered_input, - }), + Box::new(BufferedReader::new(buffered_input)), engine_state.ctrlc.clone(), span, buffer_size, diff --git a/crates/nu-protocol/src/pipeline_data/mod.rs b/crates/nu-protocol/src/pipeline_data/mod.rs index 9b1b6947ba..94096c31a4 100644 --- a/crates/nu-protocol/src/pipeline_data/mod.rs +++ b/crates/nu-protocol/src/pipeline_data/mod.rs @@ -998,8 +998,16 @@ pub fn print_if_stream( if nu_utils::ctrl_c::was_pressed(&ctrlc) { break; } - if let Ok(bytes) = bytes { - let _ = stderr.write_all(&bytes); + match bytes { + Ok(bytes) => { + let _ = stderr.write_all(&bytes); + } + Err(err) => { + // we don't have access to EngineState, but maybe logging the debug + // impl is better than nothing + eprintln!("Error in stderr stream: {err:?}"); + break; + } } } })?; diff --git a/crates/nu-protocol/src/util.rs b/crates/nu-protocol/src/util.rs index 13dca6e3a1..1c17c49e4c 100644 --- a/crates/nu-protocol/src/util.rs +++ b/crates/nu-protocol/src/util.rs @@ -2,12 +2,20 @@ use crate::ShellError; use std::io::{BufRead, BufReader, Read}; pub struct BufferedReader { - pub input: BufReader, + input: BufReader, + error: bool, } impl BufferedReader { pub fn new(input: BufReader) -> Self { - Self { input } + Self { + input, + error: false, + } + } + + pub fn into_inner(self) -> BufReader { + self.input } } @@ -15,6 +23,11 @@ impl Iterator for BufferedReader { type Item = Result, ShellError>; fn next(&mut self) -> Option { + // Don't try to read more data if an error occurs + if self.error { + return None; + } + let buffer = self.input.fill_buf(); match buffer { Ok(s) => { @@ -30,7 +43,10 @@ impl Iterator for BufferedReader { Some(Ok(result)) } } - Err(e) => Some(Err(ShellError::IOError { msg: e.to_string() })), + Err(e) => { + self.error = true; + Some(Err(ShellError::IOError { msg: e.to_string() })) + } } } }