diff --git a/benches/benchmarks.rs b/benches/benchmarks.rs index 913c87e899..304c3e2f3d 100644 --- a/benches/benchmarks.rs +++ b/benches/benchmarks.rs @@ -85,6 +85,7 @@ fn bench_command_with_custom_stack_and_engine( &mut stack.clone(), PipelineData::empty(), None, + false, ) .unwrap(); }) @@ -104,6 +105,7 @@ fn setup_stack_and_engine_from_command(command: &str) -> (Stack, EngineState) { &mut stack, PipelineData::empty(), None, + false, ) .unwrap(); @@ -263,6 +265,7 @@ mod eval_commands { &mut nu_protocol::engine::Stack::new(), PipelineData::empty(), None, + false, ) .unwrap(); }) diff --git a/crates/nu-cli/src/eval_cmds.rs b/crates/nu-cli/src/eval_cmds.rs index e29eb6f5f4..1e3cc70348 100644 --- a/crates/nu-cli/src/eval_cmds.rs +++ b/crates/nu-cli/src/eval_cmds.rs @@ -15,6 +15,7 @@ pub fn evaluate_commands( stack: &mut Stack, input: PipelineData, table_mode: Option, + no_newline: bool, ) -> Result> { // Translate environment variables from Strings to Values if let Some(e) = convert_env_values(engine_state, stack) { @@ -60,7 +61,13 @@ pub fn evaluate_commands( if let Some(t_mode) = table_mode { config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default(); } - crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &mut config) + crate::eval_file::print_table_or_error( + engine_state, + stack, + pipeline_data, + &mut config, + no_newline, + ) } Err(err) => { let working_set = StateWorkingSet::new(engine_state); diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index 68d16abf30..f69b14113e 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -185,6 +185,7 @@ pub(crate) fn print_table_or_error( stack: &mut Stack, mut pipeline_data: PipelineData, config: &mut Config, + no_newline: bool, ) -> Option { let exit_code = match &mut pipeline_data { PipelineData::ExternalStream { exit_code, .. } => exit_code.take(), @@ -203,7 +204,7 @@ pub(crate) fn print_table_or_error( 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); + 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)); @@ -211,7 +212,7 @@ pub(crate) fn print_table_or_error( match table { Ok(table) => { - print_or_exit(table, engine_state, config); + print_or_exit(table, engine_state, config, no_newline); } Err(error) => { let working_set = StateWorkingSet::new(engine_state); @@ -221,7 +222,7 @@ pub(crate) fn print_table_or_error( } } } else { - print_or_exit(pipeline_data, engine_state, config); + print_or_exit(pipeline_data, engine_state, config, no_newline); } // Make sure everything has finished @@ -238,7 +239,12 @@ pub(crate) fn print_table_or_error( } } -fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, config: &Config) { +fn print_or_exit( + pipeline_data: PipelineData, + engine_state: &mut EngineState, + config: &Config, + no_newline: bool, +) { for item in pipeline_data { if let Value::Error { error, .. } = item { let working_set = StateWorkingSet::new(engine_state); @@ -248,7 +254,10 @@ fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, co std::process::exit(1); } - let out = item.to_expanded_string("\n", config) + "\n"; + 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}")); } } diff --git a/src/command.rs b/src/command.rs index f6f06d04da..049b9606ca 100644 --- a/src/command.rs +++ b/src/command.rs @@ -97,6 +97,7 @@ pub(crate) fn parse_commandline_args( let execute = call.get_flag_expr("execute"); let table_mode: Option = call.get_flag(engine_state, &mut stack, "table-mode")?; + let no_newline = call.get_named_arg("no-newline"); // ide flags let lsp = call.has_flag(engine_state, &mut stack, "lsp")?; @@ -190,6 +191,7 @@ pub(crate) fn parse_commandline_args( ide_check, ide_ast, table_mode, + no_newline, }); } } @@ -224,6 +226,7 @@ pub(crate) struct NushellCliArgs { pub(crate) log_target: Option>, pub(crate) execute: Option>, pub(crate) table_mode: Option, + pub(crate) no_newline: Option>, pub(crate) include_path: Option>, pub(crate) lsp: bool, pub(crate) ide_goto_def: Option, @@ -270,6 +273,7 @@ impl Command for Nu { "the table mode to use. rounded is default.", Some('m'), ) + .switch("no-newline", "print the result for --commands(-c) without a newline", None) .switch( "no-config-file", "start with no config file and no env file", diff --git a/src/run.rs b/src/run.rs index 576b6c9abd..2dc3afa383 100644 --- a/src/run.rs +++ b/src/run.rs @@ -118,6 +118,7 @@ pub(crate) fn run_commands( &mut stack, input, parsed_nu_cli_args.table_mode, + parsed_nu_cli_args.no_newline.is_some(), ); perf( "evaluate_commands", diff --git a/tests/shell/mod.rs b/tests/shell/mod.rs index 69fb92bd51..433e193423 100644 --- a/tests/shell/mod.rs +++ b/tests/shell/mod.rs @@ -273,6 +273,17 @@ fn run_in_noninteractive_mode() { assert!(child_output.stderr.is_empty()); } +#[test] +fn run_with_no_newline() { + let child_output = std::process::Command::new(nu_test_support::fs::executable_path()) + .args(["--no-newline", "-c", "\"hello world\""]) + .output() + .expect("failed to run nu"); + + assert_eq!("hello world", String::from_utf8_lossy(&child_output.stdout)); // with no newline + assert!(child_output.stderr.is_empty()); +} + #[test] fn main_script_can_have_subcommands1() { Playground::setup("main_subcommands", |dirs, sandbox| {