[PATCH] Add line anchors to annotate, changeset, diff, file views for hgweb

Edward Lee edilee at mozilla.com
Tue Sep 4 23:37:57 CDT 2007


This patch makes the line numbers into anchor tags with an id to link
to itself. The default and gitweb templates are updated to have
clickable line numbers for annotate, changeset, diff, and file views.

hgweb's ability to show the whole repository for any given changeset
is really useful, but it would be nice if we could refer to a
particular line of a file or changeset (such as for a bug report or
discussing a patch). This patch adds a couple new template-vars such
as lineid and linenumber.

-- Patch comments --

Refactored the |yield self.t()| do save on duplicate calls with the
same arguments.
http://74.136.196.179:8080/rev/5447b7e5ba45#l1.25

For changesets (and single file diffs), it'll only use the
"block.line" notation for the second block on. This makes single file
diffs nicer while keeping changeset views clean.
http://74.136.196.179:8080/rev/5447b7e5ba45#l1.21

I renamed the l variable to lineno to keep it consistent with the
other code blocks.
http://74.136.196.179:8080/rev/5447b7e5ba45#l1.48

Both the default and gitweb templates are edited in the patch, but
they can be easily removed if we want to leave it to the end user to
decide if they want linkable line numbers for diffs/changesets and
annotate. I would recommend it on by default for file views though.
http://74.136.196.179:8080/rev/5447b7e5ba45#l3.1
http://74.136.196.179:8080/rev/5447b7e5ba45#l2.1

Ed
-------------- next part --------------
# HG changeset patch
# User Edward Lee <edward.lee at engineering.uiuc.edu>
# Date 1188962737 18000
# Node ID 5447b7e5ba45915da3aa86fb23bf86476e25142b
# Parent  4fe04b183fd83ec6ba9b8c8f014329064761e36c
Add line anchors to annotate, changeset, diff, file views for hgweb

diff --git a/mercurial/hgweb/common.py b/mercurial/hgweb/common.py
--- a/mercurial/hgweb/common.py
+++ b/mercurial/hgweb/common.py
@@ -76,3 +76,9 @@ def paritygen(stripecount, offset=0):
             parity = 1 - parity
             count = 0
 
+def countgen(start=0, step=1):
+    """count forever -- useful for line numbers"""
+    while True:
+        yield start
+        start += step
+
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -12,7 +12,7 @@ from mercurial.i18n import gettext as _
 from mercurial.i18n import gettext as _
 from mercurial import mdiff, ui, hg, util, archival, streamclone, patch
 from mercurial import revlog, templater
-from common import get_mtime, staticfile, style_map, paritygen
+from common import get_mtime, staticfile, style_map, paritygen, countgen
 
 def _up(p):
     if p[0] != "/":
@@ -166,16 +166,25 @@ class hgweb(object):
                          file=f,
                          filenode=hex(fn or nullid))
 
+        blockcount = countgen()
         def prettyprintlines(diff):
-            for l in diff.splitlines(1):
+            blockno = blockcount.next()
+            for lineno, l in enumerate(diff.splitlines(1)):
+                if blockno == 0:
+                    lineno = lineno + 1
+                else:
+                    lineno = "%d.%d" % (blockno, lineno + 1)
+                type = "diffline"
                 if l.startswith('+'):
-                    yield self.t("difflineplus", line=l)
+                    type = "difflineplus"
                 elif l.startswith('-'):
-                    yield self.t("difflineminus", line=l)
+                    type = "difflineminus"
                 elif l.startswith('@'):
-                    yield self.t("difflineat", line=l)
-                else:
-                    yield self.t("diffline", line=l)
+                    type = "difflineat"
+                yield self.t(type,
+                             line=l,
+                             lineid="l%s" % lineno,
+                             linenumber="% 8s" % lineno)
 
         r = self.repo
         c1 = r.changectx(node1)
@@ -394,9 +403,10 @@ class hgweb(object):
         mt = mt or 'text/plain'
 
         def lines():
