[PATCH 1 of 2] grep: introduce a manifest search method

Steve Borho steve at borho.org
Sat May 15 12:55:00 CDT 2010


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1273812860 18000
# Node ID c97ae1a76ea01b46425099ddcf3c7cb9320b8d70
# Parent  ba78a1bfbfd9fbe0fa48a05b8d94e6dcf431f635
grep: introduce a manifest search method

If no annotate information is requested by the user, perform a
fast scan using a context manifest.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1265,18 +1265,21 @@
 def grep(ui, repo, pattern, *pats, **opts):
     """search for a pattern in specified files and revisions
 
-    Search revisions of files for a regular expression.
+    Search files or revisions for a regular expression.
 
     This command behaves differently than Unix grep. It only accepts
-    Python/Perl regexps. It searches repository history, not the
-    working directory. It always prints the revision number in which a
-    match appears.
-
-    By default, grep only prints output for the first revision of a
-    file in which it finds a match. To get it to print every revision
-    that contains a change in match status ("-" for a match that
-    becomes a non-match, or "+" for a non-match that becomes a match),
-    use the --all flag.
+    Python/Perl regexps.
+    
+    If no annotation arguments (user, rev, follow, etc) are specified,
+    grep directly searches the working directory.
+    
+    When annotation is required, it searches repository history and
+    always prints the revision number in which a match appears.
+    By default when searching history, grep only prints output for the
+    first revision of a file in which it finds a match. To get it to
+    print every revision that contains a change in match status ("-" for
+    a match that becomes a non-match, or "+" for a non-match that
+    becomes a match), use the --all flag.
     """
     reflags = 0
     if opts.get('ignore_case'):
@@ -1292,6 +1295,37 @@
 
     getfile = util.lrucachefunc(repo.file)
 
+    def manifestgrep(ui, ctx, matchfn):
+        total = len(ctx.manifest())
+        for count, fn in enumerate(ctx):
+            ui.progress(_('searching'), count, fn, _('files'), total)
+            if not matchfn(fn):
+                continue
+            data = ctx[fn].data()
+            if '\0' in data:
+                continue
+            for i, line in enumerate(data.splitlines()):
+                if opts.get('files_with_matches'):
+                    if regexp.search(line):
+                        ui.write(fn + eol)
+                        break
+                    continue
+                pos = 0
+                t = []
+                for m in regexp.finditer(line):
+                    s, e = m.span()
+                    t.append(line[pos:s])
+                    t.append(ui.label(line[s:e], label='grep.match'))
+                    pos = e
+                if pos:
+                    t.append(line[pos:])
+                    cols = [fn]
+                    if opts.get('line_number'):
+                        cols.append(str(i))
+                    cols.append(''.join(t))
+                    ui.write(sep.join(cols) + eol)
+        ui.progress(_('searching'), None)
+
     def matchlines(body):
         begin = 0
         linenum = 0
@@ -1387,6 +1421,15 @@
     found = False
     follow = opts.get('follow')
 
+    for o in ('user', 'date', 'follow', 'all', 'rev'):
+        if opts.get(o):
+            break
+    else:
+        # no annotation required, do fast grep
+        ctx = repo[None]
+        manifestgrep(ui, ctx, matchfn)
+        return
+
     def prep(ctx, fns):
         rev = ctx.rev()
         pctx = ctx.parents()[0]


More information about the Mercurial-devel mailing list