From 687238ca992ae68ed859fc9071bd044e045f1987 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Wed, 30 Jan 2019 09:48:34 -0600 Subject: [PATCH 01/17] Started python-markdown support --- recommonmark/parser.py | 198 +++++++++++++++++++++++++++++++++++++++++ tests/test_new.py | 47 ++++++++++ 2 files changed, 245 insertions(+) create mode 100644 tests/test_new.py diff --git a/recommonmark/parser.py b/recommonmark/parser.py index 857aded..7b9c2b8 100644 --- a/recommonmark/parser.py +++ b/recommonmark/parser.py @@ -10,6 +10,9 @@ from warnings import warn +from markdown import markdown +from html.parser import HTMLParser + if sys.version_info < (3, 0): from urlparse import urlparse else: @@ -35,19 +38,214 @@ def parse(self, inputstring, document): self.setup_sections() parser = Parser() ast = parser.parse(inputstring + '\n') + html = markdown(inputstring + '\n', extensions=[ + 'extra', + 'abbr', + 'attr_list', + 'def_list', + 'fenced_code', + 'footnotes', + 'tables', + 'admonition', + 'codehilite', + 'meta', + 'nl2br', + 'sane_lists', + 'smarty', + 'toc', + 'wikilinks' + ]) + self.convert_html(html) self.convert_ast(ast) self.finish_parse() + def convert_html(self, html): + class MyHTMLParser(HTMLParser): + def handle_starttag(_, tag, attrs): + fn_name = '_visit_' + tag + fn = getattr(self, fn_name) + fn(attrs) + def handle_endtag(_, tag): + fn_name = '_depart_' + tag + fn = getattr(self, fn_name) + fn() + def handle_data(_, data): + self._visit_text(data) + self._depart_text() + self._visit_document() + parser = MyHTMLParser() + parser.feed(html) + self._depart_document() + def convert_ast(self, ast): for (node, entering) in ast.walker(): fn_prefix = "visit" if entering else "depart" fn_name = "{0}_{1}".format(fn_prefix, node.t.lower()) fn_default = "default_{0}".format(fn_prefix) + print(fn_name) fn = getattr(self, fn_name, None) if fn is None: fn = getattr(self, fn_default) fn(node) + + def _visit_document(self): + print('visit document') + + def _depart_document(self): + print('depart document') + + def _visit_p(self, attrs): + print('visit p') + + def _depart_p(self): + print('depart p') + + def _visit_text(self, data): + print('visit text') + + def _depart_text(self): + print('depart text') + + def _visit_h1(self, data): + print('visit h1') + + def _depart_h1(self): + print('depart h1') + + def _visit_h2(self, data): + print('visit h2') + + def _depart_h2(self): + print('depart h2') + + def _visit_h3(self, data): + print('visit h3') + + def _depart_h3(self): + print('depart h3') + + def _visit_h4(self, data): + print('visit h4') + + def _depart_h4(self): + print('depart h4') + + def _visit_h5(self, data): + print('visit h5') + + def _depart_h5(self): + print('depart h5') + + def _visit_h6(self, data): + print('visit h6') + + def _depart_h6(self): + print('depart h6') + + def _visit_a(self, data): + print('visit a') + + def _depart_a(self): + print('depart a') + + def _visit_img(self, data): + print('visit img') + + def _depart_img(self): + print('depart img') + + def _visit_ul(self, data): + print('visit ul') + + def _depart_ul(self): + print('depart ul') + + def _visit_ol(self, data): + print('visit ol') + + def _depart_ol(self): + print('depart ol') + + def _visit_li(self, data): + print('visit li') + + def _depart_li(self): + print('depart li') + + def _visit_table(self, data): + print('visit table') + + def _depart_table(self): + print('depart table') + + def _visit_thead(self, data): + print('visit thead') + + def _depart_thead(self): + print('depart thead') + + def _visit_tbody(self, data): + print('visit tbody') + + def _depart_tbody(self): + print('depart tbody') + + def _visit_tr(self, data): + print('visit tr') + + def _depart_tr(self): + print('depart tr') + + def _visit_th(self, data): + print('visit th') + + def _depart_th(self): + print('depart th') + + def _visit_td(self, data): + print('visit td') + + def _depart_td(self): + print('depart td') + + def _visit_div(self, data): + print('visit div') + + def _depart_div(self): + print('depart div') + + def _visit_pre(self, data): + print('visit pre') + + def _depart_pre(self): + print('depart pre') + + def _visit_span(self, data): + print('visit span') + + def _depart_span(self): + print('depart span') + + def _visit_blockquote(self, data): + print('visit blockquote') + + def _depart_blockquote(self): + print('depart blockquote') + + def _visit_hr(self, data): + print('visit hr') + + def _depart_hr(self): + print('depart hr') + + def _visit_br(self, data): + print('visit br') + + def _depart_br(self): + print('depart br') + + # Node type enter/exit handlers def default_visit(self, mdnode): pass diff --git a/tests/test_new.py b/tests/test_new.py new file mode 100644 index 0000000..b8da3d1 --- /dev/null +++ b/tests/test_new.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +import unittest +from textwrap import dedent + +from docutils import nodes +from docutils.utils import new_document +from docutils.readers import Reader +from docutils.core import publish_parts + +from commonmark import Parser +from recommonmark.parser import CommonMarkParser + + +class TestParsing(unittest.TestCase): + + def assertParses(self, source, expected, alt=False): # noqa + parser = CommonMarkParser() + parser.parse(dedent(source), new_document('')) + self.assertMultiLineEqual( + dedent(expected).lstrip(), + dedent(parser.document.asdom().toprettyxml(indent=' ')), + ) + + def test_heading(self): + self.assertParses( + """ + --- + ___ + + one + two + + three + four + + """, + """ + + + hi + + """ + ) + +if __name__ == '__main__': + unittest.main() From 9fe159a04e7a1b6d20ff4adb08f39db8d08ce23b Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Thu, 31 Jan 2019 14:27:05 -0600 Subject: [PATCH 02/17] Started building node tree --- recommonmark/parser.py | 38 ++++++++++++++++++++++++++++++++++++-- tests/test_new.py | 9 +++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/recommonmark/parser.py b/recommonmark/parser.py index 7b9c2b8..6ae5ff9 100644 --- a/recommonmark/parser.py +++ b/recommonmark/parser.py @@ -3,6 +3,8 @@ import sys from os.path import splitext +import pydash as _ + from docutils import parsers, nodes from sphinx import addnodes @@ -56,7 +58,7 @@ def parse(self, inputstring, document): 'wikilinks' ]) self.convert_html(html) - self.convert_ast(ast) + # self.convert_ast(ast) self.finish_parse() def convert_html(self, html): @@ -89,6 +91,13 @@ def convert_ast(self, ast): fn(node) + def _visit_section(self): + print('visit section') + + def _depart_section(self): + print('depart section') + + def _visit_document(self): print('visit document') @@ -96,57 +105,82 @@ def _depart_document(self): print('depart document') def _visit_p(self, attrs): + paragraph = nodes.paragraph() + self.current_node.append(paragraph) + self.current_node = paragraph print('visit p') def _depart_p(self): + self.current_node = self.current_node.parent print('depart p') def _visit_text(self, data): + text = nodes.Text(data) + self.current_node.append(text) + self.current_node = text print('visit text') def _depart_text(self): + self.current_node = self.current_node.parent print('depart text') def _visit_h1(self, data): + self._visit_section() print('visit h1') def _depart_h1(self): + self._depart_section() print('depart h1') def _visit_h2(self, data): + self._visit_section() print('visit h2') def _depart_h2(self): + self._depart_section() print('depart h2') def _visit_h3(self, data): + self._visit_section() print('visit h3') def _depart_h3(self): + self._depart_section() print('depart h3') def _visit_h4(self, data): + self._visit_section() print('visit h4') def _depart_h4(self): + self._depart_section() print('depart h4') def _visit_h5(self, data): + self._visit_section() print('visit h5') def _depart_h5(self): + self._depart_section() print('depart h5') def _visit_h6(self, data): + self._visit_section() print('visit h6') def _depart_h6(self): + self._depart_section() print('depart h6') - def _visit_a(self, data): + def _visit_a(self, attrs): + reference = nodes.reference() + reference['refuri'] = _.find(attrs, lambda i: i[0] == 'href')[1] + self.current_node.append(reference) + self.current_node = reference print('visit a') def _depart_a(self): + self.current_node = self.current_node.parent print('depart a') def _visit_img(self, data): diff --git a/tests/test_new.py b/tests/test_new.py index b8da3d1..e66ed48 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -28,6 +28,15 @@ def test_heading(self): --- ___ + # h1 + + ## h2 + + + [Google](https://google.com) + + ## h22 + one two From 15bca83f77ecaef473879a9174f6d164720e43d4 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Thu, 31 Jan 2019 15:50:20 -0600 Subject: [PATCH 03/17] Added sections code --- recommonmark/parser.py | 100 +++++++++++++++++++++++------------------ tests/test_new.py | 31 +++++-------- 2 files changed, 69 insertions(+), 62 deletions(-) diff --git a/recommonmark/parser.py b/recommonmark/parser.py index 6ae5ff9..ac9c912 100644 --- a/recommonmark/parser.py +++ b/recommonmark/parser.py @@ -29,6 +29,8 @@ class CommonMarkParser(parsers.Parser): supported = ('md', 'markdown') translate_section_name = None + level = 0 + wrap_text = None def __init__(self): self._level_to_elem = {} @@ -90,14 +92,26 @@ def convert_ast(self, ast): fn = getattr(self, fn_default) fn(node) - - def _visit_section(self): + def _visit_section(self, level, attrs): + for i in range(self.level - level + 1): + self._depart_section(level) + self.level = level + section = nodes.section() + id_attr = _.find(attrs, lambda attr:attr[0]=='id')[1] + section['ids'] = id_attr + section['names'] = id_attr + title = nodes.title() + self.wrap_text = title + section.append(title) + self.current_node.append(section) + self.current_node = section print('visit section') - def _depart_section(self): + def _depart_section(self, level): + if (self.current_node.parent): + self.current_node = self.current_node.parent print('depart section') - def _visit_document(self): print('visit document') @@ -116,60 +130,60 @@ def _depart_p(self): def _visit_text(self, data): text = nodes.Text(data) - self.current_node.append(text) - self.current_node = text - print('visit text') + if (self.wrap_text): + self.wrap_text.append(text) + else: + self.current_node.append(text) + self.current_node = text + print('visit text') def _depart_text(self): - self.current_node = self.current_node.parent - print('depart text') + if (self.wrap_text): + self.wrap_text = None + else: + self.current_node = self.current_node.parent + print('depart text') - def _visit_h1(self, data): - self._visit_section() + def _visit_h1(self, attrs): + self._visit_section(1, attrs) print('visit h1') def _depart_h1(self): - self._depart_section() print('depart h1') - def _visit_h2(self, data): - self._visit_section() + def _visit_h2(self, attrs): + self._visit_section(2, attrs) print('visit h2') def _depart_h2(self): - self._depart_section() print('depart h2') - def _visit_h3(self, data): - self._visit_section() + def _visit_h3(self, attrs): + self._visit_section(3, attrs) print('visit h3') def _depart_h3(self): - self._depart_section() print('depart h3') - def _visit_h4(self, data): - self._visit_section() + def _visit_h4(self, attrs): + self._visit_section(4, attrs) print('visit h4') def _depart_h4(self): - self._depart_section() print('depart h4') - def _visit_h5(self, data): - self._visit_section() + def _visit_h5(self, attrs): + self._visit_section(5, attrs) print('visit h5') def _depart_h5(self): - self._depart_section() print('depart h5') - def _visit_h6(self, data): - self._visit_section() + def _visit_h6(self, attrs): + self._visit_section(6, attrs) print('visit h6') def _depart_h6(self): - self._depart_section() print('depart h6') def _visit_a(self, attrs): @@ -183,97 +197,97 @@ def _depart_a(self): self.current_node = self.current_node.parent print('depart a') - def _visit_img(self, data): + def _visit_img(self, attrs): print('visit img') def _depart_img(self): print('depart img') - def _visit_ul(self, data): + def _visit_ul(self, attrs): print('visit ul') def _depart_ul(self): print('depart ul') - def _visit_ol(self, data): + def _visit_ol(self, attrs): print('visit ol') def _depart_ol(self): print('depart ol') - def _visit_li(self, data): + def _visit_li(self, attrs): print('visit li') def _depart_li(self): print('depart li') - def _visit_table(self, data): + def _visit_table(self, attrs): print('visit table') def _depart_table(self): print('depart table') - def _visit_thead(self, data): + def _visit_thead(self, attrs): print('visit thead') def _depart_thead(self): print('depart thead') - def _visit_tbody(self, data): + def _visit_tbody(self, attrs): print('visit tbody') def _depart_tbody(self): print('depart tbody') - def _visit_tr(self, data): + def _visit_tr(self, attrs): print('visit tr') def _depart_tr(self): print('depart tr') - def _visit_th(self, data): + def _visit_th(self, attrs): print('visit th') def _depart_th(self): print('depart th') - def _visit_td(self, data): + def _visit_td(self, attrs): print('visit td') def _depart_td(self): print('depart td') - def _visit_div(self, data): + def _visit_div(self, attrs): print('visit div') def _depart_div(self): print('depart div') - def _visit_pre(self, data): + def _visit_pre(self, attrs): print('visit pre') def _depart_pre(self): print('depart pre') - def _visit_span(self, data): + def _visit_span(self, attrs): print('visit span') def _depart_span(self): print('depart span') - def _visit_blockquote(self, data): + def _visit_blockquote(self, attrs): print('visit blockquote') def _depart_blockquote(self): print('depart blockquote') - def _visit_hr(self, data): + def _visit_hr(self, attrs): print('visit hr') def _depart_hr(self): print('depart hr') - def _visit_br(self, data): + def _visit_br(self, attrs): print('visit br') def _depart_br(self): diff --git a/tests/test_new.py b/tests/test_new.py index e66ed48..c74555f 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -25,29 +25,22 @@ def assertParses(self, source, expected, alt=False): # noqa def test_heading(self): self.assertParses( """ - --- - ___ - - # h1 - - ## h2 - - - [Google](https://google.com) - - ## h22 - - one - two - - three - four - + # I + ## A + ### 1 """, """ - hi +
+ I +
+ A +
+ 1 +
+
+
""" ) From d23b4d8ef22798fb6ac5087baaef998270bcae61 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sat, 2 Feb 2019 10:47:26 -0600 Subject: [PATCH 04/17] Improved section logic --- recommonmark/parser.py | 133 +++++++++++++++++++++-------------------- tests/test_new.py | 22 +++++-- 2 files changed, 85 insertions(+), 70 deletions(-) diff --git a/recommonmark/parser.py b/recommonmark/parser.py index ac9c912..540d398 100644 --- a/recommonmark/parser.py +++ b/recommonmark/parser.py @@ -30,7 +30,6 @@ class CommonMarkParser(parsers.Parser): supported = ('md', 'markdown') translate_section_name = None level = 0 - wrap_text = None def __init__(self): self._level_to_elem = {} @@ -59,11 +58,15 @@ def parse(self, inputstring, document): 'toc', 'wikilinks' ]) + print(html) self.convert_html(html) # self.convert_ast(ast) self.finish_parse() + print('----------------------') + print(self.document) def convert_html(self, html): + html = html.replace('\n', '') class MyHTMLParser(HTMLParser): def handle_starttag(_, tag, attrs): fn_name = '_visit_' + tag @@ -86,7 +89,6 @@ def convert_ast(self, ast): fn_prefix = "visit" if entering else "depart" fn_name = "{0}_{1}".format(fn_prefix, node.t.lower()) fn_default = "default_{0}".format(fn_prefix) - print(fn_name) fn = getattr(self, fn_name, None) if fn is None: fn = getattr(self, fn_default) @@ -101,197 +103,196 @@ def _visit_section(self, level, attrs): section['ids'] = id_attr section['names'] = id_attr title = nodes.title() - self.wrap_text = title section.append(title) self.current_node.append(section) self.current_node = section - print('visit section') def _depart_section(self, level): if (self.current_node.parent): self.current_node = self.current_node.parent - print('depart section') def _visit_document(self): - print('visit document') + pass def _depart_document(self): - print('depart document') + pass def _visit_p(self, attrs): paragraph = nodes.paragraph() self.current_node.append(paragraph) self.current_node = paragraph - print('visit p') def _depart_p(self): self.current_node = self.current_node.parent - print('depart p') def _visit_text(self, data): text = nodes.Text(data) - if (self.wrap_text): - self.wrap_text.append(text) - else: - self.current_node.append(text) - self.current_node = text - print('visit text') + if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: + title = self.current_node.children[0] + if isinstance(title, nodes.title): + title.append(text) + self.current_node = title + return None + elif isinstance(self.current_node, nodes.title) and len(self.current_node.children) > 0: + reference = self.current_node.children[0] + if isinstance(reference, nodes.reference): + reference.append(text) + self.current_node = reference + return None + self.current_node.append(text) + self.current_node = text def _depart_text(self): - if (self.wrap_text): - self.wrap_text = None - else: - self.current_node = self.current_node.parent - print('depart text') + self.current_node = self.current_node.parent def _visit_h1(self, attrs): self._visit_section(1, attrs) - print('visit h1') def _depart_h1(self): - print('depart h1') + pass def _visit_h2(self, attrs): self._visit_section(2, attrs) - print('visit h2') def _depart_h2(self): - print('depart h2') + pass def _visit_h3(self, attrs): self._visit_section(3, attrs) - print('visit h3') def _depart_h3(self): - print('depart h3') + pass def _visit_h4(self, attrs): self._visit_section(4, attrs) - print('visit h4') def _depart_h4(self): - print('depart h4') + pass def _visit_h5(self, attrs): self._visit_section(5, attrs) - print('visit h5') def _depart_h5(self): - print('depart h5') + pass def _visit_h6(self, attrs): self._visit_section(6, attrs) - print('visit h6') def _depart_h6(self): - print('depart h6') + pass def _visit_a(self, attrs): reference = nodes.reference() reference['refuri'] = _.find(attrs, lambda i: i[0] == 'href')[1] + if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: + title = self.current_node.children[0] + if isinstance(title, nodes.title): + title.append(reference) + self.current_node = title + return None self.current_node.append(reference) self.current_node = reference - print('visit a') def _depart_a(self): self.current_node = self.current_node.parent - print('depart a') def _visit_img(self, attrs): - print('visit img') + pass def _depart_img(self): - print('depart img') + pass def _visit_ul(self, attrs): - print('visit ul') + pass def _depart_ul(self): - print('depart ul') + pass def _visit_ol(self, attrs): - print('visit ol') + pass def _depart_ol(self): - print('depart ol') + pass def _visit_li(self, attrs): - print('visit li') + pass def _depart_li(self): - print('depart li') + pass def _visit_table(self, attrs): - print('visit table') + pass def _depart_table(self): - print('depart table') + pass def _visit_thead(self, attrs): - print('visit thead') + pass def _depart_thead(self): - print('depart thead') + pass def _visit_tbody(self, attrs): - print('visit tbody') + pass def _depart_tbody(self): - print('depart tbody') + pass def _visit_tr(self, attrs): - print('visit tr') + pass def _depart_tr(self): - print('depart tr') + pass def _visit_th(self, attrs): - print('visit th') + pass def _depart_th(self): - print('depart th') + pass def _visit_td(self, attrs): - print('visit td') + pass def _depart_td(self): - print('depart td') + pass def _visit_div(self, attrs): - print('visit div') + pass def _depart_div(self): - print('depart div') + pass def _visit_pre(self, attrs): - print('visit pre') + pass def _depart_pre(self): - print('depart pre') + pass def _visit_span(self, attrs): - print('visit span') + pass def _depart_span(self): - print('depart span') + pass def _visit_blockquote(self, attrs): - print('visit blockquote') + block_quote = nodes.block_quote() + self.current_node.append(block_quote) + self.current_node = block_quote def _depart_blockquote(self): - print('depart blockquote') + self.current_node = self.current_node.parent def _visit_hr(self, attrs): - print('visit hr') + pass def _depart_hr(self): - print('depart hr') + pass def _visit_br(self, attrs): - print('visit br') + pass def _depart_br(self): - print('depart br') + pass # Node type enter/exit handlers diff --git a/tests/test_new.py b/tests/test_new.py index c74555f..8b1d49a 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -26,8 +26,14 @@ def test_heading(self): self.assertParses( """ # I + ## A - ### 1 + + > some-blockquote + + [google](https://www.google.com) + + ## [B](#b) """, """ @@ -36,9 +42,17 @@ def test_heading(self): I
A -
- 1 -
+ + some-blockquote + + + google + +
+
+ + <reference refuri="#b">B</reference> +
From 4f2334d43a361dfac9ca079a98b2861a0dd8f8f3 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sat, 2 Feb 2019 11:02:56 -0600 Subject: [PATCH 05/17] Added enumerated and bullet lists --- recommonmark/parser.py | 30 ++++++++++++++++++++++-------- tests/test_new.py | 27 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/recommonmark/parser.py b/recommonmark/parser.py index 540d398..de93528 100644 --- a/recommonmark/parser.py +++ b/recommonmark/parser.py @@ -197,28 +197,42 @@ def _depart_a(self): self.current_node = self.current_node.parent def _visit_img(self, attrs): - pass + print(attrs) + image = nodes.image() + image['uri'] = _.find(attrs, lambda attr:attr[0]=='src')[1] + self.current_node.append(image) + self.current_node = image + self._visit_text(_.find(attrs, lambda attr:attr[0]=='alt')[1]) def _depart_img(self): - pass + self._depart_text() + self.current_node = self.current_node.parent def _visit_ul(self, attrs): - pass + bullet_list = nodes.bullet_list() + self.current_node.append(bullet_list) + self.current_node = bullet_list def _depart_ul(self): - pass + self.current_node = self.current_node.parent def _visit_ol(self, attrs): - pass + enumerated_list = nodes.enumerated_list() + self.current_node.append(enumerated_list) + self.current_node = enumerated_list def _depart_ol(self): - pass + self.current_node = self.current_node.parent def _visit_li(self, attrs): - pass + list_item = nodes.list_item() + self.current_node.append(list_item) + self.current_node = list_item + self._visit_p([]) def _depart_li(self): - pass + self._depart_p() + self.current_node = self.current_node.parent def _visit_table(self, attrs): pass diff --git a/tests/test_new.py b/tests/test_new.py index 8b1d49a..1e6a9be 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -34,6 +34,14 @@ def test_heading(self): [google](https://www.google.com) ## [B](#b) + + ![ello](some-image.img) + + * one + * two + + 1. ONE + 2. TWO """, """ @@ -53,6 +61,25 @@ def test_heading(self): <reference refuri="#b">B</reference> + + ello + + + + one + + + two + + + + + ONE + + + TWO + + From e6e2c370f01c54ca28755e2b0c05b3b31c53fdd7 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sat, 2 Feb 2019 11:59:45 -0600 Subject: [PATCH 06/17] Added table support --- recommonmark/parser.py | 48 ++++++++++++++++++++++++++++-------------- tests/test_new.py | 21 ++++++++++++++++++ 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/recommonmark/parser.py b/recommonmark/parser.py index de93528..5e5d1cc 100644 --- a/recommonmark/parser.py +++ b/recommonmark/parser.py @@ -235,40 +235,52 @@ def _depart_li(self): self.current_node = self.current_node.parent def _visit_table(self, attrs): - pass + table = nodes.table() + self.current_node.append(table) + self.current_node = table def _depart_table(self): - pass + self.current_node = self.current_node.parent def _visit_thead(self, attrs): - pass + thead = nodes.thead() + self.current_node.append(thead) + self.current_node = thead def _depart_thead(self): - pass + self.current_node = self.current_node.parent def _visit_tbody(self, attrs): - pass + tbody = nodes.tbody() + self.current_node.append(tbody) + self.current_node = tbody def _depart_tbody(self): - pass + self.current_node = self.current_node.parent def _visit_tr(self, attrs): - pass + row = nodes.row() + self.current_node.append(row) + self.current_node = row def _depart_tr(self): - pass + self.current_node = self.current_node.parent def _visit_th(self, attrs): - pass + entry = nodes.entry() + self.current_node.append(entry) + self.current_node = entry def _depart_th(self): - pass + self.current_node = self.current_node.parent def _visit_td(self, attrs): - pass + entry = nodes.entry() + self.current_node.append(entry) + self.current_node = entry def _depart_td(self): - pass + self.current_node = self.current_node.parent def _visit_div(self, attrs): pass @@ -297,16 +309,20 @@ def _depart_blockquote(self): self.current_node = self.current_node.parent def _visit_hr(self, attrs): - pass + transition = nodes.transition() + self.current_node.append(transition) + self.current_node = transition def _depart_hr(self): - pass + self.current_node = self.current_node.parent def _visit_br(self, attrs): - pass + text = nodes.Text('\n') + self.current_node.append(text) + self.current_node = text def _depart_br(self): - pass + self.current_node = self.current_node.parent # Node type enter/exit handlers diff --git a/tests/test_new.py b/tests/test_new.py index 1e6a9be..4db81cf 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -42,6 +42,12 @@ def test_heading(self): 1. ONE 2. TWO + + --- + + | one | two | + | --- | --- | + | ONE | TWO | """, """ @@ -80,6 +86,21 @@ def test_heading(self): TWO + + + + + one + two + + + + + ONE + TWO + + +
From db052bc47bc6bbadffc99efe99e86565ddfca3c0 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sat, 2 Feb 2019 12:35:42 -0600 Subject: [PATCH 07/17] Added backwards compatible parsing --- README.md | 17 +- docs/api_ref.md | 11 +- recommonmark/__init__.py | 14 +- recommonmark/commonmark_parser.py | 268 ++++++++++++ recommonmark/markdown_parser.py | 302 +++++++++++++ recommonmark/parser.py | 544 +----------------------- recommonmark/transform.py | 7 +- setup.py | 2 + tests/{test_new.py => test_markdown.py} | 4 +- 9 files changed, 615 insertions(+), 554 deletions(-) create mode 100644 recommonmark/commonmark_parser.py create mode 100644 recommonmark/markdown_parser.py rename tests/{test_new.py => test_markdown.py} (97%) diff --git a/README.md b/README.md index 67feab2..b3aa222 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ Contents ## Getting Started -To use `recommonmark` inside of Sphinx only takes 2 steps. +To use `recommonmark` inside of Sphinx only takes 2 steps. First you install it: ``` -pip install recommonmark +pip install recommonmark ``` Then add this to your Sphinx conf.py: @@ -27,13 +27,24 @@ Then add this to your Sphinx conf.py: # for Sphinx-1.4 or newer extensions = ['recommonmark'] -# for Sphinx-1.3 + +# for Sphinx-1.3 CommonMarkParser from recommonmark.parser import CommonMarkParser source_parsers = { '.md': CommonMarkParser, } +source_suffix = ['.rst', '.md'] + + +# for Sphinx-1.3 MarkdownParser +from recommonmark.parser import MarkdownParser + +source_parsers = { + '.md': MarkdownParser, +} + source_suffix = ['.rst', '.md'] ``` diff --git a/docs/api_ref.md b/docs/api_ref.md index b90fcf4..0c02ed8 100644 --- a/docs/api_ref.md +++ b/docs/api_ref.md @@ -3,7 +3,7 @@ API Reference This document is for developers of recommonmark, it contans the API functions -Parser Component +CommonMark Parser Component ---------------- ```eval_rst .. autoclass:: recommonmark.parser.CommonMarkParser @@ -12,6 +12,15 @@ Parser Component ``` +Markdown Parser Component +---------------- +```eval_rst +.. autoclass:: recommonmark.parser.MarkdownParser + :members: + :show-inheritance: + +``` + Dummy State Machine ------------------- ```eval_rst diff --git a/recommonmark/__init__.py b/recommonmark/__init__.py index db27ab2..85a9fb4 100644 --- a/recommonmark/__init__.py +++ b/recommonmark/__init__.py @@ -6,12 +6,20 @@ def setup(app): """Initialize Sphinx extension.""" import sphinx - from .parser import CommonMarkParser + from .parser import CommonMarkParser, MarkdownParser + Parser = CommonMarkParser + recommonmark_config = {} + if hasattr(app.config, 'recommonmark_config'): + recommonmark_config = app.config.recommonmark_config + + if 'parser' in recommonmark_config: + if recommonmark_config['parser'] == 'Markdown': + Parser = CommonMarkParser if sphinx.version_info >= (1, 8): app.add_source_suffix('.md', 'markdown') - app.add_source_parser(CommonMarkParser) + app.add_source_parser(Parser) elif sphinx.version_info >= (1, 4): - app.add_source_parser('.md', CommonMarkParser) + app.add_source_parser('.md', Parser) return {'version': __version__, 'parallel_read_safe': True} diff --git a/recommonmark/commonmark_parser.py b/recommonmark/commonmark_parser.py new file mode 100644 index 0000000..bde143b --- /dev/null +++ b/recommonmark/commonmark_parser.py @@ -0,0 +1,268 @@ +"""Docutils CommonMark parser""" + +import sys +from os.path import splitext + +import pydash as _ + +from docutils import parsers, nodes +from sphinx import addnodes + +from commonmark import Parser + +from warnings import warn + +if sys.version_info < (3, 0): + from urlparse import urlparse +else: + from urllib.parse import urlparse + +__all__ = ['CommonMarkParser'] + + +class CommonMarkParser(parsers.Parser): + + """Docutils parser for CommonMark""" + + supported = ('md', 'markdown') + translate_section_name = None + level = 0 + + def __init__(self): + self._level_to_elem = {} + + def parse(self, inputstring, document): + self.document = document + self.current_node = document + self.setup_parse(inputstring, document) + self.setup_sections() + parser = Parser() + ast = parser.parse(inputstring + '\n') + self.convert_ast(ast) + self.finish_parse() + + def convert_ast(self, ast): + for (node, entering) in ast.walker(): + fn_prefix = "visit" if entering else "depart" + fn_name = "{0}_{1}".format(fn_prefix, node.t.lower()) + fn_default = "default_{0}".format(fn_prefix) + fn = getattr(self, fn_name, None) + if fn is None: + fn = getattr(self, fn_default) + fn(node) + + # Node type enter/exit handlers + def default_visit(self, mdnode): + pass + + def default_depart(self, mdnode): + """Default node depart handler + + If there is a matching ``visit_`` method for a container node, + then we should make sure to back up to it's parent element when the node + is exited. + """ + if mdnode.is_container(): + fn_name = 'visit_{0}'.format(mdnode.t) + if not hasattr(self, fn_name): + warn("Container node skipped: type={0}".format(mdnode.t)) + else: + self.current_node = self.current_node.parent + + def visit_heading(self, mdnode): + # Test if we're replacing a section level first + if isinstance(self.current_node, nodes.section): + if self.is_section_level(mdnode.level, self.current_node): + self.current_node = self.current_node.parent + + title_node = nodes.title() + title_node.line = mdnode.sourcepos[0][0] + + new_section = nodes.section() + new_section.line = mdnode.sourcepos[0][0] + new_section.append(title_node) + + self.add_section(new_section, mdnode.level) + + # Set the current node to the title node to accumulate text children/etc + # for heading. + self.current_node = title_node + + def depart_heading(self, _): + """Finish establishing section + + Wrap up title node, but stick in the section node. Add the section names + based on all the text nodes added to the title. + """ + assert isinstance(self.current_node, nodes.title) + # The title node has a tree of text nodes, use the whole thing to + # determine the section id and names + text = self.current_node.astext() + if self.translate_section_name: + text = self.translate_section_name(text) + name = nodes.fully_normalize_name(text) + section = self.current_node.parent + section['names'].append(name) + self.document.note_implicit_target(section, section) + self.current_node = section + + def visit_text(self, mdnode): + self.current_node.append(nodes.Text(mdnode.literal, mdnode.literal)) + + def visit_softbreak(self, _): + self.current_node.append(nodes.Text('\n')) + + def visit_paragraph(self, mdnode): + p = nodes.paragraph(mdnode.literal) + p.line = mdnode.sourcepos[0][0] + self.current_node.append(p) + self.current_node = p + + def visit_emph(self, _): + n = nodes.emphasis() + self.current_node.append(n) + self.current_node = n + + def visit_strong(self, _): + n = nodes.strong() + self.current_node.append(n) + self.current_node = n + + def visit_code(self, mdnode): + n = nodes.literal(mdnode.literal, mdnode.literal) + self.current_node.append(n) + + def visit_link(self, mdnode): + ref_node = nodes.reference() + # Check destination is supported for cross-linking and remove extension + destination = mdnode.destination + _, ext = splitext(destination) + # TODO check for other supported extensions, such as those specified in + # the Sphinx conf.py file but how to access this information? + # TODO this should probably only remove the extension for local paths, + # i.e. not uri's starting with http or other external prefix. + if ext.replace('.', '') in self.supported: + destination = destination.replace(ext, '') + ref_node['refuri'] = destination + # TODO okay, so this is acutally not always the right line number, but + # these mdnodes won't have sourcepos on them for whatever reason. This + # is better than 0 though. + ref_node.line = self._get_line(mdnode) + if mdnode.title: + ref_node['title'] = mdnode.title + next_node = ref_node + + url_check = urlparse(destination) + if not url_check.scheme and not url_check.fragment: + wrap_node = addnodes.pending_xref( + reftarget=destination, + reftype='any', + refdomain=None, # Added to enable cross-linking + refexplicit=True, + refwarn=True + ) + # TODO also not correct sourcepos + wrap_node.line = self._get_line(mdnode) + if mdnode.title: + wrap_node['title'] = mdnode.title + wrap_node.append(ref_node) + next_node = wrap_node + + self.current_node.append(next_node) + self.current_node = ref_node + + def depart_link(self, mdnode): + if isinstance(self.current_node.parent, addnodes.pending_xref): + self.current_node = self.current_node.parent.parent + else: + self.current_node = self.current_node.parent + + def visit_image(self, mdnode): + img_node = nodes.image() + img_node['uri'] = mdnode.destination + + if mdnode.title: + img_node['alt'] = mdnode.title + + self.current_node.append(img_node) + self.current_node = img_node + + def visit_list(self, mdnode): + list_node = None + if (mdnode.list_data['type'] == "bullet"): + list_node_cls = nodes.bullet_list + else: + list_node_cls = nodes.enumerated_list + list_node = list_node_cls() + list_node.line = mdnode.sourcepos[0][0] + + self.current_node.append(list_node) + self.current_node = list_node + + def visit_item(self, mdnode): + node = nodes.list_item() + node.line = mdnode.sourcepos[0][0] + self.current_node.append(node) + self.current_node = node + + def visit_code_block(self, mdnode): + kwargs = {} + if mdnode.is_fenced and mdnode.info: + kwargs['language'] = mdnode.info + text = ''.join(mdnode.literal) + if text.endswith('\n'): + text = text[:-1] + node = nodes.literal_block(text, text, **kwargs) + self.current_node.append(node) + + def visit_block_quote(self, mdnode): + q = nodes.block_quote() + q.line = mdnode.sourcepos[0][0] + self.current_node.append(q) + self.current_node = q + + def visit_html(self, mdnode): + raw_node = nodes.raw(mdnode.literal, + mdnode.literal, format='html') + if mdnode.sourcepos is not None: + raw_node.line = mdnode.sourcepos[0][0] + self.current_node.append(raw_node) + + def visit_html_inline(self, mdnode): + self.visit_html(mdnode) + + def visit_html_block(self, mdnode): + self.visit_html(mdnode) + + def visit_thematic_break(self, _): + self.current_node.append(nodes.transition()) + + # Section handling + def setup_sections(self): + self._level_to_elem = {0: self.document} + + def add_section(self, section, level): + parent_level = max( + section_level for section_level in self._level_to_elem + if level > section_level + ) + parent = self._level_to_elem[parent_level] + parent.append(section) + self._level_to_elem[level] = section + + # Prune level to limit + self._level_to_elem = dict( + (section_level, section) + for section_level, section in self._level_to_elem.items() + if section_level <= level + ) + + def is_section_level(self, level, section): + return self._level_to_elem.get(level, None) == section + + def _get_line(self, mdnode): + while mdnode: + if mdnode.sourcepos: + return mdnode.sourcepos[0][0] + mdnode = mdnode.parent + return 0 diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py new file mode 100644 index 0000000..ca56cdf --- /dev/null +++ b/recommonmark/markdown_parser.py @@ -0,0 +1,302 @@ +"""Docutils Markdown parser""" + +import pydash as _ +from docutils import parsers, nodes +from markdown import markdown +from html.parser import HTMLParser + +__all__ = ['MarkdownParser'] + +class MarkdownParser(parsers.Parser): + + """Docutils parser for Markdown""" + + supported = ('md', 'markdown') + translate_section_name = None + level = 0 + + def __init__(self): + self._level_to_elem = {} + + def parse(self, inputstring, document): + self.document = document + self.current_node = document + self.setup_parse(inputstring, document) + html = markdown(inputstring + '\n', extensions=[ + 'extra', + 'abbr', + 'attr_list', + 'def_list', + 'fenced_code', + 'footnotes', + 'tables', + 'admonition', + 'codehilite', + 'meta', + 'nl2br', + 'sane_lists', + 'smarty', + 'toc', + 'wikilinks' + ]) + self.convert_html(html) + self.finish_parse() + + def convert_html(self, html): + html = html.replace('\n', '') + class MyHTMLParser(HTMLParser): + def handle_starttag(_, tag, attrs): + fn_name = 'visit_' + tag + fn = getattr(self, fn_name) + fn(attrs) + def handle_endtag(_, tag): + fn_name = 'depart_' + tag + fn = getattr(self, fn_name) + fn() + def handle_data(_, data): + self.visit_text(data) + self.depart_text() + self.visit_document() + parser = MyHTMLParser() + parser.feed(html) + self.depart_document() + + def convert_ast(self, ast): + for (node, entering) in ast.walker(): + fn_prefix = "visit" if entering else "depart" + fn_name = "{0}_{1}".format(fn_prefix, node.t.lower()) + fn_default = "default_{0}".format(fn_prefix) + fn = getattr(self, fn_name, None) + if fn is None: + fn = getattr(self, fn_default) + fn(node) + + def visit_section(self, level, attrs): + for i in range(self.level - level + 1): + self.depart_section(level) + self.level = level + section = nodes.section() + id_attr = _.find(attrs, lambda attr:attr[0]=='id')[1] + section['ids'] = id_attr + section['names'] = id_attr + title = nodes.title() + section.append(title) + self.current_node.append(section) + self.current_node = section + + def depart_section(self, level): + if (self.current_node.parent): + self.current_node = self.current_node.parent + + def visit_document(self): + pass + + def depart_document(self): + pass + + def visit_p(self, attrs): + paragraph = nodes.paragraph() + self.current_node.append(paragraph) + self.current_node = paragraph + + def depart_p(self): + self.current_node = self.current_node.parent + + def visit_text(self, data): + text = nodes.Text(data) + if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: + title = self.current_node.children[0] + if isinstance(title, nodes.title): + title.append(text) + self.current_node = title + return None + elif isinstance(self.current_node, nodes.title) and len(self.current_node.children) > 0: + reference = self.current_node.children[0] + if isinstance(reference, nodes.reference): + reference.append(text) + self.current_node = reference + return None + self.current_node.append(text) + self.current_node = text + + def depart_text(self): + self.current_node = self.current_node.parent + + def visit_h1(self, attrs): + self.visit_section(1, attrs) + + def depart_h1(self): + pass + + def visit_h2(self, attrs): + self.visit_section(2, attrs) + + def depart_h2(self): + pass + + def visit_h3(self, attrs): + self.visit_section(3, attrs) + + def depart_h3(self): + pass + + def visit_h4(self, attrs): + self.visit_section(4, attrs) + + def depart_h4(self): + pass + + def visit_h5(self, attrs): + self.visit_section(5, attrs) + + def depart_h5(self): + pass + + def visit_h6(self, attrs): + self.visit_section(6, attrs) + + def depart_h6(self): + pass + + def visit_a(self, attrs): + reference = nodes.reference() + reference['refuri'] = _.find(attrs, lambda i: i[0] == 'href')[1] + if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: + title = self.current_node.children[0] + if isinstance(title, nodes.title): + title.append(reference) + self.current_node = title + return None + self.current_node.append(reference) + self.current_node = reference + + def depart_a(self): + self.current_node = self.current_node.parent + + def visit_img(self, attrs): + print(attrs) + image = nodes.image() + image['uri'] = _.find(attrs, lambda attr:attr[0]=='src')[1] + self.current_node.append(image) + self.current_node = image + self.visit_text(_.find(attrs, lambda attr:attr[0]=='alt')[1]) + + def depart_img(self): + self.depart_text() + self.current_node = self.current_node.parent + + def visit_ul(self, attrs): + bullet_list = nodes.bullet_list() + self.current_node.append(bullet_list) + self.current_node = bullet_list + + def depart_ul(self): + self.current_node = self.current_node.parent + + def visit_ol(self, attrs): + enumerated_list = nodes.enumerated_list() + self.current_node.append(enumerated_list) + self.current_node = enumerated_list + + def depart_ol(self): + self.current_node = self.current_node.parent + + def visit_li(self, attrs): + list_item = nodes.list_item() + self.current_node.append(list_item) + self.current_node = list_item + self.visit_p([]) + + def depart_li(self): + self.depart_p() + self.current_node = self.current_node.parent + + def visit_table(self, attrs): + table = nodes.table() + self.current_node.append(table) + self.current_node = table + + def depart_table(self): + self.current_node = self.current_node.parent + + def visit_thead(self, attrs): + thead = nodes.thead() + self.current_node.append(thead) + self.current_node = thead + + def depart_thead(self): + self.current_node = self.current_node.parent + + def visit_tbody(self, attrs): + tbody = nodes.tbody() + self.current_node.append(tbody) + self.current_node = tbody + + def depart_tbody(self): + self.current_node = self.current_node.parent + + def visit_tr(self, attrs): + row = nodes.row() + self.current_node.append(row) + self.current_node = row + + def depart_tr(self): + self.current_node = self.current_node.parent + + def visit_th(self, attrs): + entry = nodes.entry() + self.current_node.append(entry) + self.current_node = entry + + def depart_th(self): + self.current_node = self.current_node.parent + + def visit_td(self, attrs): + entry = nodes.entry() + self.current_node.append(entry) + self.current_node = entry + + def depart_td(self): + self.current_node = self.current_node.parent + + def visit_div(self, attrs): + pass + + def depart_div(self): + pass + + def visit_pre(self, attrs): + pass + + def depart_pre(self): + pass + + def visit_span(self, attrs): + pass + + def depart_span(self): + pass + + def visit_blockquote(self, attrs): + block_quote = nodes.block_quote() + self.current_node.append(block_quote) + self.current_node = block_quote + + def depart_blockquote(self): + self.current_node = self.current_node.parent + + def visit_hr(self, attrs): + transition = nodes.transition() + self.current_node.append(transition) + self.current_node = transition + + def depart_hr(self): + self.current_node = self.current_node.parent + + def visit_br(self, attrs): + text = nodes.Text('\n') + self.current_node.append(text) + self.current_node = text + + def depart_br(self): + self.current_node = self.current_node.parent diff --git a/recommonmark/parser.py b/recommonmark/parser.py index 5e5d1cc..e1b62dc 100644 --- a/recommonmark/parser.py +++ b/recommonmark/parser.py @@ -1,542 +1,2 @@ -"""Docutils CommonMark parser""" - -import sys -from os.path import splitext - -import pydash as _ - -from docutils import parsers, nodes -from sphinx import addnodes - -from commonmark import Parser - -from warnings import warn - -from markdown import markdown -from html.parser import HTMLParser - -if sys.version_info < (3, 0): - from urlparse import urlparse -else: - from urllib.parse import urlparse - -__all__ = ['CommonMarkParser'] - - -class CommonMarkParser(parsers.Parser): - - """Docutils parser for CommonMark""" - - supported = ('md', 'markdown') - translate_section_name = None - level = 0 - - def __init__(self): - self._level_to_elem = {} - - def parse(self, inputstring, document): - self.document = document - self.current_node = document - self.setup_parse(inputstring, document) - self.setup_sections() - parser = Parser() - ast = parser.parse(inputstring + '\n') - html = markdown(inputstring + '\n', extensions=[ - 'extra', - 'abbr', - 'attr_list', - 'def_list', - 'fenced_code', - 'footnotes', - 'tables', - 'admonition', - 'codehilite', - 'meta', - 'nl2br', - 'sane_lists', - 'smarty', - 'toc', - 'wikilinks' - ]) - print(html) - self.convert_html(html) - # self.convert_ast(ast) - self.finish_parse() - print('----------------------') - print(self.document) - - def convert_html(self, html): - html = html.replace('\n', '') - class MyHTMLParser(HTMLParser): - def handle_starttag(_, tag, attrs): - fn_name = '_visit_' + tag - fn = getattr(self, fn_name) - fn(attrs) - def handle_endtag(_, tag): - fn_name = '_depart_' + tag - fn = getattr(self, fn_name) - fn() - def handle_data(_, data): - self._visit_text(data) - self._depart_text() - self._visit_document() - parser = MyHTMLParser() - parser.feed(html) - self._depart_document() - - def convert_ast(self, ast): - for (node, entering) in ast.walker(): - fn_prefix = "visit" if entering else "depart" - fn_name = "{0}_{1}".format(fn_prefix, node.t.lower()) - fn_default = "default_{0}".format(fn_prefix) - fn = getattr(self, fn_name, None) - if fn is None: - fn = getattr(self, fn_default) - fn(node) - - def _visit_section(self, level, attrs): - for i in range(self.level - level + 1): - self._depart_section(level) - self.level = level - section = nodes.section() - id_attr = _.find(attrs, lambda attr:attr[0]=='id')[1] - section['ids'] = id_attr - section['names'] = id_attr - title = nodes.title() - section.append(title) - self.current_node.append(section) - self.current_node = section - - def _depart_section(self, level): - if (self.current_node.parent): - self.current_node = self.current_node.parent - - def _visit_document(self): - pass - - def _depart_document(self): - pass - - def _visit_p(self, attrs): - paragraph = nodes.paragraph() - self.current_node.append(paragraph) - self.current_node = paragraph - - def _depart_p(self): - self.current_node = self.current_node.parent - - def _visit_text(self, data): - text = nodes.Text(data) - if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: - title = self.current_node.children[0] - if isinstance(title, nodes.title): - title.append(text) - self.current_node = title - return None - elif isinstance(self.current_node, nodes.title) and len(self.current_node.children) > 0: - reference = self.current_node.children[0] - if isinstance(reference, nodes.reference): - reference.append(text) - self.current_node = reference - return None - self.current_node.append(text) - self.current_node = text - - def _depart_text(self): - self.current_node = self.current_node.parent - - def _visit_h1(self, attrs): - self._visit_section(1, attrs) - - def _depart_h1(self): - pass - - def _visit_h2(self, attrs): - self._visit_section(2, attrs) - - def _depart_h2(self): - pass - - def _visit_h3(self, attrs): - self._visit_section(3, attrs) - - def _depart_h3(self): - pass - - def _visit_h4(self, attrs): - self._visit_section(4, attrs) - - def _depart_h4(self): - pass - - def _visit_h5(self, attrs): - self._visit_section(5, attrs) - - def _depart_h5(self): - pass - - def _visit_h6(self, attrs): - self._visit_section(6, attrs) - - def _depart_h6(self): - pass - - def _visit_a(self, attrs): - reference = nodes.reference() - reference['refuri'] = _.find(attrs, lambda i: i[0] == 'href')[1] - if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: - title = self.current_node.children[0] - if isinstance(title, nodes.title): - title.append(reference) - self.current_node = title - return None - self.current_node.append(reference) - self.current_node = reference - - def _depart_a(self): - self.current_node = self.current_node.parent - - def _visit_img(self, attrs): - print(attrs) - image = nodes.image() - image['uri'] = _.find(attrs, lambda attr:attr[0]=='src')[1] - self.current_node.append(image) - self.current_node = image - self._visit_text(_.find(attrs, lambda attr:attr[0]=='alt')[1]) - - def _depart_img(self): - self._depart_text() - self.current_node = self.current_node.parent - - def _visit_ul(self, attrs): - bullet_list = nodes.bullet_list() - self.current_node.append(bullet_list) - self.current_node = bullet_list - - def _depart_ul(self): - self.current_node = self.current_node.parent - - def _visit_ol(self, attrs): - enumerated_list = nodes.enumerated_list() - self.current_node.append(enumerated_list) - self.current_node = enumerated_list - - def _depart_ol(self): - self.current_node = self.current_node.parent - - def _visit_li(self, attrs): - list_item = nodes.list_item() - self.current_node.append(list_item) - self.current_node = list_item - self._visit_p([]) - - def _depart_li(self): - self._depart_p() - self.current_node = self.current_node.parent - - def _visit_table(self, attrs): - table = nodes.table() - self.current_node.append(table) - self.current_node = table - - def _depart_table(self): - self.current_node = self.current_node.parent - - def _visit_thead(self, attrs): - thead = nodes.thead() - self.current_node.append(thead) - self.current_node = thead - - def _depart_thead(self): - self.current_node = self.current_node.parent - - def _visit_tbody(self, attrs): - tbody = nodes.tbody() - self.current_node.append(tbody) - self.current_node = tbody - - def _depart_tbody(self): - self.current_node = self.current_node.parent - - def _visit_tr(self, attrs): - row = nodes.row() - self.current_node.append(row) - self.current_node = row - - def _depart_tr(self): - self.current_node = self.current_node.parent - - def _visit_th(self, attrs): - entry = nodes.entry() - self.current_node.append(entry) - self.current_node = entry - - def _depart_th(self): - self.current_node = self.current_node.parent - - def _visit_td(self, attrs): - entry = nodes.entry() - self.current_node.append(entry) - self.current_node = entry - - def _depart_td(self): - self.current_node = self.current_node.parent - - def _visit_div(self, attrs): - pass - - def _depart_div(self): - pass - - def _visit_pre(self, attrs): - pass - - def _depart_pre(self): - pass - - def _visit_span(self, attrs): - pass - - def _depart_span(self): - pass - - def _visit_blockquote(self, attrs): - block_quote = nodes.block_quote() - self.current_node.append(block_quote) - self.current_node = block_quote - - def _depart_blockquote(self): - self.current_node = self.current_node.parent - - def _visit_hr(self, attrs): - transition = nodes.transition() - self.current_node.append(transition) - self.current_node = transition - - def _depart_hr(self): - self.current_node = self.current_node.parent - - def _visit_br(self, attrs): - text = nodes.Text('\n') - self.current_node.append(text) - self.current_node = text - - def _depart_br(self): - self.current_node = self.current_node.parent - - - # Node type enter/exit handlers - def default_visit(self, mdnode): - pass - - def default_depart(self, mdnode): - """Default node depart handler - - If there is a matching ``visit_`` method for a container node, - then we should make sure to back up to it's parent element when the node - is exited. - """ - if mdnode.is_container(): - fn_name = 'visit_{0}'.format(mdnode.t) - if not hasattr(self, fn_name): - warn("Container node skipped: type={0}".format(mdnode.t)) - else: - self.current_node = self.current_node.parent - - def visit_heading(self, mdnode): - # Test if we're replacing a section level first - if isinstance(self.current_node, nodes.section): - if self.is_section_level(mdnode.level, self.current_node): - self.current_node = self.current_node.parent - - title_node = nodes.title() - title_node.line = mdnode.sourcepos[0][0] - - new_section = nodes.section() - new_section.line = mdnode.sourcepos[0][0] - new_section.append(title_node) - - self.add_section(new_section, mdnode.level) - - # Set the current node to the title node to accumulate text children/etc - # for heading. - self.current_node = title_node - - def depart_heading(self, _): - """Finish establishing section - - Wrap up title node, but stick in the section node. Add the section names - based on all the text nodes added to the title. - """ - assert isinstance(self.current_node, nodes.title) - # The title node has a tree of text nodes, use the whole thing to - # determine the section id and names - text = self.current_node.astext() - if self.translate_section_name: - text = self.translate_section_name(text) - name = nodes.fully_normalize_name(text) - section = self.current_node.parent - section['names'].append(name) - self.document.note_implicit_target(section, section) - self.current_node = section - - def visit_text(self, mdnode): - self.current_node.append(nodes.Text(mdnode.literal, mdnode.literal)) - - def visit_softbreak(self, _): - self.current_node.append(nodes.Text('\n')) - - def visit_paragraph(self, mdnode): - p = nodes.paragraph(mdnode.literal) - p.line = mdnode.sourcepos[0][0] - self.current_node.append(p) - self.current_node = p - - def visit_emph(self, _): - n = nodes.emphasis() - self.current_node.append(n) - self.current_node = n - - def visit_strong(self, _): - n = nodes.strong() - self.current_node.append(n) - self.current_node = n - - def visit_code(self, mdnode): - n = nodes.literal(mdnode.literal, mdnode.literal) - self.current_node.append(n) - - def visit_link(self, mdnode): - ref_node = nodes.reference() - # Check destination is supported for cross-linking and remove extension - destination = mdnode.destination - _, ext = splitext(destination) - # TODO check for other supported extensions, such as those specified in - # the Sphinx conf.py file but how to access this information? - # TODO this should probably only remove the extension for local paths, - # i.e. not uri's starting with http or other external prefix. - if ext.replace('.', '') in self.supported: - destination = destination.replace(ext, '') - ref_node['refuri'] = destination - # TODO okay, so this is acutally not always the right line number, but - # these mdnodes won't have sourcepos on them for whatever reason. This - # is better than 0 though. - ref_node.line = self._get_line(mdnode) - if mdnode.title: - ref_node['title'] = mdnode.title - next_node = ref_node - - url_check = urlparse(destination) - if not url_check.scheme and not url_check.fragment: - wrap_node = addnodes.pending_xref( - reftarget=destination, - reftype='any', - refdomain=None, # Added to enable cross-linking - refexplicit=True, - refwarn=True - ) - # TODO also not correct sourcepos - wrap_node.line = self._get_line(mdnode) - if mdnode.title: - wrap_node['title'] = mdnode.title - wrap_node.append(ref_node) - next_node = wrap_node - - self.current_node.append(next_node) - self.current_node = ref_node - - def depart_link(self, mdnode): - if isinstance(self.current_node.parent, addnodes.pending_xref): - self.current_node = self.current_node.parent.parent - else: - self.current_node = self.current_node.parent - - def visit_image(self, mdnode): - img_node = nodes.image() - img_node['uri'] = mdnode.destination - - if mdnode.title: - img_node['alt'] = mdnode.title - - self.current_node.append(img_node) - self.current_node = img_node - - def visit_list(self, mdnode): - list_node = None - if (mdnode.list_data['type'] == "bullet"): - list_node_cls = nodes.bullet_list - else: - list_node_cls = nodes.enumerated_list - list_node = list_node_cls() - list_node.line = mdnode.sourcepos[0][0] - - self.current_node.append(list_node) - self.current_node = list_node - - def visit_item(self, mdnode): - node = nodes.list_item() - node.line = mdnode.sourcepos[0][0] - self.current_node.append(node) - self.current_node = node - - def visit_code_block(self, mdnode): - kwargs = {} - if mdnode.is_fenced and mdnode.info: - kwargs['language'] = mdnode.info - text = ''.join(mdnode.literal) - if text.endswith('\n'): - text = text[:-1] - node = nodes.literal_block(text, text, **kwargs) - self.current_node.append(node) - - def visit_block_quote(self, mdnode): - q = nodes.block_quote() - q.line = mdnode.sourcepos[0][0] - self.current_node.append(q) - self.current_node = q - - def visit_html(self, mdnode): - raw_node = nodes.raw(mdnode.literal, - mdnode.literal, format='html') - if mdnode.sourcepos is not None: - raw_node.line = mdnode.sourcepos[0][0] - self.current_node.append(raw_node) - - def visit_html_inline(self, mdnode): - self.visit_html(mdnode) - - def visit_html_block(self, mdnode): - self.visit_html(mdnode) - - def visit_thematic_break(self, _): - self.current_node.append(nodes.transition()) - - # Section handling - def setup_sections(self): - self._level_to_elem = {0: self.document} - - def add_section(self, section, level): - parent_level = max( - section_level for section_level in self._level_to_elem - if level > section_level - ) - parent = self._level_to_elem[parent_level] - parent.append(section) - self._level_to_elem[level] = section - - # Prune level to limit - self._level_to_elem = dict( - (section_level, section) - for section_level, section in self._level_to_elem.items() - if section_level <= level - ) - - def is_section_level(self, level, section): - return self._level_to_elem.get(level, None) == section - - def _get_line(self, mdnode): - while mdnode: - if mdnode.sourcepos: - return mdnode.sourcepos[0][0] - mdnode = mdnode.parent - return 0 +from .commonmark_parser import CommonMarkParser +from .markdown_parser import MarkdownParser diff --git a/recommonmark/transform.py b/recommonmark/transform.py index dc15427..efab52e 100644 --- a/recommonmark/transform.py +++ b/recommonmark/transform.py @@ -40,13 +40,14 @@ def __init__(self, *args, **kwargs): suffix_set = set(['md', 'rst']) default_config = { - 'enable_auto_doc_ref': False, 'auto_toc_tree_section': None, + 'commonmark_suffixes': ['.md'], + 'enable_auto_doc_ref': False, 'enable_auto_toc_tree': True, 'enable_eval_rst': True, - 'enable_math': True, 'enable_inline_math': True, - 'commonmark_suffixes': ['.md'], + 'enable_math': True, + 'parser': 'CommonMark', 'url_resolver': lambda x: x, } diff --git a/setup.py b/setup.py index 1a7871a..5fc8350 100644 --- a/setup.py +++ b/setup.py @@ -23,8 +23,10 @@ 'License :: OSI Approved :: MIT License', ], install_requires=[ + 'Markdown>=3.0.1', 'commonmark>=0.7.3', 'docutils>=0.11', + 'pydash>=4.7.4', 'sphinx>=1.3.1', ], entry_points={'console_scripts': [ diff --git a/tests/test_new.py b/tests/test_markdown.py similarity index 97% rename from tests/test_new.py rename to tests/test_markdown.py index 4db81cf..1f111c3 100644 --- a/tests/test_new.py +++ b/tests/test_markdown.py @@ -9,13 +9,13 @@ from docutils.core import publish_parts from commonmark import Parser -from recommonmark.parser import CommonMarkParser +from recommonmark.parser import MarkdownParser class TestParsing(unittest.TestCase): def assertParses(self, source, expected, alt=False): # noqa - parser = CommonMarkParser() + parser = MarkdownParser() parser.parse(dedent(source), new_document('')) self.assertMultiLineEqual( dedent(expected).lstrip(), From 24385e699d445255890d9da4eafda3838f5ff051 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sat, 2 Feb 2019 18:55:50 -0600 Subject: [PATCH 08/17] Added support for code blocks --- recommonmark/commonmark_parser.py | 1 + recommonmark/markdown_parser.py | 45 +++++++++++++++++++++---------- tests/test_markdown.py | 18 +++++++++++-- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/recommonmark/commonmark_parser.py b/recommonmark/commonmark_parser.py index bde143b..b5ba715 100644 --- a/recommonmark/commonmark_parser.py +++ b/recommonmark/commonmark_parser.py @@ -40,6 +40,7 @@ def parse(self, inputstring, document): ast = parser.parse(inputstring + '\n') self.convert_ast(ast) self.finish_parse() + print(self.document) def convert_ast(self, ast): for (node, entering) in ast.walker(): diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py index ca56cdf..39f8ddf 100644 --- a/recommonmark/markdown_parser.py +++ b/recommonmark/markdown_parser.py @@ -1,9 +1,10 @@ """Docutils Markdown parser""" -import pydash as _ from docutils import parsers, nodes -from markdown import markdown from html.parser import HTMLParser +from markdown import markdown +import pydash as _ +import re __all__ = ['MarkdownParser'] @@ -24,20 +25,9 @@ def parse(self, inputstring, document): self.setup_parse(inputstring, document) html = markdown(inputstring + '\n', extensions=[ 'extra', - 'abbr', - 'attr_list', - 'def_list', - 'fenced_code', - 'footnotes', 'tables', - 'admonition', - 'codehilite', - 'meta', - 'nl2br', 'sane_lists', - 'smarty', 'toc', - 'wikilinks' ]) self.convert_html(html) self.finish_parse() @@ -174,7 +164,6 @@ def depart_a(self): self.current_node = self.current_node.parent def visit_img(self, attrs): - print(attrs) image = nodes.image() image['uri'] = _.find(attrs, lambda attr:attr[0]=='src')[1] self.current_node.append(image) @@ -277,6 +266,18 @@ def visit_span(self, attrs): def depart_span(self): pass + def visit_code(self, attrs): + literal_block = nodes.literal_block() + attr = _.find(attrs, lambda attr:attr[0]=='class') + if len(attr): + class_attr = attr[1] + literal_block['language'] = class_attr + self.current_node.append(literal_block) + self.current_node = literal_block + + def depart_code(self): + self.current_node = self.current_node.parent + def visit_blockquote(self, attrs): block_quote = nodes.block_quote() self.current_node.append(block_quote) @@ -300,3 +301,19 @@ def visit_br(self, attrs): def depart_br(self): self.current_node = self.current_node.parent + + def visit_em(self, attrs): + emphasis = nodes.emphasis() + self.current_node.append(emphasis) + self.current_node = emphasis + + def depart_em(self): + self.current_node = self.current_node.parent + + def visit_strong(self, attrs): + strong = nodes.strong() + self.current_node.append(strong) + self.current_node = strong + + def depart_strong(self): + self.current_node = self.current_node.parent diff --git a/tests/test_markdown.py b/tests/test_markdown.py index 1f111c3..55e5786 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -9,8 +9,7 @@ from docutils.core import publish_parts from commonmark import Parser -from recommonmark.parser import MarkdownParser - +from recommonmark.parser import MarkdownParser, CommonMarkParser class TestParsing(unittest.TestCase): @@ -27,6 +26,10 @@ def test_heading(self): """ # I + ```py + hello = 'world' + ``` + ## A > some-blockquote @@ -43,6 +46,10 @@ def test_heading(self): 1. ONE 2. TWO + _italicize_ + + **bold** + --- | one | two | @@ -54,6 +61,7 @@ def test_heading(self):
I + hello = 'world'
A @@ -86,6 +94,12 @@ def test_heading(self): TWO + + italicize + + + bold + From 29e420c3fad0427eb973290ab4211bc5119cdc19 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sat, 2 Feb 2019 19:27:36 -0600 Subject: [PATCH 09/17] Improved title node support --- recommonmark/commonmark_parser.py | 1 - recommonmark/markdown_parser.py | 83 +++++++++++++++++-------------- tests/test_markdown.py | 12 +++-- 3 files changed, 56 insertions(+), 40 deletions(-) diff --git a/recommonmark/commonmark_parser.py b/recommonmark/commonmark_parser.py index b5ba715..bde143b 100644 --- a/recommonmark/commonmark_parser.py +++ b/recommonmark/commonmark_parser.py @@ -40,7 +40,6 @@ def parse(self, inputstring, document): ast = parser.parse(inputstring + '\n') self.convert_ast(ast) self.finish_parse() - print(self.document) def convert_ast(self, ast): for (node, entering) in ast.walker(): diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py index 39f8ddf..c9ab405 100644 --- a/recommonmark/markdown_parser.py +++ b/recommonmark/markdown_parser.py @@ -70,6 +70,7 @@ def visit_section(self, level, attrs): section['ids'] = id_attr section['names'] = id_attr title = nodes.title() + self.title_node = title section.append(title) self.current_node.append(section) self.current_node = section @@ -94,74 +95,70 @@ def depart_p(self): def visit_text(self, data): text = nodes.Text(data) - if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: - title = self.current_node.children[0] - if isinstance(title, nodes.title): - title.append(text) - self.current_node = title - return None - elif isinstance(self.current_node, nodes.title) and len(self.current_node.children) > 0: - reference = self.current_node.children[0] - if isinstance(reference, nodes.reference): - reference.append(text) - self.current_node = reference - return None - self.current_node.append(text) - self.current_node = text + if self.title_node: + self.title_node.append(text) + self.title_node = text + else: + self.current_node.append(text) + self.current_node = text def depart_text(self): - self.current_node = self.current_node.parent + if self.title_node: + self.title_node = self.title_node.parent + else: + self.current_node = self.current_node.parent def visit_h1(self, attrs): self.visit_section(1, attrs) def depart_h1(self): - pass + self.title_node = None def visit_h2(self, attrs): self.visit_section(2, attrs) def depart_h2(self): - pass + self.title_node = None def visit_h3(self, attrs): self.visit_section(3, attrs) def depart_h3(self): - pass + self.title_node = None def visit_h4(self, attrs): self.visit_section(4, attrs) def depart_h4(self): - pass + self.title_node = None def visit_h5(self, attrs): self.visit_section(5, attrs) def depart_h5(self): - pass + self.title_node = None def visit_h6(self, attrs): self.visit_section(6, attrs) def depart_h6(self): - pass + self.title_node = None def visit_a(self, attrs): reference = nodes.reference() reference['refuri'] = _.find(attrs, lambda i: i[0] == 'href')[1] - if isinstance(self.current_node, nodes.section) and len(self.current_node.children) > 0: - title = self.current_node.children[0] - if isinstance(title, nodes.title): - title.append(reference) - self.current_node = title - return None - self.current_node.append(reference) - self.current_node = reference + if self.title_node: + self.title_node.append(reference) + self.title_node = reference + else: + self.current_node.append(reference) + self.current_node = reference def depart_a(self): - self.current_node = self.current_node.parent + if self.title_node: + self.title_node = self.title_node.parent + else: + self.current_node = self.current_node.parent def visit_img(self, attrs): image = nodes.image() @@ -304,16 +301,30 @@ def depart_br(self): def visit_em(self, attrs): emphasis = nodes.emphasis() - self.current_node.append(emphasis) - self.current_node = emphasis + if self.title_node: + self.title_node.append(emphasis) + self.title_node = emphasis + else: + self.current_node.append(emphasis) + self.current_node = emphasis def depart_em(self): - self.current_node = self.current_node.parent + if self.title_node: + self.title_node = self.title_node.parent + else: + self.current_node = self.current_node.parent def visit_strong(self, attrs): strong = nodes.strong() - self.current_node.append(strong) - self.current_node = strong + if self.title_node: + self.title_node.append(strong) + self.title_node = strong + else: + self.current_node.append(strong) + self.current_node = strong def depart_strong(self): - self.current_node = self.current_node.parent + if self.title_node: + self.title_node = self.title_node.parent + else: + self.current_node = self.current_node.parent diff --git a/tests/test_markdown.py b/tests/test_markdown.py index 55e5786..4557b98 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -9,7 +9,7 @@ from docutils.core import publish_parts from commonmark import Parser -from recommonmark.parser import MarkdownParser, CommonMarkParser +from recommonmark.parser import MarkdownParser class TestParsing(unittest.TestCase): @@ -30,7 +30,7 @@ def test_heading(self): hello = 'world' ``` - ## A + ## _[**A**](https://google.com)_ > some-blockquote @@ -63,7 +63,13 @@ def test_heading(self): I hello = 'world'
- A + + <emphasis> + <reference refuri="https://google.com"> + <strong>A</strong> + </reference> + </emphasis> + some-blockquote From ac62f4998a7b456f6e868193b61984cd672b7bf5 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sun, 3 Feb 2019 12:43:34 -0600 Subject: [PATCH 10/17] Added depth counter --- recommonmark/markdown_parser.py | 112 +++++++++++++++----------------- 1 file changed, 51 insertions(+), 61 deletions(-) diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py index c9ab405..39a20ef 100644 --- a/recommonmark/markdown_parser.py +++ b/recommonmark/markdown_parser.py @@ -12,9 +12,10 @@ class MarkdownParser(parsers.Parser): """Docutils parser for Markdown""" + depth = 0 + level = 0 supported = ('md', 'markdown') translate_section_name = None - level = 0 def __init__(self): self._level_to_elem = {} @@ -72,12 +73,11 @@ def visit_section(self, level, attrs): title = nodes.title() self.title_node = title section.append(title) - self.current_node.append(section) - self.current_node = section + self.append_node(section) def depart_section(self, level): if (self.current_node.parent): - self.current_node = self.current_node.parent + self.exit_node() def visit_document(self): pass @@ -87,11 +87,10 @@ def depart_document(self): def visit_p(self, attrs): paragraph = nodes.paragraph() - self.current_node.append(paragraph) - self.current_node = paragraph + self.append_node(paragraph) def depart_p(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_text(self, data): text = nodes.Text(data) @@ -99,14 +98,13 @@ def visit_text(self, data): self.title_node.append(text) self.title_node = text else: - self.current_node.append(text) - self.current_node = text + self.append_node(text) def depart_text(self): if self.title_node: self.title_node = self.title_node.parent else: - self.current_node = self.current_node.parent + self.exit_node() def visit_h1(self, attrs): self.visit_section(1, attrs) @@ -151,99 +149,88 @@ def visit_a(self, attrs): self.title_node.append(reference) self.title_node = reference else: - self.current_node.append(reference) - self.current_node = reference + self.append_node(reference) def depart_a(self): if self.title_node: self.title_node = self.title_node.parent else: - self.current_node = self.current_node.parent + self.exit_node() def visit_img(self, attrs): image = nodes.image() image['uri'] = _.find(attrs, lambda attr:attr[0]=='src')[1] - self.current_node.append(image) - self.current_node = image + self.append_node(image) self.visit_text(_.find(attrs, lambda attr:attr[0]=='alt')[1]) def depart_img(self): self.depart_text() - self.current_node = self.current_node.parent + self.exit_node() def visit_ul(self, attrs): bullet_list = nodes.bullet_list() - self.current_node.append(bullet_list) - self.current_node = bullet_list + self.append_node(bullet_list) def depart_ul(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_ol(self, attrs): enumerated_list = nodes.enumerated_list() - self.current_node.append(enumerated_list) - self.current_node = enumerated_list + self.append_node(enumerated_list) def depart_ol(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_li(self, attrs): list_item = nodes.list_item() - self.current_node.append(list_item) - self.current_node = list_item + self.append_node(list_item) self.visit_p([]) def depart_li(self): self.depart_p() - self.current_node = self.current_node.parent + self.exit_node() def visit_table(self, attrs): table = nodes.table() - self.current_node.append(table) - self.current_node = table + self.append_node(table) def depart_table(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_thead(self, attrs): thead = nodes.thead() - self.current_node.append(thead) - self.current_node = thead + self.append_node(thead) def depart_thead(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_tbody(self, attrs): tbody = nodes.tbody() - self.current_node.append(tbody) - self.current_node = tbody + self.append_node(tbody) def depart_tbody(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_tr(self, attrs): row = nodes.row() - self.current_node.append(row) - self.current_node = row + self.append_node(row) def depart_tr(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_th(self, attrs): entry = nodes.entry() - self.current_node.append(entry) - self.current_node = entry + self.append_node(entry) def depart_th(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_td(self, attrs): entry = nodes.entry() - self.current_node.append(entry) - self.current_node = entry + self.append_node(entry) def depart_td(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_div(self, attrs): pass @@ -269,35 +256,31 @@ def visit_code(self, attrs): if len(attr): class_attr = attr[1] literal_block['language'] = class_attr - self.current_node.append(literal_block) - self.current_node = literal_block + self.append_node(literal_block) def depart_code(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_blockquote(self, attrs): block_quote = nodes.block_quote() - self.current_node.append(block_quote) - self.current_node = block_quote + self.append_node(block_quote) def depart_blockquote(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_hr(self, attrs): transition = nodes.transition() - self.current_node.append(transition) - self.current_node = transition + self.append_node(transition) def depart_hr(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_br(self, attrs): text = nodes.Text('\n') - self.current_node.append(text) - self.current_node = text + self.append_node(text) def depart_br(self): - self.current_node = self.current_node.parent + self.exit_node() def visit_em(self, attrs): emphasis = nodes.emphasis() @@ -305,14 +288,13 @@ def visit_em(self, attrs): self.title_node.append(emphasis) self.title_node = emphasis else: - self.current_node.append(emphasis) - self.current_node = emphasis + self.append_node(emphasis) def depart_em(self): if self.title_node: self.title_node = self.title_node.parent else: - self.current_node = self.current_node.parent + self.exit_node() def visit_strong(self, attrs): strong = nodes.strong() @@ -320,11 +302,19 @@ def visit_strong(self, attrs): self.title_node.append(strong) self.title_node = strong else: - self.current_node.append(strong) - self.current_node = strong + self.append_node(strong) def depart_strong(self): if self.title_node: self.title_node = self.title_node.parent else: - self.current_node = self.current_node.parent + self.exit_node() + + def append_node(self, node): + self.current_node.append(node) + self.current_node = node + self.depth = self.depth + 1 + + def exit_node(self): + self.current_node = self.current_node.parent + self.depth = self.depth - 1 From c6167257a0c6fc41fda01e146e579c4dd6551625 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sun, 3 Feb 2019 13:00:16 -0600 Subject: [PATCH 11/17] Convert attrs to dict --- recommonmark/markdown_parser.py | 42 +++++++++++++++++++++++---------- setup.py | 1 - tests/test_markdown.py | 2 ++ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py index 39a20ef..b0dad5c 100644 --- a/recommonmark/markdown_parser.py +++ b/recommonmark/markdown_parser.py @@ -3,7 +3,6 @@ from docutils import parsers, nodes from html.parser import HTMLParser from markdown import markdown -import pydash as _ import re __all__ = ['MarkdownParser'] @@ -37,13 +36,20 @@ def convert_html(self, html): html = html.replace('\n', '') class MyHTMLParser(HTMLParser): def handle_starttag(_, tag, attrs): + attrs = self.attrs_to_dict(attrs) fn_name = 'visit_' + tag - fn = getattr(self, fn_name) - fn(attrs) + if hasattr(self, fn_name): + fn = getattr(self, fn_name) + fn(attrs) + else: + self.visit_html(tag, attrs) def handle_endtag(_, tag): fn_name = 'depart_' + tag - fn = getattr(self, fn_name) - fn() + if hasattr(self, fn_name): + fn = getattr(self, fn_name) + fn() + else: + self.depart_html() def handle_data(_, data): self.visit_text(data) self.depart_text() @@ -52,6 +58,13 @@ def handle_data(_, data): parser.feed(html) self.depart_document() + def attrs_to_dict(self, attrs): + attrs_dict = {} + for item in attrs: + if len(item) == 2: + attrs_dict[item[0]] = item[1] + return attrs_dict + def convert_ast(self, ast): for (node, entering) in ast.walker(): fn_prefix = "visit" if entering else "depart" @@ -67,7 +80,7 @@ def visit_section(self, level, attrs): self.depart_section(level) self.level = level section = nodes.section() - id_attr = _.find(attrs, lambda attr:attr[0]=='id')[1] + id_attr = attrs['id'] if 'id' in attrs else '' section['ids'] = id_attr section['names'] = id_attr title = nodes.title() @@ -144,7 +157,7 @@ def depart_h6(self): def visit_a(self, attrs): reference = nodes.reference() - reference['refuri'] = _.find(attrs, lambda i: i[0] == 'href')[1] + reference['refuri'] = attrs['href'] if 'href' in attrs else '' if self.title_node: self.title_node.append(reference) self.title_node = reference @@ -159,9 +172,9 @@ def depart_a(self): def visit_img(self, attrs): image = nodes.image() - image['uri'] = _.find(attrs, lambda attr:attr[0]=='src')[1] + image['uri'] = attrs['src'] if 'src' in attrs else '' self.append_node(image) - self.visit_text(_.find(attrs, lambda attr:attr[0]=='alt')[1]) + self.visit_text(attrs['alt'] if 'alt' in attrs else '') def depart_img(self): self.depart_text() @@ -252,9 +265,8 @@ def depart_span(self): def visit_code(self, attrs): literal_block = nodes.literal_block() - attr = _.find(attrs, lambda attr:attr[0]=='class') - if len(attr): - class_attr = attr[1] + class_attr = attrs['class'] if 'class' in attrs else '' + if len(class_attr): literal_block['language'] = class_attr self.append_node(literal_block) @@ -310,6 +322,12 @@ def depart_strong(self): else: self.exit_node() + def visit_html(self, tag, attrs): + pass + + def depart_html(self): + pass + def append_node(self, node): self.current_node.append(node) self.current_node = node diff --git a/setup.py b/setup.py index 5fc8350..8e6fd2e 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,6 @@ 'Markdown>=3.0.1', 'commonmark>=0.7.3', 'docutils>=0.11', - 'pydash>=4.7.4', 'sphinx>=1.3.1', ], entry_points={'console_scripts': [ diff --git a/tests/test_markdown.py b/tests/test_markdown.py index 4557b98..8b2fd6e 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -55,6 +55,8 @@ def test_heading(self): | one | two | | --- | --- | | ONE | TWO | + +
+ <video hello="world"><boo>howdy</boo></video> + wow
From c761d39875eb5e09cc141338ce217fe9b8f85868 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sun, 3 Feb 2019 14:30:28 -0600 Subject: [PATCH 13/17] Added support for more html tags --- recommonmark/markdown_parser.py | 107 +++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py index 592ec37..583bd78 100644 --- a/recommonmark/markdown_parser.py +++ b/recommonmark/markdown_parser.py @@ -101,91 +101,128 @@ def depart_document(self): pass def visit_p(self, attrs): - paragraph = nodes.paragraph() - self.append_node(paragraph) + if len(_.keys(attrs)): + self.visit_html('p', attrs) + else: + paragraph = nodes.paragraph() + self.append_node(paragraph) def depart_p(self): - self.exit_node() + if not self.html_mode: + self.exit_node() def visit_text(self, data): text = nodes.Text(data) - if self.title_node: - self.title_node.append(text) - self.title_node = text - elif self.html_mode: + if self.html_mode: text = nodes.Text(self.current_node.children[0].astext() + data) self.current_node.children[0] = text + elif self.title_node: + self.title_node.append(text) + self.title_node = text else: self.append_node(text) def depart_text(self): - if self.title_node: - self.title_node = self.title_node.parent - elif self.html_mode: + if self.html_mode: pass + elif self.title_node: + self.title_node = self.title_node.parent else: self.exit_node() def visit_h1(self, attrs): - self.visit_section(1, attrs) + if _.keys(attrs) != ['id']: + self.visit_html('h1', attrs) + else: + self.visit_section(1, attrs) def depart_h1(self): - self.title_node = None + if not self.html_mode: + self.title_node = None def visit_h2(self, attrs): - self.visit_section(2, attrs) + if _.keys(attrs) != ['id']: + self.visit_html('h2', attrs) + else: + self.visit_section(2, attrs) def depart_h2(self): - self.title_node = None + if not self.html_mode: + self.title_node = None def visit_h3(self, attrs): - self.visit_section(3, attrs) + if _.keys(attrs) != ['id']: + self.visit_html('h3', attrs) + else: + self.visit_section(3, attrs) def depart_h3(self): - self.title_node = None + if not self.html_mode: + self.title_node = None def visit_h4(self, attrs): - self.visit_section(4, attrs) + if _.keys(attrs) != ['id']: + self.visit_html('h4', attrs) + else: + self.visit_section(4, attrs) def depart_h4(self): - self.title_node = None + if not self.html_mode: + self.title_node = None def visit_h5(self, attrs): - self.visit_section(5, attrs) + if _.keys(attrs) != ['id']: + self.visit_html('h5', attrs) + else: + self.visit_section(5, attrs) def depart_h5(self): - self.title_node = None + if not self.html_mode: + self.title_node = None def visit_h6(self, attrs): - self.visit_section(6, attrs) + if _.keys(attrs) != ['id']: + self.visit_html('h6', attrs) + else: + self.visit_section(6, attrs) def depart_h6(self): - self.title_node = None + if not self.html_mode: + self.title_node = None def visit_a(self, attrs): - reference = nodes.reference() - reference['refuri'] = attrs['href'] if 'href' in attrs else '' - if self.title_node: - self.title_node.append(reference) - self.title_node = reference + if _.keys(attrs) != ['href']: + self.visit_html('a', attrs) else: - self.append_node(reference) + reference = nodes.reference() + reference['refuri'] = attrs['href'] if 'href' in attrs else '' + if self.title_node: + self.title_node.append(reference) + self.title_node = reference + else: + self.append_node(reference) def depart_a(self): - if self.title_node: + if self.html_mode: + pass + elif self.title_node: self.title_node = self.title_node.parent else: self.exit_node() def visit_img(self, attrs): - image = nodes.image() - image['uri'] = attrs['src'] if 'src' in attrs else '' - self.append_node(image) - self.visit_text(attrs['alt'] if 'alt' in attrs else '') + if _.keys(attrs) != ['alt', 'src']: + self.visit_html('img', attrs) + else: + image = nodes.image() + image['uri'] = attrs['src'] if 'src' in attrs else '' + self.append_node(image) + self.visit_text(attrs['alt'] if 'alt' in attrs else '') def depart_img(self): - self.depart_text() - self.exit_node() + if not self.html_mode: + self.depart_text() + self.exit_node() def visit_ul(self, attrs): bullet_list = nodes.bullet_list() From 6fe56a21741a2140d9193c4165a48b16facb243a Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Sun, 3 Feb 2019 14:58:03 -0600 Subject: [PATCH 14/17] Finished html support --- recommonmark/markdown_parser.py | 270 +++++++++++++++++++++----------- tests/test_markdown.py | 5 + 2 files changed, 187 insertions(+), 88 deletions(-) diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py index 583bd78..99b09bd 100644 --- a/recommonmark/markdown_parser.py +++ b/recommonmark/markdown_parser.py @@ -101,14 +101,16 @@ def depart_document(self): pass def visit_p(self, attrs): - if len(_.keys(attrs)): + if self.html_mode or len(_.keys(attrs)): self.visit_html('p', attrs) else: paragraph = nodes.paragraph() self.append_node(paragraph) def depart_p(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('p', attrs) + else: self.exit_node() def visit_text(self, data): @@ -131,67 +133,79 @@ def depart_text(self): self.exit_node() def visit_h1(self, attrs): - if _.keys(attrs) != ['id']: + if self.html_mode or _.keys(attrs) != ['id']: self.visit_html('h1', attrs) else: self.visit_section(1, attrs) def depart_h1(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('h1') + else: self.title_node = None def visit_h2(self, attrs): - if _.keys(attrs) != ['id']: + if self.html_mode or _.keys(attrs) != ['id']: self.visit_html('h2', attrs) else: self.visit_section(2, attrs) def depart_h2(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('h2') + else: self.title_node = None def visit_h3(self, attrs): - if _.keys(attrs) != ['id']: + if self.html_mode or _.keys(attrs) != ['id']: self.visit_html('h3', attrs) else: self.visit_section(3, attrs) def depart_h3(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('h3') + else: self.title_node = None def visit_h4(self, attrs): - if _.keys(attrs) != ['id']: + if self.html_mode or _.keys(attrs) != ['id']: self.visit_html('h4', attrs) else: self.visit_section(4, attrs) def depart_h4(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('h4') + else: self.title_node = None def visit_h5(self, attrs): - if _.keys(attrs) != ['id']: + if self.html_mode or _.keys(attrs) != ['id']: self.visit_html('h5', attrs) else: self.visit_section(5, attrs) def depart_h5(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('h5') + else: self.title_node = None def visit_h6(self, attrs): - if _.keys(attrs) != ['id']: + if self.html_mode or _.keys(attrs) != ['id']: self.visit_html('h6', attrs) else: self.visit_section(6, attrs) def depart_h6(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('h6') + else: self.title_node = None def visit_a(self, attrs): - if _.keys(attrs) != ['href']: + if self.html_mode or _.keys(attrs) != ['href']: self.visit_html('a', attrs) else: reference = nodes.reference() @@ -204,14 +218,14 @@ def visit_a(self, attrs): def depart_a(self): if self.html_mode: - pass + self.depart_html('a') elif self.title_node: self.title_node = self.title_node.parent else: self.exit_node() def visit_img(self, attrs): - if _.keys(attrs) != ['alt', 'src']: + if self.html_mode or _.keys(attrs) != ['alt', 'src']: self.visit_html('img', attrs) else: image = nodes.image() @@ -220,148 +234,228 @@ def visit_img(self, attrs): self.visit_text(attrs['alt'] if 'alt' in attrs else '') def depart_img(self): - if not self.html_mode: + if self.html_mode: + self.depart_html('img') + else: self.depart_text() self.exit_node() def visit_ul(self, attrs): - bullet_list = nodes.bullet_list() - self.append_node(bullet_list) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('ul', attrs) + else: + bullet_list = nodes.bullet_list() + self.append_node(bullet_list) def depart_ul(self): - self.exit_node() + if self.html_mode: + self.depart_html('ul') + else: + self.exit_node() def visit_ol(self, attrs): - enumerated_list = nodes.enumerated_list() - self.append_node(enumerated_list) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('ol', attrs) + else: + enumerated_list = nodes.enumerated_list() + self.append_node(enumerated_list) def depart_ol(self): - self.exit_node() + if self.html_mode: + self.depart_html('ol') + else: + self.exit_node() def visit_li(self, attrs): - list_item = nodes.list_item() - self.append_node(list_item) - self.visit_p([]) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('li', attrs) + else: + list_item = nodes.list_item() + self.append_node(list_item) + self.visit_p([]) def depart_li(self): - self.depart_p() - self.exit_node() + if self.html_mode: + self.depart_html('li') + else: + self.depart_p() + self.exit_node() def visit_table(self, attrs): - table = nodes.table() - self.append_node(table) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('table', attrs) + else: + table = nodes.table() + self.append_node(table) def depart_table(self): - self.exit_node() + if self.html_mode: + self.depart_html('table') + else: + self.exit_node() def visit_thead(self, attrs): - thead = nodes.thead() - self.append_node(thead) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('thead', attrs) + else: + thead = nodes.thead() + self.append_node(thead) def depart_thead(self): - self.exit_node() + if self.html_mode: + self.depart_html('thead') + else: + self.exit_node() def visit_tbody(self, attrs): - tbody = nodes.tbody() - self.append_node(tbody) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('tbody', attrs) + else: + tbody = nodes.tbody() + self.append_node(tbody) def depart_tbody(self): - self.exit_node() + if self.html_mode: + self.html_mode('tbody') + else: + self.exit_node() def visit_tr(self, attrs): - row = nodes.row() - self.append_node(row) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('tr', attrs) + else: + row = nodes.row() + self.append_node(row) def depart_tr(self): - self.exit_node() + if self.html_mode: + self.depart_html('tr') + else: + self.exit_node() def visit_th(self, attrs): - entry = nodes.entry() - self.append_node(entry) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('th', attrs) + else: + entry = nodes.entry() + self.append_node(entry) def depart_th(self): - self.exit_node() + if self.html_mode: + self.depart_html('th') + else: + self.exit_node() def visit_td(self, attrs): - entry = nodes.entry() - self.append_node(entry) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('td', attrs) + else: + entry = nodes.entry() + self.append_node(entry) def depart_td(self): - self.exit_node() - - def visit_div(self, attrs): - pass - - def depart_div(self): - pass + if self.html_mode: + self.depart_html('td') + else: + self.exit_node() def visit_pre(self, attrs): - pass + if self.html_mode or len(_.keys(attrs)): + self.visit_html('pre', attrs) def depart_pre(self): - pass - - def visit_span(self, attrs): - pass - - def depart_span(self): - pass + if self.html_mode: + self.depart_html('pre') def visit_code(self, attrs): - literal_block = nodes.literal_block() - class_attr = attrs['class'] if 'class' in attrs else '' - if len(class_attr): - literal_block['language'] = class_attr - self.append_node(literal_block) + if self.html_mode or _.keys(attrs) != ['class']: + self.visit_html('code', attrs) + else: + literal_block = nodes.literal_block() + class_attr = attrs['class'] if 'class' in attrs else '' + if len(class_attr): + literal_block['language'] = class_attr + self.append_node(literal_block) def depart_code(self): - self.exit_node() + if self.html_mode: + self.depart_html('code') + else: + self.exit_node() def visit_blockquote(self, attrs): - block_quote = nodes.block_quote() - self.append_node(block_quote) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('blockquote', attrs) + else: + block_quote = nodes.block_quote() + self.append_node(block_quote) def depart_blockquote(self): - self.exit_node() + if self.html_mode: + self.depart_html('blockquote') + else: + self.exit_node() def visit_hr(self, attrs): - transition = nodes.transition() - self.append_node(transition) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('hr', attrs) + else: + transition = nodes.transition() + self.append_node(transition) def depart_hr(self): - self.exit_node() + if self.html_mode: + self.depart_html('hr') + else: + self.exit_node() def visit_br(self, attrs): - text = nodes.Text('\n') - self.append_node(text) + if self.html_mode or len(_.keys(attrs)): + self.visit_html('br', attrs) + else: + text = nodes.Text('\n') + self.append_node(text) def depart_br(self): - self.exit_node() + if self.html_mode: + self.depart_html('br') + else: + self.exit_node() def visit_em(self, attrs): - emphasis = nodes.emphasis() - if self.title_node: - self.title_node.append(emphasis) - self.title_node = emphasis + if self.html_mode or len(_.keys(attrs)): + self.visit_html('em', attrs) else: - self.append_node(emphasis) + emphasis = nodes.emphasis() + if self.title_node: + self.title_node.append(emphasis) + self.title_node = emphasis + else: + self.append_node(emphasis) def depart_em(self): - if self.title_node: + if self.html_mode: + self.depart_html('em') + elif self.title_node: self.title_node = self.title_node.parent else: self.exit_node() def visit_strong(self, attrs): - strong = nodes.strong() - if self.title_node: - self.title_node.append(strong) - self.title_node = strong + if self.html_mode or len(_.keys(attrs)): + self.visit_html('strong', attrs) else: - self.append_node(strong) + strong = nodes.strong() + if self.title_node: + self.title_node.append(strong) + self.title_node = strong + else: + self.append_node(strong) def depart_strong(self): - if self.title_node: + if self.html_mode: + self.depart_html('strong') + elif self.title_node: self.title_node = self.title_node.parent else: self.exit_node() diff --git a/tests/test_markdown.py b/tests/test_markdown.py index 90478af..0b24588 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -51,6 +51,8 @@ def test_heading(self): **bold** + special + --- | one | two | @@ -111,6 +113,9 @@ def test_heading(self): bold + + <strong attr="some-attr">special</strong> + From eb68f066ebc2240f0a2a13c025ca6e3a746271c3 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Mon, 4 Feb 2019 09:31:23 -0600 Subject: [PATCH 15/17] Added frontmatter parser --- recommonmark/markdown_parser.py | 25 ++++++++++++++++++++++++- setup.py | 1 + tests/test_markdown.py | 4 ++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/recommonmark/markdown_parser.py b/recommonmark/markdown_parser.py index 99b09bd..bbdc986 100644 --- a/recommonmark/markdown_parser.py +++ b/recommonmark/markdown_parser.py @@ -5,6 +5,7 @@ from markdown import markdown from pydash import _ import re +import yaml __all__ = ['MarkdownParser'] @@ -25,7 +26,9 @@ def parse(self, inputstring, document): self.document = document self.current_node = document self.setup_parse(inputstring, document) - html = markdown(inputstring + '\n', extensions=[ + frontmatter = self.get_frontmatter(inputstring) + md = self.get_md(inputstring) + html = markdown(md + '\n', extensions=[ 'extra', 'tables', 'sane_lists', @@ -60,6 +63,26 @@ def handle_data(_, data): parser.feed(html) self.depart_document() + def get_frontmatter(self, string): + frontmatter = {} + frontmatter_string = '' + frontmatter_regex = re.findall( + r'^\s*---+((\s|\S)+?)---+', + string + ) + if len(frontmatter_regex) and len(frontmatter_regex[0]): + frontmatter_string = frontmatter_regex[0][0] + if len(frontmatter_string): + frontmatter = yaml.load(frontmatter_string) + return frontmatter + + def get_md(self, string): + return re.sub( + r'^\s*---+(\s|\S)+?---+\n((\s|\S)*)', + r'\2', + string + ) + def attrs_to_dict(self, attrs): attrs_dict = {} for item in attrs: diff --git a/setup.py b/setup.py index cc08c77..27867c0 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ ], install_requires=[ 'Markdown>=3.0.1', + 'PyYAML==3.13', 'commonmark>=0.7.3', 'docutils>=0.11', 'pydash==4.7.4', diff --git a/tests/test_markdown.py b/tests/test_markdown.py index 0b24588..3e93a33 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -25,6 +25,10 @@ def test_heading(self): self.maxDiff = None self.assertParses( """ + ---- + hello: world + ---- + # I ```py From 9bc5413cd8960f36e1e3d0a7c03bb94a20baa250 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Mon, 4 Feb 2019 15:56:52 -0600 Subject: [PATCH 16/17] Add MarkdownParser to source_parser --- README.md | 4 ++-- recommonmark/__init__.py | 21 +++++++-------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b3aa222..d054c2c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ pip install recommonmark Then add this to your Sphinx conf.py: ``` -# for Sphinx-1.4 or newer +# for Sphinx-1.4 or newer CommonMarkParser extensions = ['recommonmark'] @@ -38,7 +38,7 @@ source_parsers = { source_suffix = ['.rst', '.md'] -# for Sphinx-1.3 MarkdownParser +# for MarkdownParser from recommonmark.parser import MarkdownParser source_parsers = { diff --git a/recommonmark/__init__.py b/recommonmark/__init__.py index 85a9fb4..e4f64c6 100644 --- a/recommonmark/__init__.py +++ b/recommonmark/__init__.py @@ -6,20 +6,13 @@ def setup(app): """Initialize Sphinx extension.""" import sphinx - from .parser import CommonMarkParser, MarkdownParser + from .parser import CommonMarkParser - Parser = CommonMarkParser - recommonmark_config = {} - if hasattr(app.config, 'recommonmark_config'): - recommonmark_config = app.config.recommonmark_config - - if 'parser' in recommonmark_config: - if recommonmark_config['parser'] == 'Markdown': - Parser = CommonMarkParser - if sphinx.version_info >= (1, 8): - app.add_source_suffix('.md', 'markdown') - app.add_source_parser(Parser) - elif sphinx.version_info >= (1, 4): - app.add_source_parser('.md', Parser) + if 'md' not in app.registry.source_parsers: + if sphinx.version_info >= (1, 8): + app.add_source_suffix('.md', 'markdown') + app.add_source_parser(CommonMarkParser) + elif sphinx.version_info >= (1, 4): + app.add_source_parser('.md', CommonMarkParser) return {'version': __version__, 'parallel_read_safe': True} From 505fdb8b42f97bef880f0f3d16705c3e3646a047 Mon Sep 17 00:00:00 2001 From: Jam Risser Date: Mon, 4 Feb 2019 16:07:49 -0600 Subject: [PATCH 17/17] Load parser from conf --- README.md | 6 +----- recommonmark/__init__.py | 10 ---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/README.md b/README.md index d054c2c..e2c895e 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,7 @@ pip install recommonmark Then add this to your Sphinx conf.py: ``` -# for Sphinx-1.4 or newer CommonMarkParser -extensions = ['recommonmark'] - - -# for Sphinx-1.3 CommonMarkParser +# for CommonMarkParser from recommonmark.parser import CommonMarkParser source_parsers = { diff --git a/recommonmark/__init__.py b/recommonmark/__init__.py index e4f64c6..e2b74b1 100644 --- a/recommonmark/__init__.py +++ b/recommonmark/__init__.py @@ -5,14 +5,4 @@ def setup(app): """Initialize Sphinx extension.""" - import sphinx - from .parser import CommonMarkParser - - if 'md' not in app.registry.source_parsers: - if sphinx.version_info >= (1, 8): - app.add_source_suffix('.md', 'markdown') - app.add_source_parser(CommonMarkParser) - elif sphinx.version_info >= (1, 4): - app.add_source_parser('.md', CommonMarkParser) - return {'version': __version__, 'parallel_read_safe': True}