aboutsummaryrefslogtreecommitdiffstats
path: root/filters/html-converters/md2html
diff options
context:
space:
mode:
Diffstat (limited to 'filters/html-converters/md2html')
-rwxr-xr-xfilters/html-converters/md2html55
1 files changed, 55 insertions, 0 deletions
diff --git a/filters/html-converters/md2html b/filters/html-converters/md2html
index de393c7..faa71f3 100755
--- a/filters/html-converters/md2html
+++ b/filters/html-converters/md2html
@@ -2,8 +2,62 @@
import markdown
import sys
import io
+import re
from pygments.formatters import HtmlFormatter
from markdown.extensions.toc import TocExtension
+from markdown.extensions import Extension
+from markdown.preprocessors import Preprocessor
+
+# Python-Markdown (unlike CommonMark/GitHub) refuses to let a list interrupt a
+# paragraph unless there's a blank line between them, so a very common README
+# shape renders as one run-on paragraph instead of a list:
+#
+# Passing:
+# - foo
+# - bar
+#
+# This preprocessor restores the GitHub behavior: when a bullet ( - * + ) or a
+# "1."/"1)" ordered-list marker immediately follows a paragraph line, insert a
+# blank line so the list starts. We deliberately only interrupt on "1" for
+# ordered lists (matching CommonMark) so prose like "... the year\n1985. was
+# ..." is not turned into a list. Fenced code, indented code, and lines that
+# already follow a list item are left untouched.
+_MD_FENCE = re.compile(r'^(\s{0,3})(`{3,}|~{3,})')
+_MD_BULLET = re.compile(r'^ {0,3}[-*+][ \t]+\S')
+_MD_ORDERED1 = re.compile(r'^ {0,3}1[.)][ \t]+\S')
+_MD_ANYITEM = re.compile(r'^ {0,3}(?:[-*+]|\d{1,9}[.)])[ \t]')
+
+
+class _ListInterruptPreprocessor(Preprocessor):
+ def run(self, lines):
+ out, in_fence, fence = [], False, None
+ for line in lines:
+ m = _MD_FENCE.match(line)
+ if m:
+ tok = m.group(2)[0]
+ if not in_fence:
+ in_fence, fence = True, tok
+ elif fence == tok:
+ in_fence, fence = False, None
+ out.append(line)
+ continue
+ if not in_fence and out:
+ prev = out[-1]
+ if (prev.strip() and not _MD_ANYITEM.match(prev)
+ and not prev.startswith((' ', '\t'))
+ and (_MD_BULLET.match(line) or _MD_ORDERED1.match(line))):
+ out.append('')
+ out.append(line)
+ return out
+
+
+class ListInterruptExtension(Extension):
+ def extendMarkdown(self, md):
+ # priority 21: just above the built-in 'normalize_whitespace' (20) so we
+ # operate on clean lines before block parsing.
+ md.preprocessors.register(
+ _ListInterruptPreprocessor(md), 'list_interrupt', 21)
+
sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stdout.write('''
@@ -298,6 +352,7 @@ html = markdown.markdown(
"markdown.extensions.codehilite",
"markdown.extensions.tables",
"markdown.extensions.sane_lists",
+ ListInterruptExtension(),
TocExtension(anchorlink=True)],
extension_configs={
"markdown.extensions.codehilite":{"css_class":"highlight"}})