Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

bat Administration & Developer Guide

Generated May 2026 from sharkdp/bat at f57c1b6

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Comprehensive architecture, configuration, deployment, and development reference for bat -- a cat(1) clone with syntax highlighting, git integration, and automatic paging. Written in Rust, dual-licensed under MIT/Apache-2.0.


Executive Summary

bat is a mature, production-quality command-line tool and Rust library that replaces cat(1) with syntax-highlighted, git-aware file display. The codebase is approximately 876 files across 19 significant modules, built with Rust edition 2021 and a minimum supported Rust version (MSRV) of 1.88.

Key Metrics

Metric Value
Version 0.26.1
Language Rust (edition 2021)
MSRV 1.88
License MIT OR Apache-2.0
Source files ~876
Core modules 19 (src/)
Built-in themes 27
Dependencies ~40 direct
Cargo features 10
Public API PrettyPrinter, Input, SyntaxMapping, MappingTarget

Repository Structure

bat/
  src/                    Core library and binary
    assets.rs             Syntax/theme loading, caching, detection
    config.rs             Config struct (25+ fields), env resolution
    controller.rs         Main execution pipeline, pager orchestration
    decorations.rs        Line numbers, git markers, grid rendering
    diff.rs               Git diff integration (via git2)
    error.rs              Error types and handling
    input.rs              File/stdin/reader input, encoding detection
    less.rs               Less version detection
    lessopen.rs           LESSOPEN/LESSCLOSE preprocessing
    lib.rs                Public API exports
    line_range.rs          Line range parsing and evaluation
    macros.rs             bat_warning! macro
    nonprintable_notation.rs  Non-printable character display modes
    output.rs             Output type management (pager/stdout/builtin)
    pager.rs              Pager selection, source tracking, kind detection
    paging.rs             PagingMode enum
    preprocessor.rs       Tab expansion, ANSI stripping, overstrike removal
    pretty_printer.rs     Public library API (PrettyPrinter)
    printer.rs            InteractivePrinter (core rendering)
    style.rs              StyleComponent parsing and resolution
    syntax_mapping.rs     File-to-syntax mapping (glob patterns)
    syntax_mapping/
      ignored_suffixes.rs Suffix stripping for syntax detection
    terminal.rs           Color conversion (syntect -> nu_ansi_term)
    theme.rs              Theme resolution, color scheme detection
    vscreen.rs            Virtual screen, ANSI escape sequence parsing
    wrapping.rs           WrappingMode enum
  examples/               7 Rust examples demonstrating PrettyPrinter API
  tests/                  Integration tests, snapshot tests, syntax tests
  assets/                 Syntax definitions, themes, completions, man page
    completions/          Shell completions (bash, zsh, fish, PowerShell)
    manual/               Man page source
    syntaxes/             Sublime Text .sublime-syntax files
    themes/               .tmTheme theme files
  doc/                    Documentation, translated READMEs

Architecture

System Architecture Overview

                    ┌─────────────┐
                    │   CLI/API   │
                    │  (clap 4.x) │
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │   Config    │
                    │  (25+ fields)│
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
       ┌──────▼──────┐ ┌──▼───┐ ┌──────▼──────┐
       │HighlightingAssets│ │Input│ │ SyntaxMapping│
       │(syntect cache)│ │     │ │(glob→syntax)│
       └──────┬──────┘ └──┬───┘ └──────┬──────┘
              │            │            │
              └────────────┼────────────┘
                           │
                    ┌──────▼──────┐
                    │ Controller  │
                    │(orchestrate)│
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
       ┌──────▼──────┐ ┌──▼────────┐ ┌─▼──────┐
       │InteractivePrinter│ │Decorations│ │OutputType│
       │(render lines)│ │(sidebar)  │ │(pager) │
       └─────────────┘ └───────────┘ └────────┘

Core Components

Config (src/config.rs)

The central configuration struct that drives all behavior. All CLI flags, environment variables, and config file settings resolve into this struct.

pub struct Config<'a> {
    pub language: Option<&'a str>,
    pub show_nonprintable: bool,
    pub wrapping_mode: WrappingMode,
    pub colored_output: bool,
    pub true_color: bool,
    pub term_width: usize,
    pub tab_width: usize,
    pub theme: String,
    pub style_components: StyleComponents,
    pub pager: Option<&'a str>,
    pub use_italic_text: bool,
    pub visible_lines: VisibleLines,
    pub highlighted_lines: HighlightedLineRanges,
    pub syntax_mapping: SyntaxMapping<'a>,
    pub paging_mode: PagingMode,
    pub strip_ansi: StripAnsiMode,
    pub squeeze_empty_lines: Option<usize>,
    // ... additional fields
}

