[PATCH STABLE] highlight: produce correct markup when there's a blank line just before EOF

Anton Shestakov av6 at dwimlabs.net
Tue Jul 21 21:34:30 CDT 2015


# HG changeset patch
# User Anton Shestakov <av6 at dwimlabs.net>
# Date 1437531557 -28800
#      Wed Jul 22 10:19:17 2015 +0800
# Branch stable
# Node ID 37b7468d51470aa52068a37aae8795b84824baaf
# Parent  a2d178b3a1b4227e5e7d48d2b3fa5ab1171ca59b
highlight: produce correct markup when there's a blank line just before EOF

Due to how the colorized output from pygments was stripped of <pre> elements,
when there was an empty line at the end of a file, highlight extension produced
an incorrect markup (no closing tags from the fileline/annotateline template).
It wasn't usually noticeable, because browsers were smart enough to see where
the missing tags should've been, but in monoblue style it resulted in the last
line having twice the normal height.

Instead of awkwardly trying to strip outer <pre></pre> tags, let's make the
formatter with nowrap=True, which should do what we need in pygments since at
least 0.5 (2006-10-30).

Example from monoblue style:

Before:

    <div class="source">

<div style="font-family:monospace" class="parity0">
<pre><a class="linenr" href="#l1" id="l1">     1</a> </pre>
</div>
<div style="font-family:monospace" class="parity1">
<pre><a class="linenr" href="#l2" id="l2">     2</a>
    </div>

Now:

    <div class="source">

<div style="font-family:monospace" class="parity0">
<pre><a class="linenr" href="#l1" id="l1">     1</a> </pre>
</div>
<div style="font-family:monospace" class="parity1">
<pre><a class="linenr" href="#l2" id="l2">     2</a> </pre>
</div>
    </div>

(Notice the missing </pre></div> now in place)

diff --git a/hgext/highlight/highlight.py b/hgext/highlight/highlight.py
--- a/hgext/highlight/highlight.py
+++ b/hgext/highlight/highlight.py
@@ -51,12 +51,9 @@ def pygmentize(field, fctx, style, tmpl)
         except (ClassNotFound, ValueError):
             lexer = TextLexer(stripnl=False)
 
-    formatter = HtmlFormatter(style=style)
+    formatter = HtmlFormatter(nowrap=True, style=style)
 
     colorized = highlight(text, lexer, formatter)
-    # strip wrapping div
-    colorized = colorized[:colorized.find('\n</pre>')]
-    colorized = colorized[colorized.find('<pre>') + 5:]
     coloriter = (s.encode(encoding.encoding, 'replace')
                  for s in colorized.splitlines())
 
diff --git a/tests/test-highlight.t b/tests/test-highlight.t
--- a/tests/test-highlight.t
+++ b/tests/test-highlight.t
@@ -45,6 +45,7 @@ create random Python file to exercise Py
   >     p = primes()
   >     print "The first %d primes: %s" % (n, list(islice(p, n)))
   > EOF
+  $ echo >> primes.py  # to test html markup with an empty line just before EOF
   $ hg ci -Ama
   adding primes.py
 
@@ -68,7 +69,7 @@ hgweb filerevision, html
   <script type="text/javascript" src="/static/mercurial.js"></script>
   
   <link rel="stylesheet" href="/highlightcss" type="text/css" />
-  <title>test: 853dcd4de2a6 primes.py</title>
+  <title>test: 06824edf55d0 primes.py</title>
   </head>
   <body>
   
@@ -106,7 +107,7 @@ hgweb filerevision, html
   <div class="main">
   <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
   <h3>
-   view primes.py @ 0:<a href="/rev/853dcd4de2a6">853dcd4de2a6</a>
+   view primes.py @ 0:<a href="/rev/06824edf55d0">06824edf55d0</a>
    <span class="tag">tip</span> 
   </h3>
   
@@ -173,7 +174,8 @@ hgweb filerevision, html
   <span id="l29">    <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></span><a href="#l29"></a>
   <span id="l30">        <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></span><a href="#l30"></a>
   <span id="l31">    <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></span><a href="#l31"></a>
