From 673c0ad9bbce77a121353757a93c18c808a2655e Mon Sep 17 00:00:00 2001 From: rsiddharth Date: Tue, 2 Jan 2018 00:51:19 +0000 Subject: md_tw.py: Add `TWBlockLexer.parse_def_footnotes`. * md_tw.py (TWBlockLexer.parse_def_footnotes): New method. * tests/test_md_tw.py (TestTWBlockLexer.test_parse_def_footnotes): New test. * tests/data/blexer-footnotes.md: New file. --- md_tw.py | 42 ++++++++++++++++++ tests/data/blexer-footnotes.md | 24 +++++++++++ tests/test_md_tw.py | 97 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 tests/data/blexer-footnotes.md diff --git a/md_tw.py b/md_tw.py index 7f9b578..352805f 100644 --- a/md_tw.py +++ b/md_tw.py @@ -159,6 +159,48 @@ class TWBlockLexer(mistune.BlockLexer): 'text': m.group(0) }) + def parse_def_footnotes(self, m): + key = self._keyify(m.group(1)) + if key in self.def_footnotes: + # footnote is already defined + return + + self.def_footnotes[key] = 0 + + text = m.group(2) + multiline = False + spaces = 0 + if '\n' in text: + multiline = True + lines = text.split('\n') + whitespace = None + for line in lines[1:]: + space = len(line) - len(line.lstrip()) + if space and (not whitespace or space < whitespace): + whitespace = space + newlines = [lines[0]] + for line in lines[1:]: + newlines.append(line[whitespace:]) + text = '\n'.join(newlines) + + if whitespace: + spaces = whitespace + + self.tokens.append({ + 'type': 'footnote_start', + 'key': key, + 'multiline': multiline, + 'spaces': spaces + }) + + self.parse(text, self.footnote_rules) + + self.tokens.append({ + 'type': 'footnote_end', + 'key': key, + 'spaces': spaces + }) + class TWInlineLexer(mistune.InlineLexer): """Text Wrap Inline level lexer for inline gramars.""" diff --git a/tests/data/blexer-footnotes.md b/tests/data/blexer-footnotes.md new file mode 100644 index 0000000..0bd38b5 --- /dev/null +++ b/tests/data/blexer-footnotes.md @@ -0,0 +1,24 @@ +This phrase has a single line footnote[^foot1]. + +[^foot1]: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. + +This other phrase has a multiline footnote[^foot2]. + +[^foot2]: Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. Donec sit amet nisl. Aliquam semper ipsum sit amet + velit. + +This phrase has a blockquote in its footnote[^foot3]. + +[^foot3]: A footnote with blockquotes + + Start of block quote in footnote: + + > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, + > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. + > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. + > + > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse + > id sem consectetuer libero luctus adipiscing. + + End of block quote in foot note. diff --git a/tests/test_md_tw.py b/tests/test_md_tw.py index 467caaf..f821f0d 100644 --- a/tests/test_md_tw.py +++ b/tests/test_md_tw.py @@ -480,6 +480,103 @@ class TestTWBlockLexer(object): ] self._validate(tokens, 'def_links', expected_dls) + def test_parse_def_footnotes(self): + tokens = self._parse('blexer-footnotes.md') + + def process(tokens): + token = tokens.pop(0) + while token: + type_ = token['type'] + + expected_token = None + if type_ in expected: + expected_token = expected[type_].pop(0) + + validate(token, expected_token) + + if type_ == 'footnote_end': + break + else: + token = tokens.pop(0) + + return tokens + + def validate(token, expected_token=None): + type_ = token['type'] + + if type_ == 'footnote_start': + assert 'multiline' in token + assert 'spaces' in token + elif type_ == 'footnote_end': + assert 'spaces' in token + + if not expected_token: + return + + if 'text' in token: + assert_equal(token['text'], expected_token['text']) + if 'spaces' in token: + assert_equal(token['spaces'], expected_token['spaces']) + + return + + # test footnote 1 + expected = { + 'footnote_start': [ + {'multiline': False, 'spaces': 0}, + ], + 'paragraph': [ + {'text': 'This phrase has a single line footnote[^foot1].'}, + {'text': 'Lorem ipsum dolor sit amet, consectetuer' + ' adipiscing elit.'}, + ], + 'footnote_end': [ + {'spaces': 0} + ] + } + tokens = process(tokens) + + # test footnote 2 + expected = { + 'footnote_start': [ + {'multiline': True, 'spaces': 4}, + ], + 'paragraph': [ + {'text': 'This other phrase has a multiline footnote[^foot2].'}, + {'text': 'Vestibulum enim wisi, viverra nec, fringilla in, ' + 'laoreet\nvitae, risus. Donec sit amet nisl. Aliquam ' + 'semper ipsum sit amet\nvelit.'}, + ], + 'footnote_end': [ + {'spaces': 4} + ] + } + tokens = process(tokens) + + # test footnote 3 + expected = { + 'footnote_start': [ + {'multiline': True, 'spaces': 3}, + ], + 'paragraph': [ + {'text': 'This phrase has a blockquote in its footnote[^foot3].'}, + {'text': 'A footnote with blockquotes'}, + {'text': 'Start of block quote in footnote:'}, + {'text': 'This is a blockquote with two paragraphs. Lorem' + ' ipsum dolor sit amet,\nconsectetuer adipiscing elit.' + ' Aliquam hendrerit mi posuere lectus.\nVestibulum enim wisi,' + ' viverra nec, fringilla in, laoreet vitae, risus.'}, + {'text': 'Donec sit amet nisl. Aliquam semper ipsum sit amet ' + 'velit. Suspendisse\nid sem consectetuer libero luctus ' + 'adipiscing.'}, + {'text': 'End of block quote in foot note.'}, + ], + 'footnote_end': [ + {'spaces': 3} + ] + } + tokens = process(tokens) + def teardown(self): pass -- cgit v1.2.3