Skip to content

Commit

Permalink
Merge pull request #2976 from einfachIrgendwer0815/feature/binary_as_…
Browse files Browse the repository at this point in the history
…text

Allow printing binary content by treating it the same as text
  • Loading branch information
keith-hall authored Oct 30, 2024
2 parents 649fb05 + 8d82402 commit 2be3a14
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Syntax highlighting for JavaScript files that start with `#!/usr/bin/env bun` #2913 (@sharunkumar)
- `bat --strip-ansi={never,always,auto}` to remove ANSI escape sequences from bat's input, see #2999 (@eth-p)
- Add or remove individual style components without replacing all styles #2929 (@eth-p)
- Add option `--binary=as-text` for printing binary content, see issue #2974 and PR #2976 (@einfachIrgendwer0815)

## Bugfixes

Expand Down
7 changes: 7 additions & 0 deletions doc/long-help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ Options:
* unicode (␇, ␊, ␀, ..)
* caret (^G, ^J, ^@, ..)

--binary <behavior>
How to treat binary content. (default: no-printing)

Possible values:
* no-printing: do not print any binary content
* as-text: treat binary content as normal text

-p, --plain...
Only show plain style, no decorations. This is an alias for '--style=plain'. When '-p' is
used twice ('-pp'), it also disables automatic paging (alias for '--style=plain
Expand Down
2 changes: 2 additions & 0 deletions doc/short-help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Options:
Show non-printable characters (space, tab, newline, ..).
--nonprintable-notation <notation>
Set notation for non-printable characters.
--binary <behavior>
How to treat binary content. (default: no-printing)
-p, --plain...
Show plain style (alias for '--style=plain').
-l, --language <language>
Expand Down
6 changes: 6 additions & 0 deletions src/bin/bat/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
config::{get_args_from_config_file, get_args_from_env_opts_var, get_args_from_env_vars},
};
use bat::style::StyleComponentList;
use bat::BinaryBehavior;
use bat::StripAnsiMode;
use clap::ArgMatches;

