mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
Add --raw
switch to print
for binary data (#13597)
# Description Something I meant to add a long time ago. We currently don't have a convenient way to print raw binary data intentionally. You can pipe it through `cat` to turn it into an unknown stream, or write it to a file and read it again, but we can't really just e.g. generate msgpack and write it to stdout without this. For example: ```nushell [abc def] | to msgpack | print --raw ``` This is useful for nushell scripts that will be piped into something else. It also means that `nu_plugin_nu_example` probably doesn't need to do this anymore, but I haven't adjusted it yet: ```nushell def tell_nushell_encoding [] { print -n "\u{0004}json" } ``` This happens to work because 0x04 is a valid UTF-8 character, but it wouldn't be possible if it were something above 0x80. `--raw` also formats other things without `table`, I figured the two things kind of go together. The output is kind of like `to text`. Debatable whether that should share the same flag, but it was easier that way and seemed reasonable. # User-Facing Changes - `print` new flag: `--raw` # Tests + Formatting Added tests. # After Submitting - [ ] release notes (command modified)
This commit is contained in:
parent
18772b73b3
commit
4e205cd9a7
3 changed files with 60 additions and 3 deletions
|
@ -22,6 +22,11 @@ impl Command for Print {
|
|||
Some('n'),
|
||||
)
|
||||
.switch("stderr", "print to stderr instead of stdout", Some('e'))
|
||||
.switch(
|
||||
"raw",
|
||||
"print without formatting (including binary data)",
|
||||
Some('r'),
|
||||
)
|
||||
.category(Category::Strings)
|
||||
}
|
||||
|
||||
|
@ -50,15 +55,25 @@ Since this command has no output, there is no point in piping it with other comm
|
|||
let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let no_newline = call.has_flag(engine_state, stack, "no-newline")?;
|
||||
let to_stderr = call.has_flag(engine_state, stack, "stderr")?;
|
||||
let raw = call.has_flag(engine_state, stack, "raw")?;
|
||||
|
||||
// This will allow for easy printing of pipelines as well
|
||||
if !args.is_empty() {
|
||||
for arg in args {
|
||||
arg.into_pipeline_data()
|
||||
.print(engine_state, stack, no_newline, to_stderr)?;
|
||||
if raw {
|
||||
arg.into_pipeline_data()
|
||||
.print_raw(engine_state, no_newline, to_stderr)?;
|
||||
} else {
|
||||
arg.into_pipeline_data()
|
||||
.print(engine_state, stack, no_newline, to_stderr)?;
|
||||
}
|
||||
}
|
||||
} else if !input.is_nothing() {
|
||||
input.print(engine_state, stack, no_newline, to_stderr)?;
|
||||
if raw {
|
||||
input.print_raw(engine_state, no_newline, to_stderr)?;
|
||||
} else {
|
||||
input.print(engine_state, stack, no_newline, to_stderr)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PipelineData::empty())
|
||||
|
@ -76,6 +91,11 @@ Since this command has no output, there is no point in piping it with other comm
|
|||
example: r#"print (2 + 3)"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Print 'ABC' from binary data",
|
||||
example: r#"0x[41 42 43] | print --raw"#,
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,3 +13,15 @@ fn print_to_stderr() {
|
|||
assert!(actual.out.is_empty());
|
||||
assert!(actual.err.contains("hello world"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_raw() {
|
||||
let actual = nu!("0x[41 42 43] | print --raw");
|
||||
assert_eq!(actual.out, "ABC");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_raw_stream() {
|
||||
let actual = nu!("[0x[66] 0x[6f 6f]] | bytes collect | print --raw");
|
||||
assert_eq!(actual.out, "foo");
|
||||
}
|
||||
|
|
|
@ -604,6 +604,31 @@ impl PipelineData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Consume and print self data without any extra formatting.
|
||||
///
|
||||
/// This does not use the `table` command to format data, and also prints binary values and
|
||||
/// streams in their raw format without generating a hexdump first.
|
||||
///
|
||||
/// `no_newline` controls if we need to attach newline character to output.
|
||||
/// `to_stderr` controls if data is output to stderr, when the value is false, the data is output to stdout.
|
||||
pub fn print_raw(
|
||||
self,
|
||||
engine_state: &EngineState,
|
||||
no_newline: bool,
|
||||
to_stderr: bool,
|
||||
) -> Result<Option<ExitStatus>, ShellError> {
|
||||
if let PipelineData::Value(Value::Binary { val: bytes, .. }, _) = self {
|
||||
if to_stderr {
|
||||
stderr_write_all_and_flush(bytes)?;
|
||||
} else {
|
||||
stdout_write_all_and_flush(bytes)?;
|
||||
}
|
||||
Ok(None)
|
||||
} else {
|
||||
self.write_all_and_flush(engine_state, no_newline, to_stderr)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_all_and_flush(
|
||||
self,
|
||||
engine_state: &EngineState,
|
||||
|
|
Loading…
Reference in a new issue