From b752fdb0dce410dbcc872f8681b78b7dfbae9ba3 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Tue, 26 Mar 2024 18:22:34 +0000 Subject: [PATCH] Always pretty print binary values in `table` (#12294) # Description Binary values passed to `table` may or may not be pretty formatted based on the output destination. This leads to weird behavior as documented in #12287. This PR changes `table` to always pretty print binary values. However, binary values passed to external commands will not be formatted (this is the existing behavior). # User-Facing Changes This is a breaking change. E.g.: ```nushell 0x[8989] | table | cat - ``` used to print raw bytes, but it will now print the pretty formatted bytes. # After Submitting Add to 0.92.0 release notes and update documentation. --- crates/nu-command/src/system/run_external.rs | 34 ++++++++++++-------- crates/nu-command/src/viewers/table.rs | 21 +++--------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index 4b9f84eee4..126065f49c 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -466,20 +466,26 @@ impl ExternalCommand { thread::Builder::new() .name("external stdin worker".to_string()) .spawn(move || { - let stack = &mut stack.start_capture(); - // Attempt to render the input as a table before piping it to the external. - // This is important for pagers like `less`; - // they need to get Nu data rendered for display to users. - // - // TODO: should we do something different for list inputs? - // Users often expect those to be piped to *nix tools as raw strings separated by newlines - let input = crate::Table::run( - &crate::Table, - &engine_state, - stack, - &Call::new(head), - input, - ); + let input = match input { + input @ PipelineData::Value(Value::Binary { .. }, ..) => { + Ok(input) + } + input => { + let stack = &mut stack.start_capture(); + // Attempt to render the input as a table before piping it to the external. + // This is important for pagers like `less`; + // they need to get Nu data rendered for display to users. + // + // TODO: should we do something different for list inputs? + // Users often expect those to be piped to *nix tools as raw strings separated by newlines + crate::Table.run( + &engine_state, + stack, + &Call::new(head), + input, + ) + } + }; if let Ok(input) = input { for value in input.into_iter() { diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index 90ed150f26..67bc5ca1ed 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -9,9 +9,9 @@ use nu_engine::{env::get_config, env_to_string, CallExt}; use nu_protocol::{ ast::Call, engine::{Command, EngineState, Stack}, - record, Category, Config, DataSource, Example, IntoPipelineData, IoStream, ListStream, - PipelineData, PipelineMetadata, RawStream, Record, ShellError, Signature, Span, SyntaxShape, - TableMode, Type, Value, + record, Category, Config, DataSource, Example, IntoPipelineData, ListStream, PipelineData, + PipelineMetadata, RawStream, Record, ShellError, Signature, Span, SyntaxShape, TableMode, Type, + Value, }; use nu_table::common::create_nu_table_config; use nu_table::{ @@ -370,21 +370,10 @@ fn handle_table_command( match input.data { PipelineData::ExternalStream { .. } => Ok(input.data), PipelineData::Value(Value::Binary { val, .. }, ..) => { - let stream_list = if matches!( - input.stack.stdout(), - IoStream::Pipe | IoStream::Capture | IoStream::Null - ) { - vec![Ok(val)] - } else { - let hex = format!("{}\n", nu_pretty_hex::pretty_hex(&val)) - .as_bytes() - .to_vec(); - vec![Ok(hex)] - }; - + let bytes = format!("{}\n", nu_pretty_hex::pretty_hex(&val)).into_bytes(); let ctrlc = input.engine_state.ctrlc.clone(); let stream = RawStream::new( - Box::new(stream_list.into_iter()), + Box::new([Ok(bytes)].into_iter()), ctrlc, input.call.head, None,