From 7eedc0f854557e1ba28ce0cea35a4c80fe345fa2 Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Thu, 16 Oct 2025 13:27:11 +0100 Subject: [PATCH 1/2] feat(pipe-style): make output pipeable (any style) --- CHANGELOG.md | 1 + src/bin/bat/app.rs | 4 +- tests/integration_tests.rs | 77 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35df9a16..8a736c43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - `--style=changes` no longer prints a two-space indent when the file is unmodified, see issue #2710 and PR #3406 (@jyn514) - Add missing shell completions, see #3411 (@keith-hall) - Execute help/version/diagnostic commands even with invalid config/arguments present, see #3414 (@keith-hall) +- Fixed line numbers (`-n`) and style components not printing when piping output, see issue #2935 and PR #3438 (@lmmx) ## Other diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index a8e1e0db..0304516e 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -276,7 +276,9 @@ impl App { .get_one::("decorations") .map(|s| s.as_str()) == Some("always") - || self.matches.get_flag("force-colorization")), + || self.matches.get_flag("force-colorization") + || self.matches.get_flag("number") + || self.matches.contains_id("style") && !style_components.plain()), tab_width: self .matches .get_one::("tabs") diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 1748a3d0..40f0ed3a 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -378,6 +378,83 @@ fn line_range_context_very_large() { ); } +#[test] +fn piped_output_with_implicit_auto_style() { + bat() + .write_stdin("hello\nworld\n") + .assert() + .success() + .stdout("hello\nworld\n"); +} + +#[test] +fn piped_output_with_line_number_flag() { + bat() + .arg("--number") + .write_stdin("hello\nworld\n") + .assert() + .success() + .stdout(" 1 hello\n 2 world\n"); +} + +#[test] +fn piped_output_with_line_numbers_style_flag() { + bat() + .arg("--style=numbers") + .write_stdin("hello\nworld\n") + .assert() + .success() + .stdout(" 1 hello\n 2 world\n"); +} + +#[test] +#[cfg(not(target_os = "windows"))] +fn piped_output_with_line_numbers_with_header_grid_style_flag() { + bat() + .arg("--style=header,grid,numbers") + .write_stdin("hello\nworld\n") + .assert() + .success() + .stdout( + "─────┬────────────────────────────────────────────────────────────────────────── + │ STDIN +─────┼────────────────────────────────────────────────────────────────────────── + 1 │ hello + 2 │ world +─────┴────────────────────────────────────────────────────────────────────────── +", + ); +} + +#[test] +fn piped_output_with_auto_style() { + bat() + .arg("--style=auto") + .write_stdin("hello\nworld\n") + .assert() + .success() + .stdout("hello\nworld\n"); // Should be plain when piped +} + +#[test] +#[cfg(not(target_os = "windows"))] +fn piped_output_with_default_style_flag() { + bat() + .arg("--style=default") + .write_stdin("hello\nworld\n") + .assert() + .success() + .stdout( + "─────┬────────────────────────────────────────────────────────────────────────── + │ STDIN +─────┼────────────────────────────────────────────────────────────────────────── + 1 │ hello + 2 │ world +─────┴────────────────────────────────────────────────────────────────────────── +", + ); +} + #[test] fn squeeze_blank() { bat() From 200924772fa39d5405d868175b9dcf9929f476d4 Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Fri, 17 Oct 2025 10:18:58 +0100 Subject: [PATCH 2/2] docs: amend man page (style modifies cat-like piping) --- assets/manual/bat.1.in | 6 ++++-- doc/long-help.txt | 4 ++-- src/bin/bat/clap_app.rs | 7 ++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/assets/manual/bat.1.in b/assets/manual/bat.1.in index faa69d53..0be4bb63 100644 --- a/assets/manual/bat.1.in +++ b/assets/manual/bat.1.in @@ -14,7 +14,8 @@ It also communicates with git(1) to show modifications with respect to the git i Whenever the output of {{PROJECT_EXECUTABLE}} goes to a non-interactive terminal, i.e. when the output is piped into another process or into a file, {{PROJECT_EXECUTABLE}} will act as a drop-in -replacement for cat(1) and fall back to printing the plain file contents. +replacement for cat(1) and fall back to printing the plain file contents, +unless an explicit style is requested. .SH "OPTIONS" General remarks: Command-line options like '-l'/'--language' that take values can be specified as @@ -131,7 +132,8 @@ always, *never*. \fB\-\-decorations\fR .IP Specify when to use the decorations that have been specified via '\-\-style'. The -automatic mode only enables decorations if an interactive terminal is detected. Possible +automatic mode only enables decorations if an interactive terminal is detected. The +always mode will show decorations even when piping output. Possible values: *auto*, never, always. .HP \fB\-f\fR, \fB\-\-force\-colorization\fR diff --git a/doc/long-help.txt b/doc/long-help.txt index ac5ded9e..c625ffa3 100644 --- a/doc/long-help.txt +++ b/doc/long-help.txt @@ -87,8 +87,8 @@ Options: --decorations Specify when to use the decorations that have been specified via '--style'. The automatic - mode only enables decorations if an interactive terminal is detected. Possible values: - *auto*, never, always. + mode only enables decorations if an interactive terminal is detected. The always mode will + show decorations even when piping output. Possible values: *auto*, never, always. -f, --force-colorization Alias for '--decorations=always --color=always'. This is useful if the output of bat is diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index f7e86dbc..3820c284 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -299,9 +299,10 @@ pub fn build_app(interactive_output: bool) -> Command { .help("When to show the decorations (*auto*, never, always).") .long_help( "Specify when to use the decorations that have been specified \ - via '--style'. The automatic mode only enables decorations if \ - an interactive terminal is detected. Possible values: *auto*, never, always.", - ), + via '--style'. The automatic mode only enables decorations if \ + an interactive terminal is detected. The always mode will show \ + decorations even when piping output. Possible values: *auto*, never, always.", + ) ) .arg( Arg::new("force-colorization")