mirror of
https://github.com/sharkdp/bat.git
synced 2024-11-21 23:33:26 +01:00
Add --strip-ansi=auto
option
When using `auto`, escape sequences will be stripped unless printing plain text.
This commit is contained in:
parent
70ff93d238
commit
9e8176b1c6
@ -123,8 +123,9 @@ Options:
|
|||||||
Set the maximum number of consecutive empty lines to be printed.
|
Set the maximum number of consecutive empty lines to be printed.
|
||||||
|
|
||||||
--strip-ansi <when>
|
--strip-ansi <when>
|
||||||
Specify when to strip ANSI escape sequences from the input. Possible values: always,
|
Specify when to strip ANSI escape sequences from the input. The automatic mode will remove
|
||||||
*never*.
|
escape sequences unless the syntax highlighting language is plain text. Possible values:
|
||||||
|
auto, always, *never*.
|
||||||
|
|
||||||
--style <components>
|
--style <components>
|
||||||
Configure which elements (line numbers, file headers, grid borders, Git modifications, ..)
|
Configure which elements (line numbers, file headers, grid borders, Git modifications, ..)
|
||||||
|
@ -250,6 +250,7 @@ impl App {
|
|||||||
{
|
{
|
||||||
Some("never") => StripAnsiMode::Never,
|
Some("never") => StripAnsiMode::Never,
|
||||||
Some("always") => StripAnsiMode::Always,
|
Some("always") => StripAnsiMode::Always,
|
||||||
|
Some("auto") => StripAnsiMode::Auto,
|
||||||
_ => unreachable!("other values for --strip-ansi are not allowed"),
|
_ => unreachable!("other values for --strip-ansi are not allowed"),
|
||||||
},
|
},
|
||||||
theme: self
|
theme: self
|
||||||
|
@ -407,11 +407,13 @@ pub fn build_app(interactive_output: bool) -> Command {
|
|||||||
.long("strip-ansi")
|
.long("strip-ansi")
|
||||||
.overrides_with("strip-ansi")
|
.overrides_with("strip-ansi")
|
||||||
.value_name("when")
|
.value_name("when")
|
||||||
.value_parser(["always", "never"])
|
.value_parser(["auto", "always", "never"])
|
||||||
.default_value("never")
|
.default_value("never")
|
||||||
.hide_default_value(true)
|
.hide_default_value(true)
|
||||||
.help("Strip colors from the input (always, *never*)")
|
.help("Strip colors from the input (auto, always, *never*)")
|
||||||
.long_help("Specify when to strip ANSI escape sequences from the input. Possible values: always, *never*.")
|
.long_help("Specify when to strip ANSI escape sequences from the input. \
|
||||||
|
The automatic mode will remove escape sequences unless the syntax highlighting \
|
||||||
|
language is plain text. Possible values: auto, always, *never*.")
|
||||||
.hide_short_help(true)
|
.hide_short_help(true)
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -154,6 +154,7 @@ pub enum StripAnsiMode {
|
|||||||
#[default]
|
#[default]
|
||||||
Never,
|
Never,
|
||||||
Always,
|
Always,
|
||||||
|
Auto,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -268,26 +268,40 @@ 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 highlighter_from_set = if is_printing_binary || !config.colored_output {
|
let needs_to_match_syntax = !is_printing_binary
|
||||||
None
|
&& (config.colored_output || config.strip_ansi == StripAnsiMode::Auto);
|
||||||
} else {
|
|
||||||
// Determine the type of syntax for highlighting
|
|
||||||
let syntax_in_set =
|
|
||||||
match assets.get_syntax(config.language, input, &config.syntax_mapping) {
|
|
||||||
Ok(syntax_in_set) => syntax_in_set,
|
|
||||||
Err(Error::UndetectedSyntax(_)) => assets
|
|
||||||
.find_syntax_by_name("Plain Text")?
|
|
||||||
.expect("A plain text syntax is available"),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(HighlighterFromSet::new(syntax_in_set, theme))
|
let (is_plain_text, highlighter_from_set) = if needs_to_match_syntax {
|
||||||
|
// Determine the type of syntax for highlighting
|
||||||
|
const PLAIN_TEXT_SYNTAX: &str = "Plain Text";
|
||||||
|
match assets.get_syntax(config.language, input, &config.syntax_mapping) {
|
||||||
|
Ok(syntax_in_set) => (
|
||||||
|
syntax_in_set.syntax.name == PLAIN_TEXT_SYNTAX,
|
||||||
|
Some(HighlighterFromSet::new(syntax_in_set, theme)),
|
||||||
|
),
|
||||||
|
|
||||||
|
Err(Error::UndetectedSyntax(_)) => (
|
||||||
|
true,
|
||||||
|
Some(
|
||||||
|
assets
|
||||||
|
.find_syntax_by_name(PLAIN_TEXT_SYNTAX)?
|
||||||
|
.map(|s| HighlighterFromSet::new(s, theme))
|
||||||
|
.expect("A plain text syntax is available"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(false, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine when to strip ANSI sequences
|
// Determine when to strip ANSI sequences
|
||||||
let strip_ansi = match config.strip_ansi {
|
let strip_ansi = match config.strip_ansi {
|
||||||
_ if config.show_nonprintable => false,
|
_ if config.show_nonprintable => false,
|
||||||
StripAnsiMode::Always => true,
|
StripAnsiMode::Always => true,
|
||||||
|
StripAnsiMode::Auto if is_plain_text => false, // Plain text may already contain escape sequences.
|
||||||
|
StripAnsiMode::Auto => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2740,3 +2740,73 @@ fn strip_ansi_does_not_strip_when_show_nonprintable() {
|
|||||||
|
|
||||||
assert!(output.contains("␛"))
|
assert!(output.contains("␛"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strip_ansi_auto_strips_ansi_when_detected_syntax_by_filename() {
|
||||||
|
bat()
|
||||||
|
.arg("--style=plain")
|
||||||
|
.arg("--decorations=always")
|
||||||
|
.arg("--color=never")
|
||||||
|
.arg("--strip-ansi=auto")
|
||||||
|
.arg("--file-name=test.rs")
|
||||||
|
.write_stdin("fn \x1B[33mYellow\x1B[m() -> () {}")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout("fn Yellow() -> () {}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strip_ansi_auto_strips_ansi_when_provided_syntax_by_option() {
|
||||||
|
bat()
|
||||||
|
.arg("--style=plain")
|
||||||
|
.arg("--decorations=always")
|
||||||
|
.arg("--color=never")
|
||||||
|
.arg("--strip-ansi=auto")
|
||||||
|
.arg("--language=rust")
|
||||||
|
.write_stdin("fn \x1B[33mYellow\x1B[m() -> () {}")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout("fn Yellow() -> () {}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strip_ansi_auto_does_not_strip_when_plain_text_by_filename() {
|
||||||
|
let output = String::from_utf8(
|
||||||
|
bat()
|
||||||
|
.arg("--style=plain")
|
||||||
|
.arg("--decorations=always")
|
||||||
|
.arg("--color=never")
|
||||||
|
.arg("--strip-ansi=auto")
|
||||||
|
.arg("--file-name=ansi.txt")
|
||||||
|
.write_stdin("\x1B[33mYellow\x1B[m")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.get_output()
|
||||||
|
.stdout
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
.expect("valid utf8");
|
||||||
|
|
||||||
|
assert!(output.contains("\x1B[33mYellow"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strip_ansi_auto_does_not_strip_ansi_when_plain_text_by_option() {
|
||||||
|
let output = String::from_utf8(
|
||||||
|
bat()
|
||||||
|
.arg("--style=plain")
|
||||||
|
.arg("--decorations=always")
|
||||||
|
.arg("--color=never")
|
||||||
|
.arg("--strip-ansi=auto")
|
||||||
|
.arg("--language=txt")
|
||||||
|
.write_stdin("\x1B[33mYellow\x1B[m")
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.get_output()
|
||||||
|
.stdout
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
.expect("valid utf8");
|
||||||
|
|
||||||
|
assert!(output.contains("\x1B[33mYellow"))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user