-            for l, t in enumerate(text.splitlines(1)):
+            for lineno, t in enumerate(text.splitlines(1)):
                 yield {"line": t,
-                       "linenumber": "% 6d" % (l + 1),
+                       "lineid": "l%d" % (lineno + 1),
+                       "linenumber": "% 6d" % (lineno + 1),
                        "parity": parity.next()}
 
         yield self.t("filerevision",
@@ -423,7 +433,7 @@ class hgweb(object):
 
         def annotate(**map):
             last = None
-            for f, l in fctx.annotate(follow=True):
+            for lineno, (f, l) in enumerate(fctx.annotate(follow=True)):
                 fnode = f.filenode()
                 name = self.repo.ui.shortuser(f.user())
 
@@ -435,7 +445,9 @@ class hgweb(object):
                        "rev": f.rev(),
                        "author": name,
                        "file": f.path(),
-                       "line": l}
+                       "line": l,
+                       "lineid": "l%d" % (lineno + 1),
+                       "linenumber": "% 6d" % (lineno + 1)}
 
         yield self.t("fileannotate",
                      file=f,
diff --git a/templates/gitweb/map b/templates/gitweb/map
--- a/templates/gitweb/map
+++ b/templates/gitweb/map
@@ -22,12 +22,12 @@ fileannotate = fileannotate.tmpl
 fileannotate = fileannotate.tmpl
 filediff = filediff.tmpl
 filelog = filelog.tmpl
-fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr">   #linenumber#</span> #line|escape#</pre></div>'
-annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
-difflineplus = '<div style="color:#008800;">#line|escape#</div>'
-difflineminus = '<div style="color:#cc0000;">#line|escape#</div>'
-difflineat = '<div style="color:#990099;">#line|escape#</div>'
-diffline = '<div>#line|escape#</div>'
+fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><a class="linenr" href="##lineid#" id="#lineid#">#linenumber#</a> #line|escape#</pre></div>'
+annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre><a class="linenr" href="##lineid#" id="#lineid#">#linenumber#</a></pre></td><td><pre>#line|escape#</pre></td></tr>'
+difflineplus = '<div style="color:#008800;"><a class="linenr" href="##lineid#" id="#lineid#">#linenumber#</a> #line|escape#</div>'
+difflineminus = '<div style="color:#cc0000;"><a class="linenr" href="##lineid#" id="#lineid#">#linenumber#</a> #line|escape#</div>'
+difflineat = '<div style="color:#990099;"><a class="linenr" href="##lineid#" id="#lineid#">#linenumber#</a> #line|escape#</div>'
+diffline = '<div><a class="linenr" href="##lineid#" id="#lineid#">#linenumber#</a> #line|escape#</div>'
 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
 changesetparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
 filerevparent = '<tr><td>parent {rev}</td><td style="font-family:monospace"><a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
diff --git a/templates/map b/templates/map
--- a/templates/map
+++ b/templates/map
@@ -21,13 +21,13 @@ fileannotate = fileannotate.tmpl
 fileannotate = fileannotate.tmpl
 filediff = filediff.tmpl
 filelog = filelog.tmpl
-fileline = '<div class="parity#parity#"><span class="lineno">#linenumber#</span>#line|escape#</div>'
+fileline = '<div class="parity#parity#"><a class="lineno" href="##lineid#" id="#lineid#">#linenumber#</a>#line|escape#</div>'
 filelogentry = filelogentry.tmpl
-annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
-difflineplus = '<span class="plusline">#line|escape#</span>'
-difflineminus = '<span class="minusline">#line|escape#</span>'
-difflineat = '<span class="atline">#line|escape#</span>'
-diffline = '#line|escape#'
+annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><a class="lineno" href="##lineid#" id="#lineid#">#linenumber#</a></td><td><pre>#line|escape#</pre></td></tr>'
+difflineplus = '<span class="plusline"><a class="lineno" href="##lineid#" id="#lineid#">#linenumber#</a>#line|escape#</span>'
+difflineminus = '<span class="minusline"><a class="lineno" href="##lineid#" id="#lineid#">#linenumber#</a>#line|escape#</span>'
+difflineat = '<span class="atline"><a class="lineno" href="##lineid#" id="#lineid#">#linenumber#</a>#line|escape#</span>'
+diffline = '<a class="lineno" href="##lineid#" id="#lineid#">#linenumber#</a>#line|escape#'
 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
 changesetparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'


More information about the Mercurial mailing list