From 7c24ede827dcd0221ca80d2644283810f83b7fd7 Mon Sep 17 00:00:00 2001 From: Wondr Date: Fri, 5 Jun 2026 03:08:16 +0100 Subject: [PATCH 1/2] grep: handle zero-width matches at EOF --- src/matcher.rs | 2 ++ tests/test_grep.rs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/matcher.rs b/src/matcher.rs index 6d72b69..cb61884 100644 --- a/src/matcher.rs +++ b/src/matcher.rs @@ -209,6 +209,8 @@ struct Cursor<'a> { impl Cursor<'_> { fn refill(&mut self) { + // Searching at EOF is still meaningful for zero-width patterns such as + // `$` and `x*`. After emitting one, `offset` is nudged past EOF below. if self.offset > self.line.len() { self.pending = None; return; diff --git a/tests/test_grep.rs b/tests/test_grep.rs index 2c16db4..e01dd1b 100644 --- a/tests/test_grep.rs +++ b/tests/test_grep.rs @@ -587,6 +587,23 @@ fn only_matching() { .succeeds() .stdout_only("Hello\nhELLO\nHELLO\n"); + // Zero-width matches do not print in -o mode, but still mark the line as + // matched. This matters for -v because matched lines must not be selected. + let (_s, mut c) = ucmd(); + c.args(&["-o", "$"]).pipe_in("\n").succeeds().no_output(); + + let (_s, mut c) = ucmd(); + c.args(&["-o", "-v", "$"]) + .pipe_in("a\n\nb\n") + .fails_with_code(1) + .no_output(); + + let (_s, mut c) = ucmd(); + c.args(&["-o", "-v", "x*"]) + .pipe_in("a\n\nb\n") + .fails_with_code(1) + .no_output(); + // After a match ends, ^ must not re-match at that position. let (_s, mut c) = ucmd(); c.args(&["-o", "^hello*"]) From 5ea366761347e01fa0bac3531885bdd610f9aa66 Mon Sep 17 00:00:00 2001 From: Wondr Date: Fri, 5 Jun 2026 15:41:15 +0100 Subject: [PATCH 2/2] grep: narrow zero-width EOF PR to coverage --- src/matcher.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/matcher.rs b/src/matcher.rs index cb61884..6d72b69 100644 --- a/src/matcher.rs +++ b/src/matcher.rs @@ -209,8 +209,6 @@ struct Cursor<'a> { impl Cursor<'_> { fn refill(&mut self) { - // Searching at EOF is still meaningful for zero-width patterns such as - // `$` and `x*`. After emitting one, `offset` is nudged past EOF below. if self.offset > self.line.len() { self.pending = None; return;