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.
`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
Add extensionless regression test files for tclsh, wish, and expect
shebangs so syntect bumps don't silently break first-line detection.
Move changelog entry from Features to Syntaxes per reviewer suggestion.
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
* feat(cli): add fallback syntax option
Expose a new fallback syntax CLI option so users can opt into syntax highlighting only when auto-detection fails.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* feat(syntax): apply fallback only after detection fails
Use the fallback syntax only when path and first-line detection fail, preserving existing behavior for detected files and explicit language selection.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* test(cli): cover fallback syntax behavior
Add integration coverage for fallback syntax usage, precedence with --language, and no-op behavior when syntax is already detected; update help snapshots for the new option.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* docs(changelog): document fallback syntax option
Record the new fallback syntax feature in the unreleased changelog section.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
---------
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* feat: add word wrapping mode for --wrap flag
* Run `cargo fmt` and add CHANGELOG entry
* Add word wrap tests, update manpage and shell completions
- Add integration tests for word wrapping: basic word boundary breaking,
fallback to character wrapping for long words, line numbers, and
short lines that fit without wrapping
- Update manpage to document the new 'word' wrapping mode
- Update bash, fish, zsh, and PowerShell completions with 'word' option
- Avoid unnecessary clone of `line_buf` when word wrap is disabled
* make clippy and cargo fmt happy
---------
Co-authored-by: Keith Hall <keith-hall@users.noreply.github.com>
When output is piped to a pager, the wrapping_mode logic was not checking the explicit --wrap=never flag and would always default to NoWrapping(false). This meant the -S flag was not passed to less, causing lines to wrap despite the user's explicit request.
The fix prioritizes explicit CLI flags (--wrap=never, --chop-long-lines) over the interactive_output-based logic, ensuring they are always respected.
Fixes#3587
when a configured pager (via BAT_PAGER, PAGER, or --pager) is not found,
bat now shows a warning message before falling back to stdout. this helps
users understand why their pager isn't running and makes it obvious when
there's a typo or PATH issue.
fixes issue #2904
Repurpose the existing --unbuffered/-u flag (previously a POSIX no-op)
to enable unbuffered input reading using fill_buf()/consume() instead
of read_until(b'\n'). This allows partial lines to display immediately
when piping streaming input like `tail -f` into bat.
- Add unbuffered field to Config and InputReader
- Add read_line_unbuffered() using BufRead::fill_buf()/consume()
- Add flush() to OutputHandle, called after each line in unbuffered mode
- Auto-disable line numbers in unbuffered mode to avoid partial line confusion
- Update help text, man page, and shell completions
- Add unit tests and integration tests
When the -n/--number flag is passed on the command line, bat now shows
line numbers even when piping output to another process (loop-through
mode), similar to how `cat -n` behaves.
This change detects if -n or --number was passed on the CLI (before
merging with config file and environment variables) and disables
loop-through mode in that case, allowing the InteractivePrinter to
add line numbers.
The existing behavior is preserved:
- Styles from config/env are still ignored when piping (unless --decorations=always is set)
- Only the -n flag from CLI enables line numbers in piped mode
- -p and --style options from CLI do not disable loop-through mode
Previously, setting `--style=changes` would always print a 2-space
indent, even if the file was unmodified. This changes the style to only
print an indent if there is at least one +/- git marker in the sidebar.
test(tests/examples/multiline.txt): 🚨 trim sample file to 10 lines to match new behavior
test(tests/integration_tests.rs): 🚨 adjust line ranges and expected outputs for 10-line sample; add multi-range context test