Adds a `-b` / `--number-nonblank` flag that numbers only non-blank
lines. Blank lines (those containing only the line terminator) are
printed without a number and don't advance the counter, matching
`cat -b` behaviour.
- `-b` implies `--style=numbers` (same as `-n`), but only counts
non-blank lines
- `-b` takes precedence over `-n`: both `-bn` and `-nb` behave like `-b`
- `-bp` disables numbering (plain mode wins)
- Works with files, stdin, and piped output (like `-n`)
Closes#3856.
When an ignored suffix is also a registered extension (e.g. `.txt` maps to
"Plain Text"), `get_syntax_for_file_extension` matched the raw extension
before attempting the suffix strip. As a result `--ignored-suffix .txt` had
no effect on such files and first-line/shebang detection was never reached,
so a shell script saved as `*.txt` stayed unhighlighted.
Strip ignored suffixes first and detect on the remainder; only fall back to
the raw extension when no ignored suffix applies. When a suffix is stripped
but the remainder has no syntax, return `None` so the caller can use
first-line detection. Default behavior (no `--ignored-suffix`) is unchanged.
See #2745.
`get_languages` computed `desired_width = term_width - longest - separator.len()`.
When `--terminal-width` is smaller than the longest language name (e.g. 1), this
underflows `usize`: in overflow-checked builds it panics ("attempt to subtract with
overflow"), and in release it wraps to ~usize::MAX, silently disabling the extension
line-wrapping so `--terminal-width` is ignored for `--list-languages`.
Use `saturating_sub`, mirroring the fix applied to `print_snip` in #3804 (the snip
separator had the same `term_width - ...` underflow pattern). Output at normal widths
is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`InteractivePrinter::print_snip` computes the snip separator width as
`term_width - panel_count - snip_left_count - title_count`. At `--terminal-width 1`
the panel is disabled and `title_count == 2`, so the subtraction underflows
`usize` (release has no overflow-checks, so it wraps to ~usize::MAX); `str::repeat`
then aborts with "capacity overflow" whenever a snip separator is emitted (two or
more disjoint line ranges, or a diff gap) — which the default style does.
Use `saturating_sub` for the repeat counts so they clamp to 0 instead of
underflowing. Added an integration test.
When piped input has no filename hint, bat falls back to plain text. Many
common formats can be reliably identified by shebang or magic-string in the
first line (#!/bin/bash, <?xml, {"json: ...}, etc.). Adds a first-line
pattern matcher to assets.rs.
Fixes#3697
The Drop cleanup for Preprocessed inverted the exit-status check, so bat
emitted a warning when LESSCLOSE exited successfully and stayed silent on
failure. Align the condition with the intended behavior.
When bat is built without the `git` feature, `StyleComponent::Changes`
is not available. Add `#[cfg(feature = "git")]` guard so `--diff --plain`
works in both configurations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Control characters displayed in caret notation (e.g. ^@ for NUL)
occupy 2 terminal columns, but the width calculation treated them
as 0-width. Add a char_width() helper that returns 2 for control
characters, fixing incorrect line wrapping with --binary=as-text.
Fixes#3631