SIGN IN SIGN UP

perf(grep): up to 14.5× speedup via preFilter extensions and matcher reuse (#248)

* perf(grep): extract preFilter needles from anchored alternation (^lit1|^lit2)

* perf(grep): reuse re2 matcher and add file-level preFilter fast-path

Switch all UserRegex methods to acquireMatcher(input) to avoid
per-call allocations, and propagate preFilter into searchContentMultiline
so files with no needle are skipped without scanning every line.

* fix(grep): address PR review — matchAll generator + full output assertions
- matchAll(): revert to fresh `_re2.matcher(input)`. As a generator that
  suspends at yield, sharing the cached `_matcher` risks corruption if a
  caller interleaves any other UserRegex method (test/exec/search/replace)
  between two next() calls — acquireMatcher would reset/repoint the shared
  matcher, breaking the in-progress iteration. All other synchronous
  methods continue to use acquireMatcher.

- matcher.test.ts: replace two toContain assertions in the multiline
  preFilter tests with full output equality (per AGENTS.md guidance), so
  regressions in line numbering or group separators surface.

- grep.ts: add file-level preFilter check right after readFile — skips
  searchContent (and the content.split("\n")) entirely when no needle
  exists in the file. Handles countOnly correctly (emits "0\n" or
  "filename:0\n" without entering the line loop).

- matcher.ts searchContentMultiline: fix preFilter early return to emit
  "0\n"/"filename:0\n" in count-only mode instead of empty string.

- user-regex.ts replace() callback path: capture matcher.start(0) and
  matcher.end(0) before invoking the callback — acquireMatcher mutates
  charSequence in-place, so a re-entrant call would corrupt those reads.

* chore: bump patch ver with changeset

* fix(regex): use fresh matcher in replace() callback path

The callback may re-enter the same UserRegex instance, which would route
through acquireMatcher and repoint the shared matcher's charSequence,
causing the next matcher.find(pos) to advance through the wrong input.
Mirrors the matchAll() fix.
H
Harry Nguyen committed
d64009aef6bc1556e7c84b22ed455863275ea953
Parent: 25262af
Committed by GitHub <noreply@github.com> on 5/26/2026, 1:35:10 AM