The diff_mode() method returns true when the --diff flag is active.

Note

Config is lifetime-bound ('a) because it borrows string references from the CLI argument parser and syntax mapping data.

HighlightingAssets (src/assets.rs)

Manages syntax definitions and themes. Two loading modes:

  1. Binary (compiled-in) -- HighlightingAssets::from_binary() loads the bundled, serialized asset data. This is the default for normal operation.
  2. Cache (user-customized) -- HighlightingAssets::from_cache(path) loads from a user-built cache directory containing custom syntaxes and themes.

Key methods:

Method Purpose
get_syntax_set() Returns the compiled SyntaxSet
syntaxes() Returns all available syntax references
themes() Iterator over available theme names
get_theme(name) Returns a specific theme
set_fallback_theme(theme) Sets the fallback theme for unknown names
get_acknowledgements() Returns bundled license text

Syntax detection order (implemented in assets.rs):

  1. User-defined --map-syntax glob mappings
  2. Exact file name match
  3. Hidden file extension matching (e.g., .bashrc)
  4. File extension
  5. First-line content analysis (shebangs, modelines)

Controller (src/controller.rs)

The top-level orchestrator. Controller::new(config, assets) creates the execution context. The controller:

  1. Resolves syntax for each input
  2. Creates the output type (pager or stdout)
  3. Instantiates the InteractivePrinter with decorations
  4. Iterates through input lines, applying highlighting and decorations
  5. Manages pager lifecycle

Input (src/input.rs)

Represents a single input source with metadata.

pub struct Input<'a> {
    kind: InputKind<'a>,
    metadata: InputMetadata,
    description: InputDescription,
}

Input sources:

Method Source
Input::ordinary_file(path) File on disk
Input::stdin() Standard input
Input::from_reader(reader) Custom Read implementation

The InputDescription struct holds the display name, kind (e.g., "File"), title, and summary for the header decoration.

Encoding detection: bat detects UTF-16 (BOM-based) and handles the conversion to UTF-8 internally. It also detects ZIP files by magic bytes and refuses to display them.

SyntaxMapping (src/syntax_mapping.rs)

Maps file names/paths to syntax definitions using glob patterns.

pub struct SyntaxMapping<'a> {
    mappings: Vec<(GlobMatcher, MappingTarget<'a>)>,
    // ...
}

MappingTarget variants:

  • MapTo(syntax_name) -- Use the named syntax
  • MapToUnknown -- Force plain text
  • MapExtensionToUnknown -- Ignore file extension, use plain text

The IgnoredSuffixes sub-module (syntax_mapping/ignored_suffixes.rs) strips known suffixes (e.g., .bak, .orig) before syntax detection, so file.rs.bak is detected as Rust.

Output (src/output.rs)

Three output types:

Variant Description
OutputType::Pager(Child) External pager process (e.g., less)
OutputType::BuiltinPager(BuiltinPager) Built-in pager (via minus crate)
OutputType::Stdout Direct stdout

The BuiltinPager uses minus::dynamic_paging() on a background thread. It registers Home/End key bindings for navigation.

OutputHandle abstracts over io::Write and fmt::Write to support both external pagers (byte-oriented) and the built-in pager (string-oriented).

Pager Selection (src/pager.rs)

Priority chain for pager resolution:

--pager / config file  →  PagerSource::Config
BAT_PAGER env var      →  PagerSource::EnvVarBatPager
PAGER env var          →  PagerSource::EnvVarPager
"less" (default)       →  PagerSource::Default

Known pager kinds:

PagerKind Behavior
Less Gets automatic -R, -F, -K flags when from PAGER/default
More Silently replaced with less when from PAGER
Most Silently replaced with less when from PAGER
Bat Error (InvalidPagerValueBat) if from BAT_PAGER/--pager; replaced with less if from PAGER
Builtin Uses the internal minus-based pager
Unknown Used as-is with user-provided arguments

Important

When the pager is less and comes from PAGER (not BAT_PAGER), bat replaces the user's arguments with its own defaults. This is intentional: the generic PAGER variable often contains flags incompatible with ANSI colors. BAT_PAGER arguments are always preserved.

