Patchwork [hyperblame] annotate: allow skipping revs

login
register
mail settings
Submitter Siddharth Agarwal
Date May 23, 2017, 12:27 a.m.
Message ID <c14a092fcb1184b5961d.1495499256@devvm31800.prn1.facebook.com>
Download mbox | patch
Permalink /patch/20855/
State Superseded
Headers show

Comments

Siddharth Agarwal - May 23, 2017, 12:27 a.m.
# HG changeset patch
# User Siddharth Agarwal <sid0@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.
Siddharth Agarwal - May 23, 2017, 12:32 a.m.
On 5/22/17 17:27, Siddharth Agarwal wrote:
> # HG changeset patch
> # User Siddharth Agarwal <sid0@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.

Forgot to flag this as WIP -- this is totally WIP at the moment.

The heuristic we use here is very simple. Once this lands, if necessary 
we can iterate on it.


>
> 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]
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Patch

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]