diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -3403,8 +3403,6 @@ def grep(ui, repo, pattern, *pats, **opt ) getfile = searcher._getfile - matches = searcher._matches - copies = searcher._copies uipathfn = scmutil.getuipathfn(repo) @@ -3514,8 +3512,6 @@ def grep(ui, repo, pattern, *pats, **opt fm.data(matched=False) fm.end() - skip = searcher._skip - revfiles = searcher._revfiles found = False wopts = logcmdutil.walkopts( @@ -3532,29 +3528,11 @@ def grep(ui, repo, pattern, *pats, **opt ui.pager(b'grep') fm = ui.formatter(b'grep', opts) - for ctx in scmutil.walkchangerevs( - repo, revs, makefilematcher, searcher._prep - ): - rev = ctx.rev() - parent = ctx.p1().rev() - for fn in sorted(revfiles.get(rev, [])): - states = matches[rev][fn] - copy = copies.get(rev, {}).get(fn) - if fn in skip: - if copy: - skip.add(copy) - continue - pstates = matches.get(parent, {}).get(copy or fn, []) - if pstates or states: - r = display(fm, fn, ctx, pstates, states) - found = found or r - if r and not diff and not all_files: - searcher.skipfile(fn, rev) - del revfiles[rev] - # We will keep the matches dict for the duration of the window - # clear the matches dict once the window is over - if not revfiles: - matches.clear() + for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher): + r = display(fm, fn, ctx, pstates, states) + found = found or r + if r and not diff and not all_files: + searcher.skipfile(fn, ctx.rev()) fm.end() return not found diff --git a/mercurial/grep.py b/mercurial/grep.py --- a/mercurial/grep.py +++ b/mercurial/grep.py @@ -115,6 +115,34 @@ class grepsearcher(object): if copy: self._skip.add(copy) + def searchfiles(self, revs, makefilematcher): + """Walk files and revisions to yield (fn, ctx, pstates, states) + matches + + states is a list of linestate objects. pstates may be empty unless + diff is True. + """ + for ctx in scmutil.walkchangerevs( + self._repo, revs, makefilematcher, self._prep + ): + rev = ctx.rev() + parent = ctx.p1().rev() + for fn in sorted(self._revfiles.get(rev, [])): + states = self._matches[rev][fn] + copy = self._copies.get(rev, {}).get(fn) + if fn in self._skip: + if copy: + self._skip.add(copy) + continue + pstates = self._matches.get(parent, {}).get(copy or fn, []) + if pstates or states: + yield fn, ctx, pstates, states + del self._revfiles[rev] + # We will keep the matches dict for the duration of the window + # clear the matches dict once the window is over + if not self._revfiles: + self._matches.clear() + def _grepbody(self, fn, rev, body): self._matches[rev].setdefault(fn, []) m = self._matches[rev][fn]