Less Version Detection (src/less.rs)

bat detects the less version to adjust behavior:

Version Behavior
< 530 Adds --no-init to fix --quit-if-one-screen bug
>= 530 (Unix) Omits --no-init (enables mouse wheel)
>= 558 (Windows) Omits --no-init
BusyBox Omits -K (not supported)

Detection via less --version output parsing.

Preprocessor (src/preprocessor.rs)

Three preprocessing operations:

  1. Tab expansion (expand_tabs) -- Converts tabs to spaces respecting tab stops. Handles ANSI escape sequences correctly (cursor position is not affected by escapes).
  2. ANSI stripping (strip_ansi) -- Removes ANSI escape sequences from input.
  3. Overstrike removal (strip_overstrike) -- Strips man-page-style bold (X\x08X) and underline (_\x08X) formatting.

The StripAnsiMode enum controls when ANSI stripping occurs: Never, Always, or Auto (strip only when input is not plain text).

Virtual Screen (src/vscreen.rs)

Parses and tracks ANSI escape sequences for correct terminal state management. Two tracker types:

  • EscapeSequenceTracker -- Tracks basic state across escape sequences
  • EscapeSequenceOffsetsIterator -- Zero-allocation parser that yields offset ranges for text vs. escape sequence segments

LESSOPEN Preprocessing (src/lessopen.rs)

Note

Only available when the lessopen cargo feature is enabled (included in default features).

Implements the same LESSOPEN/LESSCLOSE protocol as less:

LESSOPEN Prefix Mode Behavior
(none) TempFile Preprocessor writes output to a temp file
| PipedIgnoreExitCode Output piped; falls back to original if empty AND non-zero exit
|| Piped Output piped; falls back to original only if empty
- prefix stdin processing Also preprocesses stdin input

The Preprocessed struct implements Drop to run LESSCLOSE cleanup on deallocation.

Warning

When the pager is less and LESSOPEN is enabled, bat passes --no-lessopen to less to prevent double-preprocessing.

Decorations (src/decorations.rs)

Sidebar decorations are implemented as trait objects that produce formatted output for each line:

  • LineNumberDecoration -- Renders line numbers
  • GridBorderDecoration -- Renders vertical grid lines
  • GitChangeDecoration -- Renders +, ~, - markers from git diff data
  • SnipDecoration -- Renders ... markers between non-contiguous line ranges

Diff Integration (src/diff.rs)

Uses git2 (libgit2 bindings) to compute line-level changes:

pub fn get_git_diff(filename: &Path) -> Option<LineChanges>

Returns a HashMap<usize, LineChange> mapping line numbers to change types. Only available when the git cargo feature is enabled.

Theme Resolution (src/theme.rs)

The theme() function resolves the active theme:

pub fn theme(options: ThemeOptions) -> ThemeResult

ThemeOptions includes:

  • theme -- User-requested theme name (may be "auto")
  • color_scheme -- Detected terminal color scheme (dark/light/unknown)

When theme is "auto" or references a dark/light variant, the function uses terminal-colorsaurus to detect the terminal background color and selects an appropriate theme.

Style Components (src/style.rs)

StyleComponents is a set-based container for active visual components:

pub struct StyleComponents(pub HashSet<StyleComponent>);

Parsing supports:

  • Comma-separated component names
  • Negation with - prefix (e.g., default,-grid)
  • Meta-components that expand to multiple components (full, default, auto, header)
  • Multiple --style arguments that merge (later values take precedence)

Requirements

Build Requirements

Requirement Version
Rust >= 1.88
Cargo (bundled with Rust)
C compiler Required for libgit2 (unless vendored-libgit2)
pkg-config Linux: for finding system libgit2
cmake When building vendored libgit2

Runtime Requirements

Requirement Required Notes
Terminal Yes Any terminal supporting ANSI escape sequences
less Recommended Default pager; bat works without it (falls back to stdout)
git No Only needed for git2 feature at compile time
Visual C++ Runtime Windows only Required on Windows
COLORTERM env Recommended Set to truecolor or 24bit for best color output

Supported Platforms

Pre-built binaries are provided for:

Platform Architectures
Linux x86_64 (glibc, musl), aarch64, armhf, i686
macOS x86_64, aarch64 (Apple Silicon)
Windows x86_64, i686
FreeBSD x86_64

