Patchwork [2,of,4,V6] hgweb: display blamed revision once per block in annotate view

login
register
mail settings
Submitter Denis Laxalde
Date June 16, 2016, 1:58 p.m.
Message ID <8829839dfd23c9caa5f3.1466085497@sh77.tls.logilab.fr>
Download mbox | patch
Permalink /patch/15527/
State Accepted
Delegated to: Pierre-Yves David
Headers show

Comments

Denis Laxalde - June 16, 2016, 1:58 p.m.
# HG changeset patch
# User Denis Laxalde <denis.laxalde@logilab.fr>
# Date 1465294201 -7200
#      Tue Jun 07 12:10:01 2016 +0200
# Node ID 8829839dfd23c9caa5f368a7367559a6bc3593bb
# Parent  6ef96d3a3dc685edabc0f5ef653c31d9fece2916
hgweb: display blamed revision once per block in annotate view

I.e. when a revision blames a block of source lines, only display the
revision link on the first line of the block (this is identified by the
"blockhead" key in annotate context).

This addresses item "Visual grouping of changesets" of the blame improvements
plan (https://www.mercurial-scm.org/wiki/BlamePlan) which states: "Typically
there are block of lines all attributed to the same revision. Instead of
rendering the revision/changeset for every line, we could only render it once
per block."
Anton Shestakov - June 21, 2016, 3:17 p.m.
16.06.2016, 21:58, "Denis Laxalde" <denis.laxalde@logilab.fr>:
> diff --git a/mercurial/templates/gitweb/map b/mercurial/templates/gitweb/map
> --- a/mercurial/templates/gitweb/map
> +++ b/mercurial/templates/gitweb/map
> @@ -97,8 +97,10 @@ fileline = '
>  annotateline = '
>    <tr id="{lineid}" style="font-family:monospace" class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
>      <td class="linenr" style="text-align: right;">
> - <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
> - title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
> + {if(blockhead,
> + '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
> + title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
> + '')}

The empty string could be omitted, as `hg help templates` say: "if(expr, then[, else])".

(That's a nitpick that may or may not be fixed in-flight)

Other than this, series LGTM.
Yuya Nishihara - June 24, 2016, 12:39 p.m.
On Thu, 16 Jun 2016 15:58:17 +0200, Denis Laxalde wrote:
> # HG changeset patch
> # User Denis Laxalde <denis.laxalde@logilab.fr>
> # Date 1465294201 -7200
> #      Tue Jun 07 12:10:01 2016 +0200
> # Node ID 8829839dfd23c9caa5f368a7367559a6bc3593bb
> # Parent  6ef96d3a3dc685edabc0f5ef653c31d9fece2916
> hgweb: display blamed revision once per block in annotate view

> --- a/mercurial/hgweb/webcommands.py
> +++ b/mercurial/hgweb/webcommands.py
> @@ -872,14 +872,19 @@ def annotate(web, req, tmpl):
>          else:
>              lines = enumerate(fctx.annotate(follow=True, linenumber=True,
>                                              diffopts=diffopts))
> +        previousrev = None
>          for lineno, ((f, targetline), l) in lines:
> +            rev = f.rev()
> +            blockhead = rev != previousrev or None

Just a random thought, but if blockhead is the number of lines in that block,
it could be used as a rowspan value.
Gregory Szorc - June 25, 2016, 12:22 a.m.
On Fri, Jun 24, 2016 at 5:39 AM, Yuya Nishihara <yuya@tcha.org> wrote:

> On Thu, 16 Jun 2016 15:58:17 +0200, Denis Laxalde wrote:
> > # HG changeset patch
> > # User Denis Laxalde <denis.laxalde@logilab.fr>
> > # Date 1465294201 -7200
> > #      Tue Jun 07 12:10:01 2016 +0200
> > # Node ID 8829839dfd23c9caa5f368a7367559a6bc3593bb
> > # Parent  6ef96d3a3dc685edabc0f5ef653c31d9fece2916
> > hgweb: display blamed revision once per block in annotate view
>
> > --- a/mercurial/hgweb/webcommands.py
> > +++ b/mercurial/hgweb/webcommands.py
> > @@ -872,14 +872,19 @@ def annotate(web, req, tmpl):
> >          else:
> >              lines = enumerate(fctx.annotate(follow=True,
> linenumber=True,
> >                                              diffopts=diffopts))
> > +        previousrev = None
> >          for lineno, ((f, targetline), l) in lines:
> > +            rev = f.rev()
> > +            blockhead = rev != previousrev or None
>
> Just a random thought, but if blockhead is the number of lines in that
> block,
> it could be used as a rowspan value.
>

And this could potentially be combined with some CSS/JS foo so the text
never scrolls out of window if you e.g. have a block hundreds of lines
long. Alternatively, we could ensure there is a link every N rows (you
shouldn't need to scroll to find a link).

Patch

diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -872,14 +872,19 @@  def annotate(web, req, tmpl):
         else:
             lines = enumerate(fctx.annotate(follow=True, linenumber=True,
                                             diffopts=diffopts))
+        previousrev = None
         for lineno, ((f, targetline), l) in lines:
+            rev = f.rev()
+            blockhead = rev != previousrev or None
+            previousrev = rev
             yield {"parity": next(parity),
                    "node": f.hex(),
-                   "rev": f.rev(),
+                   "rev": rev,
                    "author": f.user(),
                    "desc": f.description(),
                    "extra": f.extra(),
                    "file": f.path(),
+                   "blockhead": blockhead,
                    "targetline": targetline,
                    "line": l,
                    "lineno": lineno + 1,
diff --git a/mercurial/templates/gitweb/map b/mercurial/templates/gitweb/map
--- a/mercurial/templates/gitweb/map
+++ b/mercurial/templates/gitweb/map
@@ -97,8 +97,10 @@  fileline = '
 annotateline = '
   <tr id="{lineid}" style="font-family:monospace" class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
     <td class="linenr" style="text-align: right;">
-      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
+      {if(blockhead,
+          '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
+              title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
+          '')}
     </td>
     <td><pre><a class="linenr" href="#{lineid}">{linenumber}</a></pre></td>
     <td><pre>{line|escape}</pre></td>
diff --git a/mercurial/templates/monoblue/map b/mercurial/templates/monoblue/map
--- a/mercurial/templates/monoblue/map
+++ b/mercurial/templates/monoblue/map
@@ -93,8 +93,10 @@  fileline = '
 annotateline = '
   <tr id="{lineid}" class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
     <td class="linenr">
-      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
+      {if(blockhead,
+          '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
+              title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
+          '')}
     </td>
     <td class="lineno">
       <a href="#{lineid}">{linenumber}</a>
diff --git a/mercurial/templates/paper/map b/mercurial/templates/paper/map
--- a/mercurial/templates/paper/map
+++ b/mercurial/templates/paper/map
@@ -78,8 +78,10 @@  filelogentry = filelogentry.tmpl
 annotateline = '
   <tr id="{lineid}"{ifeq(node, originalnode, ' class="thisrev"')}>
     <td class="annotate">
-      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
+      {if(blockhead,
+          '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
+              title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
+          '')}
     </td>
     <td class="source"><a href="#{lineid}">{linenumber}</a> {line|escape}</td>
   </tr>'
diff --git a/mercurial/templates/spartan/map b/mercurial/templates/spartan/map
--- a/mercurial/templates/spartan/map
+++ b/mercurial/templates/spartan/map
@@ -56,8 +56,10 @@  filelogentry = filelogentry.tmpl
 annotateline = '
   <tr class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
     <td class="annotate">
-      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
+      {if(blockhead,
+          '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
+              title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
+          '')}
     </td>
     <td>
       <a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>
diff --git a/tests/test-highlight.t b/tests/test-highlight.t
--- a/tests/test-highlight.t
+++ b/tests/test-highlight.t
@@ -297,225 +297,193 @@  hgweb fileannotate, html
   </tr>
   <tr id="l2" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l2"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l2">     2</a> </td>
   </tr>
   <tr id="l3" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l3"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l3">     3</a> <span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></td>
   </tr>
   <tr id="l4" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l4"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l4">     4</a> </td>
   </tr>
   <tr id="l5" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l5"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l5">     5</a> <span class="sd">primes = 2 : sieve [3, 5..]</span></td>
   </tr>
   <tr id="l6" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l6"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l6">     6</a> <span class="sd">    where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></td>
   </tr>
   <tr id="l7" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l7"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l7">     7</a> <span class="sd">&quot;&quot;&quot;</span></td>
   </tr>
   <tr id="l8" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l8"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l8">     8</a> </td>
   </tr>
   <tr id="l9" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l9"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l9">     9</a> <span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">ifilter</span><span class="p">,</span> <span class="n">islice</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">chain</span></td>
   </tr>
   <tr id="l10" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l10"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l10">    10</a> </td>
   </tr>
   <tr id="l11" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l11"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l11">    11</a> <span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></td>
   </tr>
   <tr id="l12" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l12"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l12">    12</a>     <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></td>
   </tr>
   <tr id="l13" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l13"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l13">    13</a>     <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
   </tr>
   <tr id="l14" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l14"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l14">    14</a>         <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></td>
   </tr>
   <tr id="l15" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l15"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l15">    15</a>         <span class="c"># It is important to yield *here* in order to stop the</span></td>
   </tr>
   <tr id="l16" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l16"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l16">    16</a>         <span class="c"># infinite recursion.</span></td>
   </tr>
   <tr id="l17" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l17"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l17">    17</a>         <span class="kn">yield</span> <span class="n">p</span></td>
   </tr>
   <tr id="l18" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l18"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l18">    18</a>         <span class="n">ns</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></td>
   </tr>
   <tr id="l19" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l19"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l19">    19</a>         <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
   </tr>
   <tr id="l20" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l20"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l20">    20</a>             <span class="kn">yield</span> <span class="n">n</span></td>
   </tr>
   <tr id="l21" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l21"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l21">    21</a> </td>
   </tr>
   <tr id="l22" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l22"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l22">    22</a>     <span class="n">odds</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></td>
   </tr>
   <tr id="l23" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l23"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l23">    23</a>     <span class="kn">return</span> <span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></td>
   </tr>
   <tr id="l24" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l24"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l24">    24</a> </td>
   </tr>
   <tr id="l25" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l25"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l25">    25</a> <span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></td>
   </tr>
   <tr id="l26" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l26"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l26">    26</a>     <span class="kn">import</span> <span class="nn">sys</span></td>
   </tr>
   <tr id="l27" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l27"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l27">    27</a>     <span class="kn">try</span><span class="p">:</span></td>
   </tr>
   <tr id="l28" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l28"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l28">    28</a>         <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></td>
   </tr>
   <tr id="l29" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l29"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l29">    29</a>     <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></td>
   </tr>
   <tr id="l30" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l30"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l30">    30</a>         <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></td>
   </tr>
   <tr id="l31" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l31"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l31">    31</a>     <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></td>
   </tr>
   <tr id="l32" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l32"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l32">    32</a>     <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></td>
   </tr>
   <tr id="l33" class="thisrev">
   <td class="annotate">
-  <a href="/annotate/06824edf55d0/primes.py#l33"
-  title="06824edf55d0: a">test@0</a>
+  
   </td>
   <td class="source"><a href="#l33">    33</a> </td>
   </tr>