diff --git a/CHANGES.rst b/CHANGES.rst index eb204dd..3eb99a7 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,14 @@ Changelog Here is the full history of mistune. +Version 0.7 +~~~~~~~~~~~ + +Release date not decided. + +* Fix the breaking change in version 0.6 with options: **parse_inline_html** and **parse_block_html** + + Version 0.6 ~~~~~~~~~~~ diff --git a/README.rst b/README.rst index 894833b..f6cb5f9 100644 --- a/README.rst +++ b/README.rst @@ -38,12 +38,6 @@ Installing mistune with pip:: $ pip install mistune -If pip is not available, try easy_install:: - - $ easy_install mistune - -Cython Feature -~~~~~~~~~~~~~~ Mistune can be faster, if you compile with cython:: @@ -59,10 +53,49 @@ A simple API that render a markdown formatted text: import mistune - mistune.markdown('I am using **markdown**') - # output:

I am using markdown

+ mistune.markdown('I am using **mistune markdown parser**') + # output:

I am using mistune markdown parser

+ +If you care about performance, it is better to re-use the Markdown instance: + +.. code:: python + + import mistune + + markdown = mistune.Markdown() + markdown('I am using **mistune markdown parser**') + +Mistune has enabled all features by default. You don't have to configure +anything. But there are options for you to change the parser behaviors. + + +Options +------- + +Here is a list of all options that will affect the rendering results, +configure them with ``mistune.Renderer``: + +.. code:: python + + renderer = mistune.Renderer(escape=True, hard_wrap=True) + # use this renderer instance + markdown = mistune.Markdown(renderer=renderer) + markdown(text) + +* **escape**: if set to *True*, all raw html tags will be escaped. +* **hard_wrap**: if set to *True*, it will has GFM line breaks feature. +* **use_xhtml**: if set to *True*, all tags will be in xhtml, for example: ``
``. +* **parse_html**: parse text in block and inline level html. +* **parse_block_html**: parse text only in block level html. +* **parse_inline_html**: parse text only in inline level html. + +When using the default renderer, you can use one of the following shortcuts:: + + mistune.markdown(text, escape=True, hard_wrap=True) + + markdown = mistune.Markdown(escape=True, hard_wrap=True) + markdown(text) -Mistune has all features by default. You don't have to configure anything. Renderer -------- @@ -79,7 +112,7 @@ Here is an example of code highlighting: from pygments.lexers import get_lexer_by_name from pygments.formatters import HtmlFormatter - class MyRenderer(mistune.Renderer): + class HighlightRenderer(mistune.Renderer): def block_code(self, code, lang): if not lang: return '\n
%s
\n' % \ @@ -88,9 +121,9 @@ Here is an example of code highlighting: formatter = HtmlFormatter() return highlight(code, lexer, formatter) - renderer = MyRenderer() - md = mistune.Markdown(renderer=renderer) - print(md.render('Some Markdown text.')) + renderer = HighlightRenderer() + markdown = mistune.Markdown(renderer=renderer) + print(markdown('Some code text.')) Block Level @@ -127,34 +160,18 @@ Here is a list of span level renderer API:: linebreak() newline() link(link, title, content) - tag(html) strikethrough(text) text(text) + inline_html(text) +Footnotes +~~~~~~~~~ -Options -------- - -Here is a list of all options that will affect the rendering results: - -.. code:: python - - renderer = mistune.Renderer(escape=True) - md = mistune.Markdown(renderer=renderer) - md.render(text) - -* **escape**: if set to *True*, all raw html tags will be escaped. -* **hard_wrap**: if set to *True*, it will has GFM line breaks feature. -* **use_xhtml**: if set to *True*, all tags will be in xhtml, for example: ``
``. -* **parse_html**: parse text in block level html. - -When using the default renderer, you can use one of the following shorthands:: - - mistune.markdown(text, escape=True) - - md = mistune.Markdown(escape=True) - md.render(text) +Here is a list of renderers related to footnotes:: + footnote_ref(key, index) + footnote_item(key, text) + footnotes(text) Lexers ------ @@ -172,33 +189,23 @@ It is an inline grammar, which requires custom ``InlineGrammar`` and import copy from mistune import Renderer, InlineGrammar, InlineLexer - class MyRenderer(Renderer): + class WikiLinkRenderer(Renderer): def wiki_link(self, alt, link): return '%s' % (link, alt) + class WikiLinkInlineLexer(InlineLexer): + def enable_wiki_link(self): + # add wiki_link rules + self.rules.wiki_link = re.compile( + r'\[\[' # [[ + r'([\s\S]+?\|[\s\S]+?)' # Page 2|Page 2 + r'\]\](?!\])' # ]] + ) - class MyInlineGrammar(InlineGrammar): - # it would take a while for creating the right regex - wiki_link = re.compile( - r'\[\[' # [[ - r'([\s\S]+?\|[\s\S]+?)' # Page 2|Page 2 - r'\]\](?!\])' # ]] - ) - - - class MyInlineLexer(InlineLexer): - default_rules = copy.copy(InlineLexer.default_rules) - - # Add wiki_link parser to default rules - # you can insert it any place you like - default_rules.insert(3, 'wiki_link') - - def __init__(self, renderer, rules=None, **kwargs): - if rules is None: - # use the inline grammar - rules = MyInlineGrammar() - - super(MyInlineLexer, self).__init__(renderer, rules, **kwargs) + # Add wiki_link parser to default rules + # you can insert it some place you like + # but place matters, maybe 3 is not good + self.default_rules.insert(3, 'wiki_link') def output_wiki_link(self, m): text = m.group(1) @@ -211,8 +218,10 @@ You should pass the inline lexer to ``Markdown`` parser: .. code:: python - renderer = MyRenderer() - inline = MyInlineLexer(renderer) + renderer = WikiLinkRenderer() + inline = WikiLinkInlineLexer(renderer) + # enable the feature + inline.enable_wiki_link() markdown = Markdown(renderer, inline=inline) markdown('[[Link Text|Wiki Link]]') @@ -220,12 +229,21 @@ It is the same with block level lexer. It would take a while to understand the whole mechanism. But you won't do the trick a lot. -Contribution ------------- +Contribution & Extensions +------------------------- Mistune itself doesn't accept any extension. It will always be a simple one file script. If you want to add features, you can head over to `mistune-contrib`_. +Here are some extensions already in `mistune-contrib`_: + +* Math/MathJax features +* Highlight Code Renderer +* TOC table of content features +* MultiMarkdown Metadata parser + +Get inspired with the contrib repository. + .. _`mistune-contrib`: https://github.com/lepture/mistune-contrib diff --git a/mistune.py b/mistune.py index 316f86d..86d215e 100644 --- a/mistune.py +++ b/mistune.py @@ -476,6 +476,11 @@ class InlineLexer(object): 'double_emphasis', 'emphasis', 'code', 'linebreak', 'strikethrough', 'text', ] + inline_html_rules = [ + 'escape', 'autolink', 'url', 'link', 'reflink', + 'nolink', 'double_emphasis', 'emphasis', 'code', + 'linebreak', 'strikethrough', 'text', + ] def __init__(self, renderer, rules=None, **kwargs): self.renderer = renderer @@ -491,6 +496,10 @@ class InlineLexer(object): self._in_link = False self._in_footnote = False + kwargs.update(self.renderer.options) + _to_parse = kwargs.get('parse_html') or kwargs.get('parse_inline_html') + self._parse_inline_html = _to_parse + def __call__(self, text): return self.output(text) @@ -553,7 +562,15 @@ class InlineLexer(object): return self.renderer.autolink(link, False) def output_inline_html(self, m): - return self.renderer.inline_html(m.group(0)) + text = m.group(0) + if self._parse_inline_html: + if m.group(1) == 'a': + self._in_link = True + text = self.output(text, rules=self.inline_html_rules) + self._in_link = False + else: + text = self.output(text, rules=self.inline_html_rules) + return self.renderer.inline_html(text) def output_footnote(self, m): key = _keyify(m.group(1)) @@ -909,6 +926,10 @@ class Markdown(object): self.footnotes = [] self.tokens = [] + # detect if it should parse text in block html + _to_parse = kwargs.get('parse_html') or kwargs.get('parse_block_html') + self._parse_block_html = _to_parse + def __call__(self, text): return self.parse(text) @@ -1072,7 +1093,7 @@ class Markdown(object): def output_block_html(self): text = self.token['text'] - if self.options.get('parse_html') and not self.token.get('pre'): + if self._parse_block_html and not self.token.get('pre'): text = self.inline(text) return self.renderer.block_html(text) diff --git a/tests/test_cases.py b/tests/test_cases.py index 933fa4c..3853a67 100644 --- a/tests/test_cases.py +++ b/tests/test_cases.py @@ -99,12 +99,36 @@ def test_use_xhtml(): assert 'foo' in ret -def test_block_html(): +def test_parse_html(): ret = mistune.markdown('
**foo**
') assert '' not in ret ret = mistune.markdown('
**foo**
', parse_html=True) assert '' in ret + ret = mistune.markdown('**foo**') + assert '' not in ret + ret = mistune.markdown('**foo**', parse_html=True) + assert '' in ret + + ret = mistune.markdown('http://example.com', parse_html=True) + assert 'href' in ret + ret = mistune.markdown('http://example.com', parse_html=True) + assert 'href' not in ret + + +def test_parse_inline_html(): + ret = mistune.markdown('
**foo**
', parse_inline_html=True) + assert '' not in ret + ret = mistune.markdown('**foo**', parse_inline_html=True) + assert '' in ret + + +def test_parse_block_html(): + ret = mistune.markdown('
**foo**
', parse_block_html=True) + assert '' in ret + ret = mistune.markdown('**foo**', parse_block_html=True) + assert '' not in ret + def test_trigger_more_cases(): markdown = mistune.Markdown( @@ -114,79 +138,3 @@ def test_trigger_more_cases(): ) ret = markdown.render('foo[^foo]\n\n[^foo]: foo\n\n[^foo]: bar\n') assert 'bar' not in ret - - -def test_custom_lexer(): - import copy - - class MyInlineGrammar(mistune.InlineGrammar): - # it would take a while for creating the right regex - wiki_link = re.compile( - r'\[\[' # [[ - r'([\s\S]+?\|[\s\S]+?)' # Page 2|Page 2 - r'\]\](?!\])' # ]] - ) - - class MyInlineLexer(mistune.InlineLexer): - default_rules = copy.copy(mistune.InlineLexer.default_rules) - default_rules.insert(3, 'wiki_link') - - def __init__(self, renderer, rules=None, **kwargs): - if rules is None: - rules = MyInlineGrammar() - - super(MyInlineLexer, self).__init__(renderer, rules, **kwargs) - - def output_wiki_link(self, m): - text = m.group(1) - alt, link = text.split('|') - return '%s' % (link, alt) - - markdown = mistune.Markdown(inline=MyInlineLexer) - ret = markdown('[[Link Text|Wiki Link]]') - assert '%s' % (link, alt) + + +def test_custom_lexer(): + markdown = mistune.Markdown(inline=WikiInlineLexer) + ret = markdown('[[Link Text|Wiki Link]]') + assert '