Additional platforms supported via source compilation (any Rust target with std support).


Configuration Reference

Config Struct Fields

Complete reference of all Config struct fields and their corresponding CLI/env sources:

Field Type CLI Flag Env Var Default
language Option<&str> --language, -l -- None (auto-detect)
show_nonprintable bool --show-all, -A -- false
wrapping_mode WrappingMode --wrap -- NoWrapping(false)
colored_output bool --color -- true (interactive)
true_color bool -- COLORTERM Auto-detected
term_width usize --terminal-width -- Terminal width
tab_width usize --tabs -- 4
theme String --theme BAT_THEME Platform default
style_components StyleComponents --style BAT_STYLE default
pager Option<&str> --pager BAT_PAGER, PAGER None (use default chain)
use_italic_text bool --italic-text -- false
visible_lines VisibleLines --line-range, -r, --diff -- All lines
highlighted_lines HighlightedLineRanges --highlight-line, -H -- None
syntax_mapping SyntaxMapping --map-syntax -- Empty
paging_mode PagingMode --paging -- QuitIfOneScreen
strip_ansi StripAnsiMode --strip-ansi -- Auto
squeeze_empty_lines Option<usize> --squeeze-limit -- None

WrappingMode Values

Value CLI Description
NoWrapping(false) --wrap=never No wrapping
NoWrapping(true) --wrap=never with less No wrapping + -S flag to less
Character --wrap=character Wrap at character boundaries

PagingMode Values

Value CLI Description
Always --paging=always Always use pager
QuitIfOneScreen --paging=auto Pager only if output exceeds terminal
Never --paging=never Never use pager

StyleComponent Values

Component Description Expansion
auto Platform-aware defaults (varies)
full All components All below
default Same as auto (varies)
plain No decorations (empty set)
changes Git change markers --
header File header header-filename + header-filesize
header-filename File name in header --
header-filesize File size in header --
grid Vertical/horizontal grid lines --
rule Horizontal rule between files --
numbers Line numbers --
snip Snip markers between ranges --

Cargo Features

bat uses Cargo features to control optional functionality:

Feature Default Description
default Yes Enables application
application Yes Full CLI binary (includes git, paging, lessopen, build-assets)
git Yes (via application) Git diff integration via git2
paging Yes (via application) Pager support
lessopen Yes (via application) LESSOPEN/LESSCLOSE preprocessing
build-assets Yes (via application) Asset compilation for custom syntaxes/themes
regex-onig No Use Oniguruma regex engine (faster, requires C lib)
regex-fancy No Use pure-Rust fancy-regex engine
minimal-application No Minimal binary without git/paging/lessopen
vendored-libgit2 No Compile libgit2 from source instead of using system lib

Important

Library consumers must enable either regex-onig or regex-fancy. Neither is enabled by default for the library crate -- the application feature selects one automatically for the binary.

Feature Combinations for Library Use

# Recommended for library usage (pure Rust, no C dependencies)
[dependencies]
bat = { version = "0.26", default-features = false, features = ["regex-fancy"] }

# With git support
bat = { version = "0.26", default-features = false, features = ["regex-fancy", "git"] }

# With paging support
bat = { version = "0.26", default-features = false, features = ["regex-fancy", "paging"] }

Dependencies

Key Direct Dependencies

Crate Version Purpose
syntect 5.3.0 Syntax highlighting engine (Sublime Text compatible)
clap 4.5.60 CLI argument parser (compile-time generated)
git2 0.20 Git integration (libgit2 bindings)
nu-ansi-term 0.50.3 ANSI color/style formatting
content_inspector 0.2.4 Binary file detection
encoding_rs 0.8 Character encoding conversion
terminal-colorsaurus 0.4.7 Terminal color scheme detection
minus 5.6 Built-in pager
console 0.15 Terminal width detection
shell-words 1.1 Shell command parsing
grep-cli 0.1 Binary path resolution
globset 0.4 Glob pattern matching for syntax mapping
once_cell 1.21 Lazy initialization
itertools 0.14.0 Iterator utilities

Build Dependencies

Crate Purpose
clap_complete Shell completion generation

Test Dependencies

Crate Purpose
assert_cmd CLI integration testing
predicates Assertion helpers
serial_test Serialized test execution (for env-var-dependent tests)
tempfile Temporary file/directory creation
wait-timeout Process timeout handling

