markdown-textwrap

text wrap markdown documents
git clone git://git.ricketyspace.net/markdown-textwrap.git
Log | Files | Refs

commit 12903a82dc2ee039b0356855657e3f66173b9e92
parent 9011ef7c4e768955bd3a4355d86eda39469bc127
Author: rsiddharth <s@ricketyspace.net>
Date:   Tue,  2 Jan 2018 00:47:30 +0000

md_tw.py: Add TWBlockLexer.parse_block_quote.

* md_tw.py
(TWBlockLexer.parse_block_quote): New method.
(TWBlockLexer.__init__): Update method.
* tests/test_md_tw.py
(TestTWBlockLexer.test_parse_block_quote): New test.
* tests/data/blexer-blockquote.md: New file.

Diffstat:
md_tw.py | 21+++++++++++++++++++++
tests/data/blexer-blockquote.md | 34++++++++++++++++++++++++++++++++++
tests/test_md_tw.py | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 190 insertions(+), 0 deletions(-)

diff --git a/md_tw.py b/md_tw.py @@ -31,6 +31,7 @@ class TWBlockLexer(mistune.BlockLexer): super(TWBlockLexer, self).__init__(rules, **kwargs) # from mistune + self._block_quote_leading_pattern = re.compile(r'^ *> ?', flags=re.M) self._key_pattern = re.compile(r'\s+') # from mistune @@ -127,6 +128,26 @@ class TWBlockLexer(mistune.BlockLexer): 'spaces': len(bullet) }) + def parse_block_quote(self, m): + # slurp and clean leading > + quote = '' + qm = self._block_quote_leading_pattern.match(m.group(0)) + if qm: + quote = qm.group(0) + + cap = self._block_quote_leading_pattern.sub('', m.group(0)) + + self.tokens.append({ + 'type': 'block_quote_start', + 'text': quote, + 'spaces': len(quote) + }) + self.parse(cap) + self.tokens.append({ + 'type': 'block_quote_end', + 'spaces': len(quote) + }) + class TWInlineLexer(mistune.InlineLexer): """Text Wrap Inline level lexer for inline gramars.""" diff --git a/tests/data/blexer-blockquote.md b/tests/data/blexer-blockquote.md @@ -0,0 +1,34 @@ +> 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. + +Making Me Nervous + +> 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. + +Bad Attraction + +> This is the first level of quoting. +> +> > This is nested blockquote. +> +> Back to the first level. + +Overreacting + +> ## This is a header. +> +> 1. This is the first list item. +> 2. This is the second list item. +> +> Here's some example code: +> +> return shell_exec("echo $input | $markdown_script"); diff --git a/tests/test_md_tw.py b/tests/test_md_tw.py @@ -328,6 +328,141 @@ class TestTWBlockLexer(object): } tokens = process(tokens) + def test_parse_block_quote(self): + tokens = self._parse('blexer-blockquote.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_ == 'block_quote_end': + break + else: + token = tokens.pop(0) + + return tokens + + def validate(token, expected_token=None): + type_ = token['type'] + + if type_ == 'block_quote_start': + assert 'text' in token + assert 'spaces' in token + elif type_ == 'block_quote_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 blockquote 1 + expected = { + 'block_quote_start': [ + {'text': '> ', 'spaces': 2}, + ], + 'paragraph': [ + {'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.'}, + ], + 'block_quote_end': [ + {'spaces': 2}, + ] + } + tokens = process(tokens) + token = tokens.pop(0) # Remove paragraph after blockquote. + + # test blockquote 2 + expected = { + 'block_quote_start': [ + {'text': '> ', 'spaces': 2}, + ], + 'paragraph': [ + {'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.'}, + ], + 'block_quote_end': [ + {'spaces': 2}, + ] + } + tokens = process(tokens) + token = tokens.pop(0) # Remove paragraph after blockquote. + + # test blockquote 3 + expected = { + 'block_quote_start': [ + {'text': '> ', 'spaces': 2}, + {'text': '> ', 'spaces': 2}, + ], + 'paragraph': [ + {'text': 'This is the first level of quoting.'}, + {'text': 'This is nested blockquote.'}, + {'text': 'Back to the first level.'} + ], + 'block_quote_end': [ + {'spaces': 2}, + {'spaces': 2}, + ] + } + tokens = process(tokens) + tokens = process(tokens) + token = tokens.pop(0) # Remove paragraph after blockquote. + + # test blockquote 4 + expected = { + 'block_quote_start': [ + {'text': '> ', 'spaces': 2}, + ], + 'heading': [ + {'text': '## This is a header.\n\n'} + ], + 'list_item_start': [ + {'text': '1. ', 'spaces': 5}, + {'text': '2. ', 'spaces': 5} + ], + 'text': [ + {'text': 'This is the first list item.'}, + {'text': 'This is the second list item.'} + ], + 'list_item_end': [ + {'spaces': 5}, + {'spaces': 5} + ], + 'paragraph': [ + {'text': 'Here\'s some example code:'} + ], + 'code': [ + {'text': ' return shell_exec("echo $input | ' + '$markdown_script");'} + ], + 'block_quote_end': [ + {'spaces': 2}, + ] + } + tokens = process(tokens) + def teardown(self): pass