BurntSushi/ripgrep
searcher (grep-searcher)
Active contributors: Andrew Gallant
Purpose
crates/searcher (published as grep-searcher) is ripgrep's line-oriented search engine. It owns the loop that:
- Reads bytes from a source (file, stdin, or memory map).
- Hands chunks to a
Matcherto find matches. - Tracks line numbers, context lines, binary detection, and encoding.
- Pushes results into a
Sink(typically a printer).
The Matcher is engine-agnostic; the Sink is output-agnostic. This crate sits between them and does the line-oriented bookkeeping.
Directory layout
crates/searcher/src/
├── lib.rs # Public API surface (re-exports + crate docs)
├── line_buffer.rs # Streaming line buffer for non-mmap mode (~35K)
├── lines.rs # LineIter, LineStep — slicing byte buffers into lines
├── sink.rs # The Sink trait + SinkMatch / SinkContext / SinkFinish
├── macros.rs # Internal macros
├── testutil.rs # SearcherTester: matrix tester used by this crate and grep-printer
└── searcher/
├── mod.rs # Searcher / SearcherBuilder / Encoding / BinaryDetection (~41K)
├── core.rs # The actual search loop (~23K)
├── glue.rs # Wires Searcher + Matcher + Sink + LineBuffer (~50K)
└── mmap.rs # MmapChoice and the mmap vs. read decisionKey abstractions
| Type | File | Description |
|---|---|---|
Searcher |
crates/searcher/src/searcher/mod.rs |
The main type. Configured by SearcherBuilder. Has methods like search_path, search_file, search_reader, search_slice. |
SearcherBuilder |
crates/searcher/src/searcher/mod.rs |
Builder for Searcher. Controls line terminator, multi-line, encoding, binary detection, mmap choice, line numbers, before/after context, and stop-on-NUL. |
Sink |
crates/searcher/src/sink.rs |
Trait that receives match callbacks. matched, context, context_break, binary_data, begin, finish. |
SinkMatch / SinkContext / SinkFinish |
crates/searcher/src/sink.rs |
The data passed to Sink callbacks: the matching/contextual lines, byte offsets, line numbers. |
BinaryDetection |
crates/searcher/src/searcher/mod.rs |
None, Quit(byte), or Convert(byte) — what to do when a forbidden byte is seen. |
Encoding |
crates/searcher/src/searcher/mod.rs |
Wraps an encoding_rs::Encoding for transcoding non-UTF-8 input. |
MmapChoice |
crates/searcher/src/searcher/mmap.rs |
Auto, Always, Never decision for whether to use a memory map. |
LineBuffer |
crates/searcher/src/line_buffer.rs |
Streaming buffer used in non-mmap mode. Reads chunks, finds line boundaries, hands aligned slices to the search loop. |
LineIter / LineStep |
crates/searcher/src/lines.rs |
Iterators for slicing a &[u8] into lines respecting the configured terminator. |
How it works
sequenceDiagram
participant Caller
participant Builder as SearcherBuilder
participant Searcher
participant Source as Reader / Mmap
participant Matcher
participant Sink
Caller->>Builder: configure (multi_line, encoding, binary, ...)
Builder->>Searcher: build()
Caller->>Searcher: search_path(matcher, path, sink)
Searcher->>Source: open / mmap
loop for each chunk
Source->>Searcher: bytes
Searcher->>Matcher: find_iter_at(chunk)
Matcher->>Searcher: matches
Searcher->>Sink: matched(SinkMatch) / context(SinkContext)
end
Searcher->>Sink: finish(SinkFinish)The "chunk" here depends on mode:
- mmap: the entire file is mapped, then
searcher/glue.rsruns the loop over the whole slice in one call tosearcher/core.rs. - buffered:
line_buffer.rsreads in fixed-size chunks (default 8 KiB), maintains an alignment invariant ("the buffer always ends at a line boundary"), and feeds aligned slices to the same core loop.
Multi-line mode
When multi_line(true) is set on SearcherBuilder, the searcher disables line-by-line slicing and gives the matcher the whole haystack at once. This is what -U/--multiline does. It is mutually exclusive with chunked buffered reads — multi-line mode forces mmap (or a single read into a Vec<u8> if mmap is disabled).
Binary detection
BinaryDetection::quit(b) is the default for ripgrep when searching files. The searcher peeks at the first ~8 KiB of the haystack; if b (typically NUL) appears, the rest of the file is skipped and the sink's binary_data callback fires.
BinaryDetection::convert(b) instead replaces the byte with a line terminator and continues searching. ripgrep uses this for stdin under some conditions.
BinaryDetection::None disables the check (--text).
Encoding
If Encoding::new(...) is set, the source is read through an encoding_rs decoder that emits UTF-8 bytes. Heuristic UTF-16 detection (BOM-based) is built in. This is what makes rg --encoding utf-16le work.
Public examples
crates/searcher/examples/search-stdin.rs is a minimal program showing how to search stdin with a regex and print matching lines. The crate's lib-level docs in lib.rs show a fuller example using sinks::UTF8.
Test harness
testutil.rs defines SearcherTester, a matrix-style harness that runs the same query through every relevant configuration (mmap on/off, multi-line on/off, line numbers on/off, ...) and compares against a single expected output. Both this crate's tests and grep-printer's tests use it.
Integration points
- Used by:
crates/core/search.rs::SearchWorker, every printer ingrep-printer. - Uses:
grep-matcher(for theMatcherinterface),bstr(byte string utilities),encoding_rs(transcoding),memchr(fast byte scanning),memmap2(memory mapping). - Re-exported by:
grep::searcher.
Entry points for modification
- New
SearcherBuilderoption: add a config field, plumb throughSearcher, surface as a CLI flag incrates/core/flags/defs.rsif user-facing. - Performance changes to the core loop:
searcher/core.rsandsearcher/glue.rs. These files are written for the optimiser; benchmark before merging. - New sink behaviour: usually means changes in
grep-printer, not here. Only modify theSinktrait if the new behaviour cannot be expressed with existing callbacks.
For more on what plugs into a searcher, see matcher and printer.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.