Building and Development

Building from Source

# Clone with all submodules (syntax test files)
git clone --recursive https://github.com/sharkdp/bat
cd bat

# Debug build
cargo build --bins

# Release build
cargo build --release --bins

# Install release binary
cargo install --locked

Running Tests

# All tests
cargo test

# Unit tests only
cargo test --lib

# Integration tests only
cargo test --test integration_tests

Note

Some tests use serial_test because they read/write environment variables. These tests must not run in parallel. The test harness handles this automatically.

Building Custom Assets

To include modified syntaxes and themes in the binary:

bash assets/create.sh
cargo install --locked --force

Snapshot Testing

bat uses snapshot-based testing for output verification. The test infrastructure is in tests/snapshots/:

# Generate snapshots
python tests/snapshots/generate_snapshots.py

# Syntax-specific highlighted versions
python tests/syntax-tests/create_highlighted_versions.py
python tests/syntax-tests/compare_highlighted_versions.py

Test Utilities

Located in tests/utils/:

  • command.rs -- Helper functions to create bat command instances (bat(), bat_with_config(), bat_raw_command())
  • mocked_pagers.rs -- Creates temporary mocked pager executables for testing pager behavior

Security

Input Validation

Binary File Detection

bat uses the content_inspector crate to detect binary files by inspecting the initial bytes. When binary content is detected, bat prints a warning and does not display the content. This prevents:

  • Terminal corruption from binary escape sequences
  • Rendering of executable content as text
  • Accidental processing of binary data through the pager

Path Traversal

bat reads files specified on the command line. It does not follow symlinks in any special way -- standard OS file resolution applies. On Windows, Cygwin-style paths are not natively supported.

Encoding Safety

bat natively handles UTF-8 and UTF-16 (with BOM detection). It uses the encoding_rs crate for character encoding, which is a well-audited, spec-compliant implementation.

ZIP file detection (by magic bytes) prevents accidental display of archive contents.

LESSOPEN Security Considerations

Warning

The LESSOPEN/LESSCLOSE mechanism executes arbitrary shell commands specified in environment variables. This is by design (matching less behavior) but represents a potential security risk if environment variables are controlled by an attacker. bat does not sanitize or sandbox LESSOPEN commands.

When LESSOPEN processing is enabled and the pager is less, bat passes --no-lessopen to less to prevent the input from being preprocessed twice.

Pager Security

bat spawns the configured pager as a child process with stdin piped. The pager command is parsed using shell-words, which handles shell quoting but does not perform shell expansion. This means:

  • Pager commands are split by whitespace with quote handling
  • No shell metacharacters are expanded
  • The binary is resolved via grep_cli::resolve_binary(), which searches PATH

Dependencies and Supply Chain

bat's dependencies are locked via Cargo.lock. Key security-sensitive dependencies:

Dependency Risk Surface
git2 (libgit2) Native C code via FFI; system or vendored
syntect Complex parser; processes untrusted syntax definitions
encoding_rs Well-audited Mozilla project
shell-words Simple parser; no shell execution

Denial of Service Considerations

  • Large files: bat reads and processes entire files into memory for syntax highlighting. Very large files may consume significant memory. Use --line-range to limit.
  • Complex syntax definitions: Pathological syntax definitions could cause excessive backtracking in the regex engine.
  • Regex engine: regex-onig (Oniguruma, C) or regex-fancy (pure Rust) -- both handle untrusted patterns but may exhibit worst-case performance.

Operations

Configuration Directories

Platform Config Dir Cache Dir
Linux ~/.config/bat/ ~/.cache/bat/
macOS ~/Library/Application Support/bat/ ~/Library/Caches/bat/
Windows %APPDATA%\bat\ %LOCALAPPDATA%\bat\

Cache Management

The syntax/theme cache is a serialized binary file. It must be rebuilt when:

  • Custom syntaxes are added/removed/updated
  • Custom themes are added/removed/updated
  • bat is updated to a new version (binary format may change)
# Build cache from custom syntaxes/themes
bat cache --build

# Clear cache (revert to built-in assets)
bat cache --clear

# Show cache directory
bat --cache-dir

Performance Characteristics