-  <span id="l32">    <span class="kn">print</span> <span class="s">"The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">"</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></span><a href="#l32"></a></pre>
+  <span id="l32">    <span class="kn">print</span> <span class="s">"The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">"</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></span><a href="#l32"></a>
+  <span id="l33"></span><a href="#l33"></a></pre>
   <div class="sourcelast"></div>
   </div>
   </div>
@@ -240,7 +242,7 @@ hgweb fileannotate, html
   <div class="main">
   <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
   <h3>
-   annotate primes.py @ 0:<a href="/rev/853dcd4de2a6">853dcd4de2a6</a>
+   annotate primes.py @ 0:<a href="/rev/06824edf55d0">06824edf55d0</a>
    <span class="tag">tip</span> 
   </h3>
   
@@ -284,228 +286,235 @@ hgweb fileannotate, html
     
   <tr id="l1">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l1"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l1"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l1">     1</a> <span class="c">#!/usr/bin/env python</span></td>
   </tr>
   <tr id="l2">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l2"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l2"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l2">     2</a> </td>
   </tr>
   <tr id="l3">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l3"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l3"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l3">     3</a> <span class="sd">"""Fun with generators. Corresponding Haskell implementation:</span></td>
   </tr>
   <tr id="l4">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l4"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l4"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l4">     4</a> </td>
   </tr>
   <tr id="l5">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l5"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l5"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l6"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l6"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l6">     6</a> <span class="sd">    where sieve (p:ns) = p : sieve [n | n <- ns, mod n p /= 0]</span></td>
   </tr>
   <tr id="l7">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l7"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l7"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l7">     7</a> <span class="sd">"""</span></td>
   </tr>
   <tr id="l8">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l8"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l8"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l8">     8</a> </td>
   </tr>
   <tr id="l9">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l9"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l9"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l10"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l10"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l10">    10</a> </td>
   </tr>
   <tr id="l11">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l11"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l11"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l12"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l12"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l12">    12</a>     <span class="sd">"""Generate all primes."""</span></td>
   </tr>
   <tr id="l13">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l13"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l13"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l14"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l14"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l15"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l15"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l16"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l16"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l16">    16</a>         <span class="c"># infinite recursion.</span></td>
   </tr>
   <tr id="l17">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l17"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l17"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l18"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l18"
+  title="06824edf55d0: a">test at 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="mf">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></td>
   </tr>
   <tr id="l19">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l19"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l19"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l20"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l20"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l21"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l21"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l21">    21</a> </td>
   </tr>
   <tr id="l22">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l22"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l22"
+  title="06824edf55d0: a">test at 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="mf">2</span> <span class="o">==</span> <span class="mf">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></td>
   </tr>
   <tr id="l23">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l23"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l23"
+  title="06824edf55d0: a">test at 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="mf">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"><</span> <span class="mf">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></td>
   </tr>
   <tr id="l24">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l24"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l24"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l24">    24</a> </td>
   </tr>
   <tr id="l25">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l25"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l25"
+  title="06824edf55d0: a">test at 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">"__main__"</span><span class="p">:</span></td>
   </tr>
   <tr id="l26">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l26"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l26"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l27"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l27"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l28"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l28"
+  title="06824edf55d0: a">test at 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="mf">1</span><span class="p">])</span></td>
   </tr>
   <tr id="l29">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l29"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l29"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l30"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l30"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l30">    30</a>         <span class="n">n</span> <span class="o">=</span> <span class="mf">10</span></td>
   </tr>
   <tr id="l31">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l31"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l31"
+  title="06824edf55d0: a">test at 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">
   <td class="annotate">
-  <a href="/annotate/853dcd4de2a6/primes.py#l32"
-  title="853dcd4de2a6: a">test at 0</a>
+  <a href="/annotate/06824edf55d0/primes.py#l32"
+  title="06824edf55d0: a">test at 0</a>
   </td>
   <td class="source"><a href="#l32">    32</a>     <span class="kn">print</span> <span class="s">"The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">"</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">
+  <td class="annotate">
+  <a href="/annotate/06824edf55d0/primes.py#l33"
+  title="06824edf55d0: a">test at 0</a>
+  </td>
+  <td class="source"><a href="#l33">    33</a> </td>
+  </tr>
   </tbody>
   </table>
   </div>


More information about the Mercurial-devel mailing list