mirror of
https://github.com/sharkdp/bat.git
synced 2025-04-15 07:10:43 +01:00
Merge pull request #2976 from einfachIrgendwer0815/feature/binary_as_text
Allow printing binary content by treating it the same as text
This commit is contained in:
commit
2be3a14a7e
@ -9,6 +9,7 @@
|
|||||||
- Syntax highlighting for JavaScript files that start with `#!/usr/bin/env bun` #2913 (@sharunkumar)
|
- 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)
|
- `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 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
|
## Bugfixes
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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()) {
|
||||||
|
@ -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")
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
@ -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,
|
||||||
|
}
|
||||||
|
@ -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 {
|
||||||
@ -268,7 +269,8 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
.content_type
|
.content_type
|
||||||
.map_or(false, |c| c.is_binary() && !config.show_nonprintable);
|
.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);
|
&& (config.colored_output || config.strip_ansi == StripAnsiMode::Auto);
|
||||||
|
|
||||||
let (is_plain_text, highlighter_from_set) = if needs_to_match_syntax {
|
let (is_plain_text, highlighter_from_set) = if needs_to_match_syntax {
|
||||||
@ -458,7 +460,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 +544,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 +559,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 +609,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,
|
||||||
|
@ -1938,6 +1938,16 @@ fn show_all_with_unicode() {
|
|||||||
.stderr("");
|
.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]
|
#[test]
|
||||||
fn no_paging_arg() {
|
fn no_paging_arg() {
|
||||||
bat()
|
bat()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user