Operation Performance Notes
Startup ~5-15ms (binary asset loading, no file I/O for built-in assets)
Syntax detection O(n) glob matching against mappings; fast for typical mapping counts
Highlighting Line-by-line; proportional to file size and syntax complexity
Git diff One git2 call per file; reads .git directory
Tab expansion Single-pass with ANSI-awareness
Pager startup Process spawn; ~5ms for less

Monitoring and Diagnostics

bat does not provide built-in monitoring or logging. Diagnostic approaches:

# Show detected syntax for a file
bat --language --list-languages

# Verify theme availability
bat --list-themes | grep "ThemeName"

# Test color support
bat --color=always test.rs | cat -v

# Debug pager behavior
BAT_PAGER="cat" bat file.rs  # Bypass pager entirely

# Check bat version and features
bat --version

Exit Codes

Code Meaning
0 Success
1 General error
2 Invalid pager value (bat set as its own pager)

Troubleshooting (Administrator)

Build Failures

git2 compilation fails

Cause: Missing C compiler or libgit2 dependencies.

Solution:

# Ubuntu/Debian
sudo apt install cmake pkg-config libssl-dev

# Or use vendored libgit2
cargo build --features vendored-libgit2

regex-onig compilation fails

Cause: Missing Oniguruma C library.

Solution: Use regex-fancy instead:

cargo build --no-default-features --features minimal-application,regex-fancy,git,paging

MSRV violation

Cause: Rust version < 1.88.

Solution: Update Rust:

rustup update stable

Runtime Issues

Syntax cache corruption

Symptoms: Panics or garbled highlighting after update.

Solution:

bat cache --clear
bat cache --build

Memory usage with large files

bat loads entire files for syntax highlighting. For very large files:

# Use line ranges
bat -r :1000 large.log

# Use plain mode (reduces memory from decoration tracking)
bat -pp large.log

# Use cat for files that don't need highlighting
cat large.log

Pager process orphaned

If bat crashes or is killed, the pager child process may become orphaned. The OutputType::Drop implementation waits for the pager to exit, but this only works during normal cleanup.

Solution: Kill orphaned less processes manually if they persist.

Environment variable conflicts

Variable Conflict Scenario
PAGER=bat Infinite recursion (bat detects and errors)
PAGER=most No ANSI color support (bat substitutes less)
BAT_OPTS with conflicting flags Later values override earlier ones
LESSOPEN May preprocess bat input unexpectedly

Packaging Notes

Debian/Ubuntu naming conflict

The bat binary conflicts with another Debian package. The Debian package installs the binary as batcat:

# Standard Debian installation
apt install bat
# Binary is at /usr/bin/batcat

# Users create symlink
ln -s /usr/bin/batcat ~/.local/bin/bat

Package maintainers should be aware of this naming convention.

Shell completion installation

Completions are generated during build and can also be generated at runtime:

bat --completion bash > /usr/share/bash-completion/completions/bat
bat --completion zsh > /usr/share/zsh/vendor-completions/_bat
bat --completion fish > /usr/share/fish/vendor_completions.d/bat.fish

Man page installation

The man page source is in assets/manual/. It should be installed to $PREFIX/share/man/man1/bat.1.


Quick Reference

Environment Variables

Variable Purpose Scope
BAT_THEME Set syntax highlighting theme Global
BAT_STYLE Set output style components Global
BAT_PAGER Override pager (highest priority after --pager) Global
BAT_OPTS Additional CLI options Global
BAT_CONFIG_PATH Override config file path Global
BAT_CONFIG_DIR Override config directory path Global
PAGER Default pager (lower priority than BAT_PAGER) System
COLORTERM Terminal color capability (truecolor or 24bit) System
LESSOPEN Input preprocessor command System
LESSCLOSE Preprocessor cleanup command System
LESSCHARSET Set by bat to UTF-8 when invoking less Set by bat

File Locations

File Platform Default Path
Config file Linux ~/.config/bat/config
Config file macOS ~/Library/Application Support/bat/config
Config file Windows %APPDATA%\bat\config
Custom syntaxes All $(bat --config-dir)/syntaxes/
Custom themes All $(bat --config-dir)/themes/
Binary cache Linux ~/.cache/bat/
Binary cache macOS ~/Library/Caches/bat/
Binary cache Windows %LOCALAPPDATA%\bat\

Pager Priority

1. --pager flag (CLI or config file)  →  PagerSource::Config
2. BAT_PAGER env var                  →  PagerSource::EnvVarBatPager
3. PAGER env var                      →  PagerSource::EnvVarPager
4. "less" (built-in default)          →  PagerSource::Default

