# HG changeset patch # User Yuya Nishihara # Date 2020-09-09 08:17:38 # Node ID f9d3ff23bfc01407423f75f90c65860033dd4d25 # Parent 508dfd1c18df2d4875b7cb1b647b8d23527a1d7f grep: extract main search loop as searcher method Still displayer part is in commands.grep(), the core grep logic is now reusable. I'll revisit the displayer stuff later since it will be another long series. 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]