How bat Handles Line Ranges to Display Specific Parts of a File
bat parses the --line-range flag into a LineRange structure that supports absolute numbers, relative offsets from the end, and context modifiers, then filters output during streaming via LineRanges::check to display only requested lines.
The bat command-line tool by sharkdp/bat enhances file viewing with syntax highlighting and git integration. When you need to display specific sections of large files, understanding how bat handles line ranges helps you extract exactly the content you need using the --line-range (-r) flag.
Understanding the LineRange Syntax
The --line-range flag accepts flexible syntax patterns that define lower and upper bounds. These patterns are parsed in src/line_range.rs to handle absolute positions, offsets from the end, and relative ranges.
| Syntax | Meaning |
|---|---|
N:M |
Print lines N through M (inclusive). |
:M |
Print from the start of the file up to line M. |
N: |
Print from line N to the end of the file. |
N |
Print only line N. |
-K: |
Print the last K lines (offset from the end). |
:-K |
Print from the start up to the line K lines before the end. |
N:+K |
Print lines N through N + K (relative positive offset). |
N:-K |
Print lines N - K through N (relative negative offset). |
N::C |
Print line N plus C lines of context on both sides. |
N:M:C |
Print range N … M plus C lines of context on both sides. |
Parsing Line Ranges in bat
The LineRange Structure and parse_range Function
In src/line_range.rs, the LineRange struct stores lower and upper bounds as RangeBound variants. The LineRange::parse_range function tokenizes the raw string (e.g., "30:+10"), detects the presence of colons or +/- signs, and builds a LineRange whose fields are RangeBound variants.
The RangeBound enum supports two variants:
Absolute(usize)for fixed line numbersOffsetFromEnd(usize)for negative offsets (e.g.,-5:)
See the implementation in src/line_range.rs lines 36-77 for the tokenization logic that handles the various syntax patterns.
Context Syntax Handling
When the parser encounters three components (e.g., N:M:C or N::C), it interprets the third value as context lines. In src/line_range.rs lines 100-124, the code expands the lower bound by subtracting the context value and expands the upper bound by adding it, ensuring the output includes the specified number of lines before and after the target range.
Resolving Relative and End-Based Offsets
OffsetFromEnd and File Size Resolution
Relative offsets like -K: (last K lines) cannot be resolved until the file size is known. The LineRange::is_inside method in src/line_range.rs (lines 133-190) evaluates whether a given line number falls within the range, using the current MaxBufferedLineNumber to calculate final positions for OffsetFromEnd variants.
This deferred resolution allows bat to evaluate ranges that depend on the final line count while streaming the file, avoiding the need to buffer the entire file upfront.
Selective Rendering with LineRanges::check
Multiple ranges are managed by the LineRanges struct. The LineRanges::check method in src/line_range.rs (lines 378-449) classifies each line as InRange, BeforeOrBetweenRanges, or AfterLastRange during the rendering process.
The PrettyPrinter in src/pretty_printer.rs holds a HighlightedLineRanges (wrapping a LineRanges) and queries LineRanges::check for each line to determine whether to print it and apply syntax highlighting.
CLI Integration and Rendering Pipeline
Command-Line Flag Definition
The --line-range flag is defined in src/bin/bat/clap_app.rs (lines 17-24). The configuration specifies allow_hyphen_values(true) to ensure that leading hyphens (such as -10:) are accepted as part of the range value rather than being interpreted as separate command-line flags.
Building LineRanges in the Application Layer
In src/bin/bat/app.rs (lines 486-504), the application transforms each supplied --line-range argument into a LineRange via LineRange::from, then collects them into a LineRanges object that is passed to the printer for filtering during output.
Rendering Integration
The controller.rs module uses LineRanges::check to drive paging and output flow, while src/pretty_printer.rs wraps the range checking logic in HighlightedLineRanges to determine which lines receive syntax highlighting and are sent to the output buffer.
Practical Examples
# Print lines 10 to 20 (inclusive)
bat -r 10:20 source.rs
# Print the first 40 lines
bat -r :40 source.rs
# Print from line 40 to the end of the file
bat -r 40: source.rs
# Print only line 42
bat -r 42 source.rs
# Print the last 5 lines (negative offset from end)
bat -r -5: source.rs
# Print lines 30 to 40, plus 2 lines of context on each side
bat -r 30:40:2 source.rs
# Print line 35 with 5 lines of context (single-line base)
bat -r 35::5 source.rs
# Print a range with a relative "+" offset (30-40)
bat -r 30:+10 source.rs
All of these options are parsed by LineRange::from and ultimately evaluated by LineRanges::check during the rendering pipeline.
Summary
-
Flexible Syntax: bat supports absolute ranges (
N:M), open-ended ranges (:M,N:), single lines (N), end-relative offsets (-K:), and context modifiers (N::C,N:M:C). -
Structured Representation: The
LineRangestruct insrc/line_range.rsstores bounds asRangeBoundvariants (AbsoluteorOffsetFromEnd), parsed byLineRange::parse_range. -
Deferred Resolution: End-relative offsets are resolved during streaming via
LineRange::is_inside, which uses the current maximum buffered line number to calculate final positions without loading the entire file. -
Collection Management: Multiple ranges are managed by
LineRanges, which usesLineRanges::checkto classify each line asInRange,BeforeOrBetweenRanges, orAfterLastRangeduring output. -
CLI Integration: The
--line-rangeflag is defined insrc/bin/bat/clap_app.rswithallow_hyphen_values(true), processed insrc/bin/bat/app.rs, and consumed by thePrettyPrinterinsrc/pretty_printer.rs.
Frequently Asked Questions
How does bat handle negative line numbers like -5: to show the last 5 lines?
bat interprets negative offsets using the OffsetFromEnd variant of the RangeBound enum in src/line_range.rs. When you specify -5:, the parser creates a range with a lower bound of OffsetFromEnd(5) and an upper bound of OffsetFromEnd(0). The LineRange::is_inside method resolves these offsets against the current maximum buffered line number while streaming the file, allowing bat to display the final lines without reading the entire file into memory first.
Can I specify multiple line ranges in a single bat command?
Yes, you can provide multiple --line-range (or -r) flags to display disjoint sections of a file. According to src/bin/bat/app.rs (lines 486-504), each argument is converted to a LineRange via LineRange::from and collected into a LineRanges object. The LineRanges::check method in src/line_range.rs (lines 378-449) then evaluates each line against all specified ranges, printing it if it falls within any of them.
What is the difference between N:+K and N:M syntax in bat line ranges?
The N:+K syntax specifies a relative offset from line N, printing lines N through N+K inclusive, while N:M specifies absolute line numbers. In src/line_range.rs, the LineRange::parse_range function detects the + or - prefix after the colon and constructs bounds accordingly. For N:+K, the upper bound becomes Absolute(N + K), whereas for N:M, both bounds are parsed as absolute values directly from the input strings without arithmetic modification.
How does bat add context lines around a specific range?
bat supports context syntax using double colons (N::C) or triple components (N:M:C), where C represents the number of context lines to add on both sides. In src/line_range.rs (lines 100-124), when the parser detects three components or the :: pattern, it expands the lower bound by subtracting the context value and expands the upper bound by adding it. This ensures the output includes the specified number of lines before and after the target range while maintaining the original range as the core content.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →