summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--md_tw.py21
-rw-r--r--tests/data/blexer-blockquote.md34
-rw-r--r--tests/test_md_tw.py135
3 files changed, 190 insertions, 0 deletions
diff --git a/md_tw.py b/md_tw.py
index 7b20692..19b5b30 100644
--- 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
new file mode 100644
index 0000000..5dce085
--- /dev/null
+++ 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
index d90db2c..4b78dcd 100644
--- 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