git » git-arr » commit 722d765

markdown: Handle local links

author Alberto Bertogli
2018-03-04 20:53:35 UTC
committer Alberto Bertogli
2018-03-04 20:53:35 UTC
parent 5e75a1e7a10a0485f5aa339abf055bad94a0a353

markdown: Handle local links

By default, the markdown generator creates links for local files
transparently. For example, "[text](link.md)" will generate
"<a href=link.md>text</a>".

This works fine for absolute and external links, but breaks for links
relative to the repository itself, as git-arr links are of the form
"dir/f=file.ext.html".

So this patch adds a markdown extension to rewrite the links. It uses a
heuristic to detect them, which should work for the vast majority of
common cases.

utils.py +41 -0

diff --git a/utils.py b/utils.py
index 008f11a..ada9c7e 100644
--- a/utils.py
+++ b/utils.py
@@ -14,12 +14,14 @@ except ImportError:
 
 try:
     import markdown
+    import markdown.treeprocessors
 except ImportError:
     markdown = None
 
 import base64
 import mimetypes
 import string
+import os.path
 
 def shorten(s, width = 60):
     if len(s) < 60:
@@ -100,6 +102,7 @@ def markdown_blob(s):
     extensions = [
         "markdown.extensions.fenced_code",
         "markdown.extensions.tables",
+        RewriteLocalLinksExtension(),
     ]
     return markdown.markdown(s, extensions = extensions)
 
@@ -122,3 +125,41 @@ def hexdump(s):
         yield offset, ' '.join(hexvals[:8]), ' '.join(hexvals[8:]), text
         offset += 16
         s = s[16:]
+
+
+if markdown:
+    class RewriteLocalLinks(markdown.treeprocessors.Treeprocessor):
+        """Rewrites relative links to files, to match git-arr's links.
+
+        A link of "[example](a/file.md)" will be rewritten such that it links to
+        "a/f=file.md.html".
+
+        Note that we're already assuming a degree of sanity in the HTML, so we
+        don't re-check that the path is reasonable.
+        """
+        def run(self, root):
+            for child in root:
+                if child.tag == "a":
+                    self.rewrite_href(child)
+
+                # Continue recursively.
+                self.run(child)
+
+        def rewrite_href(self, tag):
+            """Rewrite an <a>'s href."""
+            target = tag.get("href")
+            if not target:
+                return
+            if "://" in target or target.startswith("/"):
+                return
+
+            head, tail = os.path.split(target)
+            new_target = os.path.join(head, "f=" + tail + ".html")
+            tag.set("href", new_target)
+
+
+    class RewriteLocalLinksExtension(markdown.Extension):
+        def extendMarkdown(self, md, md_globals):
+            md.treeprocessors.add(
+                    "RewriteLocalLinks", RewriteLocalLinks(), "_end")
+