# How bat Handles Paging for Long Output: A Deep Dive into the Rust Source Code

> Explore how bat handles paging for long output. Dive into the Rust source code to understand its pager configuration and external or built-in pager delegation.

- Repository: [David Peter/bat](https://github.com/sharkdp/bat)
- Tags: deep-dive
- Published: 2026-03-06

---

**bat determines whether to pipe output through a pager by checking the `PagingMode` configuration (Always, QuitIfOneScreen, or Never), then delegates to `OutputType::from_mode` in [`src/output.rs`](https://github.com/sharkdp/bat/blob/main/src/output.rs) to spawn either an external pager (like `less`) with carefully crafted arguments or a built-in pager using the `minus` crate.**

The `bat` command-line tool by `sharkdp/bat` enhances the standard `cat` command with syntax highlighting and Git integration. Understanding how bat handles paging for long output reveals a sophisticated system that balances user configuration, environment detection, and intelligent pager selection to ensure optimal viewing experience across different terminal environments.

## The Three Paging Modes in bat

At the core of bat's paging logic is the `PagingMode` enum defined in [`src/paging.rs`](https://github.com/sharkdp/bat/blob/main/src/paging.rs). This enum specifies exactly when bat should engage a pager:

```rust
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum PagingMode {
    Always,
    QuitIfOneScreen,
    #[default] Never,
}

```

- **`Never`** (default): bat writes directly to stdout without invoking a pager.
- **`QuitIfOneScreen`**: bat invokes the pager with flags that cause it to exit immediately if the entire output fits on one screen.
- **`Always`**: bat always pipes output through the pager, regardless of length.

## How bat Decides When to Page

The decision logic resides in `Controller::run` within [`src/controller.rs`](https://github.com/sharkdp/bat/blob/main/src/controller.rs). This method inspects the runtime `Config` to determine the appropriate paging strategy:

```rust
let mut paging_mode = self.config.paging_mode;
// ... logic to force Never mode when no input files exist ...
output_type_opt = Some(OutputType::from_mode(
    paging_mode,
    wrapping_mode,
    self.config.pager,
)?);

```

If no input files are provided (for example, when reading from stdin with no tty), bat forces `PagingMode::Never` to prevent hanging on interactive pager prompts. Otherwise, it constructs an `OutputType` that encapsulates either a spawned pager process or direct stdout access.

## Selecting and Configuring the Pager

The `OutputType::from_mode` function in [`src/output.rs`](https://github.com/sharkdp/bat/blob/main/src/output.rs) serves as the factory for pager instances. It delegates to `try_pager` with specific `SingleScreenAction` instructions based on the paging mode:

```rust
match paging_mode {
    Always => OutputType::try_pager(SingleScreenAction::Nothing, …)?,
    QuitIfOneScreen => OutputType::try_pager(SingleScreenAction::Quit, …)?,
    _ => OutputType::stdout(),
}

```

### External Pager Selection

The `try_pager` method relies on [`src/pager.rs`](https://github.com/sharkdp/bat/blob/main/src/pager.rs) to resolve which pager binary to execute. The resolution follows a strict priority hierarchy:

1.  **`--pager` CLI flag**
2.  **`BAT_PAGER` environment variable**
3.  **`PAGER` environment variable**
4.  **Default to `less`**

As implemented in [`src/pager.rs`](https://github.com/sharkdp/bat/blob/main/src/pager.rs):

```rust
let (cmd, source) = match (config_pager, &bat_pager, &pager) {
    (Some(config_pager), _, _) => (config_pager, PagerSource::Config),
    (_, Ok(bat_pager), _) => (bat_pager.as_str(), PagerSource::EnvVarBatPager),
    (_, _, Ok(pager)) => (pager.as_str(), PagerSource::EnvVarPager),
    _ => ("less", PagerSource::Default),
};

```

### Argument Handling for less

When using the generic `PAGER` environment variable, bat sanitizes arguments to ensure proper behavior. It injects flags such as:

- **`-R`** (or `--RAW-CONTROL-CHARS`): Preserves ANSI color sequences
- **`-F`** (or `--quit-if-one-screen`): Exits immediately if output fits on one screen (used with `QuitIfOneScreen` mode)
- **`-S`** (or `--chop-long-lines`): Truncates long lines rather than wrapping
- **`--no-init`**: Prevents clearing the screen on exit

### Built-in Pager Fallback

If the resolved pager command is exactly `builtin`, bat instantiates an internal pager using the **minus** crate. This provides a pure-Rust paging solution that requires no external binaries, useful in constrained environments or when `less` is unavailable.

## Practical Examples

Configure bat's paging behavior using CLI flags or environment variables:

```bash

# Default behavior – use less, quit if output fits on one screen

bat src/main.rs

# Force paging always, even for short output

bat --paging=always src/main.rs

# Disable paging entirely – pipe-friendly for scripts

bat --paging=never src/main.rs

# Use a custom pager via environment variable

export BAT_PAGER="most -R"
bat src/main.rs

# Use the built-in Rust pager

export BAT_PAGER="builtin"
bat src/main.rs

```

For programmatic use in Rust applications using bat as a library:

```rust
// Requires bat = "0.24"
use bat::{ConfigBuilder, PagingMode};

let config = ConfigBuilder::new()
    .paging_mode(PagingMode::QuitIfOneScreen)
    .build()
    .unwrap();

let printer = bat::PrettyPrinter::new(&config);
printer.print_source("fn main() {}", "rust").unwrap();

```

## Summary

- **Three paging policies**: `Never` (default), `QuitIfOneScreen`, and `Always`, defined in [`src/paging.rs`](https://github.com/sharkdp/bat/blob/main/src/paging.rs).
- **Decision logic**: `Controller::run` in [`src/controller.rs`](https://github.com/sharkdp/bat/blob/main/src/controller.rs) evaluates `config.paging_mode` and forces `Never` when no input files exist.
- **Pager instantiation**: `OutputType::from_mode` in [`src/output.rs`](https://github.com/sharkdp/bat/blob/main/src/output.rs) spawns external pagers or falls back to stdout based on the mode.
- **Pager resolution**: [`src/pager.rs`](https://github.com/sharkdp/bat/blob/main/src/pager.rs) selects binaries via `--pager`, `BAT_PAGER`, `PAGER`, or defaults to `less`, sanitizing arguments for color and quit behavior.
- **Built-in option**: Setting the pager to `builtin` uses the **minus** crate for a pure-Rust paging implementation.

## Frequently Asked Questions

### How do I disable paging in bat completely?

Set the paging mode to `never` using the `--paging=never` CLI flag or configure it in your bat configuration file. This forces bat to write directly to stdout without invoking any pager process, making it ideal for piping output to other commands or scripts.

### Why does bat sometimes quit automatically when output is short?

When using the default `QuitIfOneScreen` paging mode (or when `--paging=auto` is set), bat passes the `-F` flag to `less`, which instructs the pager to exit immediately if the entire output fits on one screen. This behavior prevents unnecessary interactive prompts for short files.

### Can I use a custom pager like `most` or `delta` with bat?

Yes, bat respects the `BAT_PAGER` environment variable and the `--pager` CLI option, allowing you to specify any executable. For example, `export BAT_PAGER="most -R"` or `bat --pager="delta"` will route bat's formatted output through your chosen pager with the specified arguments.

### What happens if `less` is not installed on my system?

If `less` is unavailable and no custom pager is configured via `BAT_PAGER` or `PAGER`, bat can fall back to a built-in pager by setting `BAT_PAGER="builtin"`. This uses the **minus** crate to provide a pure-Rust paging implementation that requires no external binaries.