Expand Down Expand Up @@ -193,6 +194,11 @@ impl App {
Some("caret") => NonprintableNotation::Caret,
_ => unreachable!("other values for --nonprintable-notation are not allowed"),
},
binary: match self.matches.get_one::<String>("binary").map(|s| s.as_str()) {
Some("as-text") => BinaryBehavior::AsText,
Some("no-printing") => BinaryBehavior::NoPrinting,
_ => unreachable!("other values for --binary are not allowed"),
},
wrapping_mode: if self.interactive_output || maybe_term_width.is_some() {
if !self.matches.get_flag("chop-long-lines") {
match self.matches.get_one::<String>("wrap").map(|s| s.as_str()) {
Expand Down
16 changes: 16 additions & 0 deletions src/bin/bat/clap_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ pub fn build_app(interactive_output: bool) -> Command {
* caret (^G, ^J, ^@, ..)",
),
)
.arg(
Arg::new("binary")
.long("binary")
.action(ArgAction::Set)
.default_value("no-printing")
.value_parser(["no-printing", "as-text"])
.value_name("behavior")
.hide_default_value(true)
.help("How to treat binary content. (default: no-printing)")
.long_help(
"How to treat binary content. (default: no-printing)\n\n\
Possible values:\n \
* no-printing: do not print any binary content\n \
* as-text: treat binary content as normal text",
),
)
.arg(
Arg::new("plain")
.overrides_with("plain")
Expand Down
5 changes: 4 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::line_range::{HighlightedLineRanges, LineRanges};
use crate::nonprintable_notation::NonprintableNotation;
use crate::nonprintable_notation::{BinaryBehavior, NonprintableNotation};
#[cfg(feature = "paging")]
use crate::paging::PagingMode;
use crate::style::StyleComponents;
Expand Down Expand Up @@ -44,6 +44,9 @@ pub struct Config<'a> {
/// The configured notation for non-printable characters
pub nonprintable_notation: NonprintableNotation,

/// How to treat binary content
pub binary: BinaryBehavior,

/// The character width of the terminal
pub term_width: usize,

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ mod terminal;
mod vscreen;
pub(crate) mod wrapping;

pub use nonprintable_notation::NonprintableNotation;
pub use nonprintable_notation::{BinaryBehavior, NonprintableNotation};
pub use preprocessor::StripAnsiMode;
pub use pretty_printer::{Input, PrettyPrinter, Syntax};
pub use syntax_mapping::{MappingTarget, SyntaxMapping};
Expand Down
12 changes: 12 additions & 0 deletions src/nonprintable_notation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ pub enum NonprintableNotation {
#[default]
Unicode,
}

/// How to treat binary content
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum BinaryBehavior {
/// Do not print any binary content
#[default]
NoPrinting,

/// Treat binary content as normal text
AsText,
}
22 changes: 17 additions & 5 deletions src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use crate::style::StyleComponent;
use crate::terminal::{as_terminal_escaped, to_ansi_color};
use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator};
use crate::wrapping::WrappingMode;
use crate::BinaryBehavior;
use crate::StripAnsiMode;

const ANSI_UNDERLINE_ENABLE: EscapeSequence = EscapeSequence::CSI {
Expand Down Expand Up @@ -268,7 +269,8 @@ impl<'a> InteractivePrinter<'a> {
.content_type
.map_or(false, |c| c.is_binary() && !config.show_nonprintable);

let needs_to_match_syntax = !is_printing_binary
let needs_to_match_syntax = (!is_printing_binary
|| matches!(config.binary, BinaryBehavior::AsText))
&& (config.colored_output || config.strip_ansi == StripAnsiMode::Auto);

let (is_plain_text, highlighter_from_set) = if needs_to_match_syntax {
Expand Down Expand Up @@ -458,7 +460,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
}

if !self.config.style_components.header() {
if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable {
if Some(ContentType::BINARY) == self.content_type
&& !self.config.show_nonprintable
&& !matches!(self.config.binary, BinaryBehavior::AsText)
{
writeln!(
handle,
"{}: Binary content from {} will not be printed to the terminal \
Expand Down Expand Up @@ -539,7 +544,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
})?;

if self.config.style_components.grid() {
if self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable {
if self.content_type.map_or(false, |c| c.is_text())
|| self.config.show_nonprintable
|| matches!(self.config.binary, BinaryBehavior::AsText)
{
self.print_horizontal_line(handle, '┼')?;
} else {
self.print_horizontal_line(handle, '┴')?;
Expand All @@ -551,7 +559,9 @@ impl<'a> Printer for InteractivePrinter<'a> {

fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
if self.config.style_components.grid()
&& (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable)
&& (self.content_type.map_or(false, |c| c.is_text())
|| self.config.show_nonprintable
|| matches!(self.config.binary, BinaryBehavior::AsText))
{
self.print_horizontal_line(handle, '┴')
} else {
Expand Down Expand Up @@ -599,7 +609,9 @@ impl<'a> Printer for InteractivePrinter<'a> {
.into()
} else {
let mut line = match self.content_type {
Some(ContentType::BINARY) | None => {
Some(ContentType::BINARY) | None
if !matches!(self.config.binary, BinaryBehavior::AsText) =>
{
return Ok(());
}
Some(ContentType::UTF_16LE) => UTF_16LE.decode_with_bom_removal(line_buffer).0,
Expand Down
10 changes: 10 additions & 0 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1938,6 +1938,16 @@ fn show_all_with_unicode() {
.stderr("");
}

#[test]
fn binary_as_text() {
bat()
.arg("--binary=as-text")
.arg("control_characters.txt")
.assert()
.stdout("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F")
.stderr("");
}

#[test]
fn no_paging_arg() {
bat()
Expand Down

0 comments on commit 2be3a14

Please sign in to comment.