# bat Administration & Developer Guide

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.

```rust
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.

```rust
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.

```rust
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:

```rust
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:

```rust
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:

```rust
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

```toml
# 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

```bash
# 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

```bash
# 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
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/`:

```bash
# 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)

```bash
# 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:

```bash
# 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:**

```bash
# 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:

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

#### MSRV violation

**Cause:** Rust version < 1.88.

**Solution:** Update Rust:

```bash
rustup update stable
```

### Runtime Issues

#### Syntax cache corruption

**Symptoms:** Panics or garbled highlighting after update.

**Solution:**

```bash
bat cache --clear
bat cache --build
```

#### Memory usage with large files

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

```bash
# 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`:

```bash
# 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:

```bash
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:

```rust
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`:

```rust
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:

```rust
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](https://github.com/sharkdp/bat/issues/3633) -- Would benefit CI/CD pipeline integration.

2. **No riscv64 pre-built binaries** -- [#3463](https://github.com/sharkdp/bat/issues/3463) -- Growing platform demand.

3. **DOS newline handling** -- [#3556](https://github.com/sharkdp/bat/issues/3556) -- Explicit CR/LF handling could improve cross-platform behavior.

4. **Tclsh shebang detection** -- [#3513](https://github.com/sharkdp/bat/issues/3513) -- Missing first-line detection for Tcl scripts.

5. **Caddyfile syntax support** -- [#3644](https://github.com/sharkdp/bat/issues/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.

---

_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. Unofficial; not affiliated with or reviewed by the project._
