In UTF-16BE a newline is 00 0A, so the initial read_until(b'\n') usually
already ends exactly at the end of line 1. The BE branch then always called
read_utf16_line, which read on to the next newline, merging lines 1 and 2.
Only keep reading when the first read did not end on a complete 00 0A.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VVn4SeAXPsUajXT2rtHQfo
The main output path has exited with status 0 on EPIPE since #232, but
auxiliary outputs still used println!/print!/io::stdout().flush().unwrap()
and panicked (exit code 101) when the reader of a piped stdout went away
early, e.g. 'bat --completion bash | head -n0'.
Route them through the existing convention instead: write!/writeln! to
io::stdout() and '?' so that Error::Io(BrokenPipe) reaches
default_error_handler, which exits with status 0. This covers
--completion, --config-file, --diagnostic (bugreport's print() becomes
format() + writeln!), --generate-config-file, the 'cache' subcommand
progress messages, the OSC title sequence of --set-terminal-title, and
the 'built without feature' notices.
Closes#4034
The `Attributes` ANSI style tracker in `src/vscreen.rs` declares, initializes,
clears (in `sgr_reset`), and re-emits (in `Display`) a `strike` field
documented as `ON: ^[9m / OFF: ^[29m`, but `update_with_sgr()` had no match
arm for SGR 9 (set strikethrough) or 29 (clear strikethrough). As a result
`strike` was only ever cleared, never set.
Because bat re-applies the tracked input ANSI style before each highlighted
text run (nu_ansi_term appends a full reset after every token), attributes
that are tracked — bold, dim, italic, underline — survive across tokens,
while strikethrough was silently dropped after the first token. This path is
active by default (`--strip-ansi`/`--sanitize` default to `never`).
Add the missing `9` and `29` arms, mirroring the sibling underline (4/24) and
italic (3/23) arms, so strikethrough is tracked and re-emitted like every
other supported attribute.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bat prepends the arguments from its config file to the command line, so a
user who has `--show-all` in their config and also types `-A` passes the
flag twice, and clap rejects that with "the argument '--show-all' cannot be
used multiple times" and exit code 2. The file is never displayed.
`--plain`, `--number`, `--number-nonblank`, `--force-colorization` and
`--no-paging` already avoid this by overriding themselves. The same is now
done for the eight remaining flags that affect how a file is displayed:
--show-all, --diff, --chop-long-lines, --squeeze-blank, --unbuffered,
--quiet-empty, --no-custom-assets and --set-terminal-title.
Repeating a flag produces byte-identical output to giving it once, and
--show-all still conflicts with --language as before.
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.
`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.
Every shell completion script (bash, zsh, fish, PowerShell) shells out
to bat to enumerate languages/themes for tab completion candidates. If
the user has wired bat into LESSOPEN (e.g. LESSOPEN='|-bat -f -pp %s'),
bat's normal pager auto-detection can engage when stdout looks like a
terminal at completion time and reflect ANSI escape sequences back into
the candidate list. The result is the issue's reproducer: tab completion
expands 'Per' to '\033[38;2;248;248;242mPerl' instead of 'Perl'.
The list-languages/list-themes calls are always meant to be machine-
readable, so they should never page. Pass --no-paging explicitly to
every bat invocation inside the four completion files. The flag is the
public alias for --paging=never (already documented in bat --help) and
is the same form completion scripts elsewhere in the codebase use.
Touches the four completion files only; no production code changes.
The previous awk script in `bat.zsh.in` split each line of
`bat --list-languages` on `:` or `,` and emitted every field as a
completion candidate, including the second column. That column lists
file matchers, which can be plain extensions (`rs`), globs (`*.rs`),
absolute paths (`/etc/profile`), or filenames (`Containerfile`). None
of those parse as `-l` arguments, so completing them produces
`unknown syntax` errors.
Switch to splitting on `:` only and emit the language name as the
completion value with the file-matcher list as its description, which
matches the bash completion's behavior.
Closes#3735.