From 862e27c9e40be18fb411193631828b101791943c Mon Sep 17 00:00:00 2001
From: Zhiming Wang <zmwangx@gmail.com>
Date: Thu, 14 May 2015 20:57:01 -0700
Subject: add source code line numbers

The way I handle line numbers and the pre block in general is inspired
by the MDN wiki. See, for instance,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript
a screenshot is here: https://i.imgur.com/982TBDc.png

Also tweaked other styles, e.g., changed the primary monospace font to
Consolas, and slightly tweaked a few old posts.
---
 pyblog | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

(limited to 'pyblog')

diff --git a/pyblog b/pyblog
index 42694cba..add06650 100755
--- a/pyblog
+++ b/pyblog
@@ -54,6 +54,7 @@ ATOM = os.path.join(BUILDDIR, "atom.xml")
 INDEXHTML = os.path.join(BUILDDIR, "index.html")
 
 FEED_MAX_ENTRIES = 20
+CODE_LINE_HEIGHT = 18
 ####################### END OF GENERATOR CONFIGURATIONS ########################
 
 
@@ -409,6 +410,38 @@ def generate_index_and_feed():
     generate_sitemap(feed)
 
 
+def _pre_tag_insert_line_numbers(soup, pre_tag):
+    """Insert line numbers to a pre tag."""
+    num_lines = len(pre_tag.text.split("\n"))
+    for line_number in range(1, num_lines + 1):
+        # line number divs will look like:
+        # <span class="line-number" data-line="1" style="top: 0px"><!----></span>
+        # <span class="line-number" data-line="2" style="top: 18px"><!----></span>
+        ln_tag = soup.new_tag("span")
+        ln_tag["class"] = "line-number"
+        ln_tag["data-line"] = line_number
+        ln_tag["style"] = "top: %dpx" % ((line_number - 1) * CODE_LINE_HEIGHT)
+        ln_tag.append(soup.new_string("", bs4.Comment))
+        pre_tag.code.append(ln_tag)
+
+
+def number_code_lines(htmlfilepath):
+    """Insert line numbers to preformatted code blocks."""
+    with open(htmlfilepath, "r+", encoding="utf-8") as htmlfileobj:
+        soup = bs4.BeautifulSoup(htmlfileobj.read())
+        for pre_tag in soup.find_all("pre"):
+            if ((pre_tag.code is None or "class" not in pre_tag.attrs or
+                 not "sourceCode" in pre_tag["class"])):
+                # not really a block of source code
+                continue
+            _pre_tag_insert_line_numbers(soup, pre_tag)
+
+        # write back
+        htmlfileobj.seek(0)
+        htmlfileobj.write(str(soup))
+        htmlfileobj.truncate()
+
+
 def generate_blog(fresh=False, report_total_errors=True):
     """Generate the blog in BUILDDIR.
 
@@ -503,8 +536,11 @@ def generate_blog(fresh=False, report_total_errors=True):
                         failed_builds += 1
                         sys.stderr.write("error: failed to generate %s" %
                                          relpath)
+                    number_code_lines(dstpath)
+
     if anything_modified:
         generate_index_and_feed()
+        sys.stderr.write("done\n")
 
     if report_total_errors:
         sys.stderr.write("build finished with %d errors\n" % failed_builds)
-- 
cgit v1.2.1