[PATCH hyperblame] annotate: allow skipping revs

Siddharth Agarwal sid0 at fb.com
Tue May 23 00:27:36 UTC 2017


# HG changeset patch
# User Siddharth Agarwal <sid0 at fb.com>
# Date 1495499248 25200
#      Mon May 22 17:27:28 2017 -0700
# Node ID c14a092fcb1184b5961d81620f88de5771e24cea
# Parent  e8c043375b53b30c4b468687f08323cbeeb452ef
annotate: allow skipping revs

This is not ready to be landed yet, but several people on IRC asked for it so
here it is.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -376,6 +376,7 @@ def annotate(ui, repo, *pats, **opts):
 
         lines = fctx.annotate(follow=follow, linenumber=linenumber,
                               diffopts=diffopts)
+        import sys; sys.stderr.write("lines: %s\n" % lines)
         if not lines:
             continue
         formats = []
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -969,13 +969,51 @@ class basefilectx(object):
             def decorate(text, rev):
                 return ([(rev, False)] * lines(text), text)
 
-        def pair(parent, child):
-            blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts)
+        def pairequal(parent, blocks, child):
             for (a1, a2, b1, b2), t in blocks:
                 # Changed blocks ('!') or blocks made only of blank lines ('~')
                 # belong to the child.
                 if t == '=':
                     child[0][b1:b2] = parent[0][a1:a2]
+
+        def pairunequal(childfctx, parent, blocks, child):
+            # Try and assign anything that couldn't be matched exactly.
+            for (a1, a2, b1, b2), t in blocks:
+                for bline in xrange(b1, b2):
+                    if child[0][bline][0] == childfctx:
+                        offset = min(a1 + (bline - b1), a2 - 1)
+                        child[0][bline] = parent[0][offset]
+
+        def pair(childfctx, parent, child, skipchild):
+            blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts)
+            if skipchild:
+                # we'll need to iterate over blocks twice
+                blocks = list(blocks)
+
+            pairequal(parent, blocks, child)
+            if skipchild:
+                pairunequal(childfctx, parent, blocks, child)
+
+            return child
+
+        def pair2(childfctx, parent1, parent2, child, skipchild):
+            blocks1 = mdiff.allblocks(parent1[1], child[1], opts=diffopts)
+            blocks2 = mdiff.allblocks(parent2[1], child[1], opts=diffopts)
+            if skipchild:
+                blocks1 = list(blocks1)
+                blocks2 = list(blocks2)
+
+            # Mercurial currently prefers p2 over p1 for annotate.
+            # TODO: change this?
+            pairequal(parent1, blocks1, child)
+            pairequal(parent2, blocks2, child)
+
+            if skipchild:
+                # Note that if we change to prefer p2 over p1 for matched
+                # blocks, we'd want to reverse blocks2 and blocks1 here.
+                pairunequal(childfctx, parent2, blocks2, child)
+                pairunequal(childfctx, parent1, blocks1, child)
+
             return child
 
         getlog = util.lrucachefunc(lambda x: self._repo.file(x))
@@ -1053,8 +1091,13 @@ class basefilectx(object):
             if ready:
                 visit.pop()
                 curr = decorate(f.data(), f)
+
+                skipchild = f.rev() == 4
+                if len(pl) == 1:
+                    curr = pair(f, hist[pl[0]], curr, skipchild)
+                elif len(pl) == 2:
+                    curr = pair2(f, hist[pl[0]], hist[pl[1]], curr, skipchild)
                 for p in pl:
-                    curr = pair(hist[p], curr)
                     if needed[p] == 1:
                         del hist[p]
                         del needed[p]


More information about the Mercurial-devel mailing list