Less Flags (Auto-configured)

When bat uses less as the pager with default or PAGER-sourced arguments:

Flag Purpose Condition
-R Enable ANSI color pass-through Always
-F Quit if content fits one screen When paging mode = QuitIfOneScreen
-S Chop long lines (horizontal scroll) When wrapping = never
-K Quit on interrupt (Ctrl+C) Unless BusyBox less
--no-init Fix quit-if-one-screen bug Only less < 530 (Unix) or < 558 (Windows)
--no-lessopen Prevent double preprocessing When lessopen feature is enabled

Public Library API

Type Module Description
PrettyPrinter bat::PrettyPrinter Main library entry point (builder pattern)
Input bat::Input Input source wrapper
Syntax bat::Syntax Syntax definition metadata
SyntaxMapping bat::SyntaxMapping File-to-syntax mapping
MappingTarget bat::MappingTarget Syntax mapping target
WrappingMode bat::WrappingMode Text wrapping mode
PagingMode bat::PagingMode Pager behavior mode
StripAnsiMode bat::StripAnsiMode ANSI stripping mode
NonprintableNotation bat::NonprintableNotation Non-printable display mode
BinaryBehavior bat::BinaryBehavior Binary content handling mode

Class/Enum Inventory

Key types in the codebase (46 total classes/enums):

Type Kind Module Purpose
Config Struct config.rs Central configuration
HighlightingAssets Struct assets.rs Syntax/theme cache
Controller Struct controller.rs Execution orchestrator
Input Struct input.rs Input source
InputDescription Struct input.rs Input metadata
InputKind Enum input.rs Input source variant
SyntaxMapping Struct syntax_mapping.rs Glob-to-syntax map
MappingTarget Enum syntax_mapping.rs Mapping destination
IgnoredSuffixes Struct ignored_suffixes.rs Suffix stripping
OutputType Enum output.rs Output destination
OutputHandle Enum output.rs Write abstraction
BuiltinPager Struct output.rs minus-based pager
Pager Struct pager.rs Pager metadata
PagerSource Enum pager.rs Pager origin
PagerKind Enum pager.rs Known pager type
PagingMode Enum paging.rs Paging behavior
PrettyPrinter Struct pretty_printer.rs Public API
StyleComponent Enum style.rs Visual component
StyleComponents Struct style.rs Component set
WrappingMode Enum wrapping.rs Wrapping behavior
StripAnsiMode Enum preprocessor.rs ANSI stripping mode
NonprintableNotation Enum nonprintable_notation.rs Display mode
BinaryBehavior Enum nonprintable_notation.rs Binary handling
LineRange Struct line_range.rs Range specification
LineRanges Struct line_range.rs Range collection
RangeBound Enum line_range.rs Absolute or relative bound
HighlightedLineRanges Struct line_range.rs Highlighted ranges
RangeCheckResult Enum line_range.rs Range check outcome
VisibleLines Enum config.rs Visible line specification
ThemeOptions Struct theme.rs Theme resolution input
ThemeResult Struct theme.rs Theme resolution output
LessVersion Enum less.rs Detected less variant
LessOpenPreprocessor Struct lessopen.rs LESSOPEN handler
LessOpenKind Enum lessopen.rs LESSOPEN mode
Preprocessed Struct lessopen.rs Preprocessed input
PreprocessedKind Enum lessopen.rs Piped vs temp file

Internals

Execution Flow

1. CLI parsing (clap)
      ↓
2. Config construction
   - Merge: CLI flags > BAT_* env > PAGER env > defaults
   - Resolve theme (color scheme detection if "auto")
   - Parse style components
   - Build syntax mappings
      ↓
3. Asset loading
   - Try cache (from_cache) → fallback to binary (from_binary)
      ↓
4. For each input:
   a. Open input (file/stdin/reader)
   b. Detect syntax (mapping → filename → extension → first line)
   c. Detect encoding (UTF-8/UTF-16/binary)
   d. If LESSOPEN enabled: preprocess
      ↓
5. Create output type
   - Resolve pager (Config → BAT_PAGER → PAGER → "less")
   - Spawn pager process or use stdout
      ↓
6. Create InteractivePrinter
   - Configure decorations (line numbers, git markers, grid)
   - Set up syntax highlighting state
      ↓
