Repository navigation
Description
Summary
-f/--file reads pattern files differently from ripgrep. Every line is trimmed and blank lines are dropped, so:
- a blank line, which ripgrep treats as an empty pattern that matches every line, is ignored;
- leading and trailing whitespace is removed from each pattern (
testis searched astest); - an empty pattern file matches every line and exits 0, while ripgrep matches nothing and exits 1.
ripgrep documents the first case explicitly: "Empty pattern lines will match all input lines, and the newline is not counted as part of the pattern."
All three happen with --no-index, with the on-disk index, and through tgrep serve.
Reproduce
mkdir repro && cd repro
printf 'alpha\nbeta\n' > a.txt
printf 'alpha\n\n' > blank_line.txt # "alpha" plus one empty pattern
: > empty.txt # no patterns at all
printf ' test\n' > b.txt
printf ' test\n' > space.txt # one pattern with a leading space
tgrep --no-index -n -f blank_line.txt a.txt
tgrep --no-index -n -f empty.txt a.txt
tgrep --no-index -o -f space.txt b.txt| Query | Actual: tgrep | Expected: rg 15.1.0 |
|---|---|---|
-n -f blank_line.txt a.txt |
1:alpha |
1:alpha, 2:beta |
-n -f empty.txt a.txt |
1:alpha, 2:beta (exit 0) |
no output (exit 1) |
-o -f space.txt b.txt |
test |
test |
Environment
- tgrep 1.1.0, built from 1120aca (current
main) with rustc 1.95.0 (59807616e 2026-04-14) - Windows 11 Pro (build 28000); the code involved is platform-independent
- Same results with
--no-index, with a local index (tgrep index .), and throughtgrep serve
Cause
SearchOptions::all_patterns trims each line of the pattern file and skips it if the result is empty:
Lines 441 to 449 in 1120aca
| if let Some(ref path) = self.pattern_file { | |
| let content = std::fs::read_to_string(path)?; | |
| for line in content.lines() { | |
| let line = line.trim(); | |
| if !line.is_empty() { | |
| patterns.push(line.to_string()); | |
| } | |
| } | |
| } |
For an empty file the pattern list ends up empty. combine_patterns then joins zero patterns into (?:), which matches everywhere, and build_multi_pattern_plan returns MatchAll for zero patterns. The client builds the server request from the same list (search.rs#L994), so serve behaves the same way.
Possible fix
- Keep each line as written.
str::linesalready strips both\nand\r\n, so dropping thetrim()and the empty-line filter is enough, and pattern files with CRLF line endings keep working (a file containingalpha\r\nfindsalphain both tools today). - Treat "no patterns" as "matches nothing" rather than as one empty pattern: skip the search and exit 1, as ripgrep does. An empty line in the file is one empty pattern and should still match every line.
A regression test could run the three cases above with --no-index, against a local index, and through serve.
Activity
Fix search compatibility bugs and Linux RSS test (#187)