Add option --binary

`--binary` allows to specify how to deal with binary content. Current
options are not printing anything or treating the binary data as text.
This commit is contained in:
einfachIrgendwer0815 2024-05-31 18:20:16 +02:00
parent b662fec214
commit 7f089ead62
No known key found for this signature in database
GPG Key ID: 58D55E5F117DA873
8 changed files with 63 additions and 6 deletions

View File

@ -20,6 +20,13 @@ Options:
* unicode (␇, ␊, ␀, ..) * unicode (␇, ␊, ␀, ..)
* caret (^G, ^J, ^@, ..) * 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... -p, --plain...
Only show plain style, no decorations. This is an alias for '--style=plain'. When '-p' is 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 used twice ('-pp'), it also disables automatic paging (alias for '--style=plain

View File

@ -11,6 +11,8 @@ Options:
Show non-printable characters (space, tab, newline, ..). Show non-printable characters (space, tab, newline, ..).
--nonprintable-notation <notation> --nonprintable-notation <notation>
Set notation for non-printable characters. Set notation for non-printable characters.
--binary <behavior>
How to treat binary content. (default: no-printing)
-p, --plain... -p, --plain...
Show plain style (alias for '--style=plain'). Show plain style (alias for '--style=plain').
-l, --language <language> -l, --language <language>

View File

@ -9,6 +9,7 @@ use crate::{
config::{get_args_from_config_file, get_args_from_env_opts_var, get_args_from_env_vars}, config::{get_args_from_config_file, get_args_from_env_opts_var, get_args_from_env_vars},
}; };
use bat::style::StyleComponentList; use bat::style::StyleComponentList;
use bat::BinaryBehavior;
use bat::StripAnsiMode; use bat::StripAnsiMode;
use clap::ArgMatches; use clap::ArgMatches;
@ -193,6 +194,11 @@ impl App {
Some("caret") => NonprintableNotation::Caret, Some("caret") => NonprintableNotation::Caret,
_ => unreachable!("other values for --nonprintable-notation are not allowed"), _ => 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() { wrapping_mode: if self.interactive_output || maybe_term_width.is_some() {
if !self.matches.get_flag("chop-long-lines") { if !self.matches.get_flag("chop-long-lines") {
match self.matches.get_one::<String>("wrap").map(|s| s.as_str()) { match self.matches.get_one::<String>("wrap").map(|s| s.as_str()) {

View File

@ -77,6 +77,22 @@ pub fn build_app(interactive_output: bool) -> Command {
* caret (^G, ^J, ^@, ..)", * 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(
Arg::new("plain") Arg::new("plain")
.overrides_with("plain") .overrides_with("plain")

View File

@ -1,5 +1,5 @@
use crate::line_range::{HighlightedLineRanges, LineRanges}; use crate::line_range::{HighlightedLineRanges, LineRanges};
use crate::nonprintable_notation::NonprintableNotation; use crate::nonprintable_notation::{BinaryBehavior, NonprintableNotation};
#[cfg(feature = "paging")] #[cfg(feature = "paging")]
use crate::paging::PagingMode; use crate::paging::PagingMode;
use crate::style::StyleComponents; use crate::style::StyleComponents;
@ -44,6 +44,9 @@ pub struct Config<'a> {
/// The configured notation for non-printable characters /// The configured notation for non-printable characters
pub nonprintable_notation: NonprintableNotation, pub nonprintable_notation: NonprintableNotation,
/// How to treat binary content
pub binary: BinaryBehavior,
/// The character width of the terminal /// The character width of the terminal
pub term_width: usize, pub term_width: usize,

View File

@ -52,7 +52,7 @@ mod terminal;
mod vscreen; mod vscreen;
pub(crate) mod wrapping; pub(crate) mod wrapping;
pub use nonprintable_notation::NonprintableNotation; pub use nonprintable_notation::{BinaryBehavior, NonprintableNotation};
pub use preprocessor::StripAnsiMode; pub use preprocessor::StripAnsiMode;
pub use pretty_printer::{Input, PrettyPrinter, Syntax}; pub use pretty_printer::{Input, PrettyPrinter, Syntax};
pub use syntax_mapping::{MappingTarget, SyntaxMapping}; pub use syntax_mapping::{MappingTarget, SyntaxMapping};

View File

@ -10,3 +10,15 @@ pub enum NonprintableNotation {
#[default] #[default]
Unicode, 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,
}

View File

@ -35,6 +35,7 @@ use crate::style::StyleComponent;
use crate::terminal::{as_terminal_escaped, to_ansi_color}; use crate::terminal::{as_terminal_escaped, to_ansi_color};
use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator}; use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator};
use crate::wrapping::WrappingMode; use crate::wrapping::WrappingMode;
use crate::BinaryBehavior;
use crate::StripAnsiMode; use crate::StripAnsiMode;
const ANSI_UNDERLINE_ENABLE: EscapeSequence = EscapeSequence::CSI { const ANSI_UNDERLINE_ENABLE: EscapeSequence = EscapeSequence::CSI {
@ -458,7 +459,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
} }
if !self.config.style_components.header() { 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!( writeln!(
handle, handle,
"{}: Binary content from {} will not be printed to the terminal \ "{}: Binary content from {} will not be printed to the terminal \
@ -539,7 +543,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
})?; })?;
if self.config.style_components.grid() { 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, '┼')?; self.print_horizontal_line(handle, '┼')?;
} else { } else {
self.print_horizontal_line(handle, '┴')?; self.print_horizontal_line(handle, '┴')?;
@ -551,7 +558,9 @@ impl<'a> Printer for InteractivePrinter<'a> {
fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> { fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
if self.config.style_components.grid() 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, '┴') self.print_horizontal_line(handle, '┴')
} else { } else {
@ -599,7 +608,9 @@ impl<'a> Printer for InteractivePrinter<'a> {
.into() .into()
} else { } else {
let mut line = match self.content_type { let mut line = match self.content_type {
Some(ContentType::BINARY) | None => { Some(ContentType::BINARY) | None
if !matches!(self.config.binary, BinaryBehavior::AsText) =>
{
return Ok(()); return Ok(());
} }
Some(ContentType::UTF_16LE) => UTF_16LE.decode_with_bom_removal(line_buffer).0, Some(ContentType::UTF_16LE) => UTF_16LE.decode_with_bom_removal(line_buffer).0,