7. For each line:
   a. Strip overstrike if present
   b. Expand tabs (ANSI-aware)
   c. Apply syntax highlighting (syntect)
   d. Render decorations (sidebar)
   e. Apply wrapping
   f. Write to output handle
      ↓
8. Cleanup
   - Close input
   - Flush output
   - Wait for pager process to exit (Drop impl)
   - Run LESSCLOSE if applicable (Drop impl)

Syntax Highlighting Pipeline

Raw input line
    ↓
Strip overstrike (if backspace found)
    ↓
Expand tabs → spaces (ANSI-aware, respects tab stops)
    ↓
Strip ANSI (if StripAnsiMode != Never && not plain text)
    ↓
syntect::highlight_line() → styled spans
    ↓
Convert syntect Color → nu_ansi_term::Color
    ↓
Render with decorations (line number, git markers, grid)
    ↓
Apply wrapping (if enabled)
    ↓
Output to pager/stdout

Line Range Evaluation

The LineRange system supports both absolute and relative-from-end bounds:

enum RangeBound {
    Absolute(usize),        // Line N
    OffsetFromEnd(usize),   // N lines from end
}

For relative-from-end bounds, bat buffers lines since the final line count is unknown until EOF. The MaxBufferedLineNumber enum tracks whether the current maximum is Tentative (still reading) or Final (EOF reached), and range checks return conservative results for tentative values.

Asset Compilation

bat's built-in assets (syntaxes and themes) are compiled at build time into a binary blob using syntect's serialization:

  1. assets/create.sh collects .sublime-syntax and .tmTheme files
  2. syntect compiles them into SyntaxSet and ThemeSet
  3. These are serialized and embedded in the binary via include_bytes!
  4. At runtime, HighlightingAssets::from_binary() deserializes them

User custom assets follow the same path but are compiled at runtime with bat cache --build and stored in the cache directory.

Error Handling

bat defines its own Error type in src/error.rs with a default_error_handler:

pub fn default_error_handler(error: &Error, output: &mut dyn Write)

Error handling is done via Result<T> (aliased to bat::error::Result<T>). The bat_warning! macro in src/macros.rs outputs yellow-formatted warnings to stderr:

bat_warning!("Pager '{}' not found, outputting to stdout instead", pager.bin);

Module Visibility

Module Visibility Notes
assets pub Public API
config pub Public API
controller pub Public API
decorations private Internal
diff private Internal
error pub Public API
input pub Public API
less private Internal
lessopen private Internal, feature-gated
line_range pub Public API
output pub Public API
pager private Internal, feature-gated
paging pub(crate) Crate-internal, feature-gated
preprocessor private Internal
pretty_printer private (re-exported) Public types via pub use
printer pub(crate) Crate-internal
style pub Public API
syntax_mapping pub(crate) Crate-internal (re-exported)
terminal private Internal
theme pub Public API
vscreen private Internal
wrapping pub(crate) Crate-internal (re-exported)

Potential Improvements

Architecture Improvements

  1. Streaming output for large files -- Currently bat loads entire lines for syntax highlighting. A streaming mode could reduce memory for files that don't need full syntax context.

  2. Async pager integration -- The built-in pager uses a background thread. An async architecture could simplify the BuiltinPager implementation and improve shutdown behavior.

  3. Pluggable syntax engines -- Currently tightly coupled to syntect. An abstraction layer would allow alternative highlighting engines (e.g., tree-sitter).

Feature Gaps

  1. No official Docker image -- #3633 -- Would benefit CI/CD pipeline integration.

  2. No riscv64 pre-built binaries -- #3463 -- Growing platform demand.

  3. DOS newline handling -- #3556 -- Explicit CR/LF handling could improve cross-platform behavior.

  4. Tclsh shebang detection -- #3513 -- Missing first-line detection for Tcl scripts.

  5. Caddyfile syntax support -- #3644 -- Growing demand for Caddy web server config highlighting.

Code Quality

  1. clap argument definitions are compile-time generated -- The CLI surface is not available for AST extraction tools. Consider generating a machine-readable CLI specification.

  2. Test serialization -- LESSOPEN tests require serial_test due to environment variable mutation. Consider test isolation via subprocess or separate environment.

  3. Man page syntax still in development -- The Manpage.sublime-syntax definition in assets/syntaxes/02_Extra/ is noted as still being developed. May produce suboptimal highlighting for some man page formats.